diff --git a/android/app/build.gradle b/android/app/build.gradle index 4c2c528186e27d..a1a2da951a6d49 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -202,6 +202,11 @@ dependencies { // ADD_NEW_SDKS_HERE + // BEGIN_SDK_49 + versionedImplementation(project(':expoview-abi49_0_0')) + // END_SDK_49 + + // BEGIN_SDK_48 versionedImplementation(project(':expoview-abi48_0_0')) // END_SDK_48 diff --git a/android/build.gradle b/android/build.gradle index 63aca3814e6b27..d72417397d1b28 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -51,6 +51,9 @@ allprojects { url "$rootDir/maven" } // For old expoviews to work + maven { + url "$rootDir/versioned-abis/expoview-abi49_0_0/maven" + } maven { url "$rootDir/versioned-abis/expoview-abi48_0_0/maven" } diff --git a/android/expoview/build.gradle b/android/expoview/build.gradle index 4489493e32e275..c37756c274b4ab 100644 --- a/android/expoview/build.gradle +++ b/android/expoview/build.gradle @@ -207,6 +207,9 @@ dependencies { // Versioned react native // THIS COMMENT IS USED BY android-build-aar.sh DO NOT MODIFY + // BEGIN_SDK_49 + versionedApi 'host.exp:reactandroid-abi49_0_0:1.0.0' + // END_SDK_49 // BEGIN_SDK_48 versionedApi 'host.exp:reactandroid-abi48_0_0:1.0.0' // END_SDK_48 diff --git a/android/expoview/src/main/java/host/exp/exponent/Constants.java b/android/expoview/src/main/java/host/exp/exponent/Constants.java index a701e420408ae2..1e7f4df8324b6e 100644 --- a/android/expoview/src/main/java/host/exp/exponent/Constants.java +++ b/android/expoview/src/main/java/host/exp/exponent/Constants.java @@ -75,6 +75,9 @@ public static void setSdkVersions(List sdkVersions) { // WHEN_DISTRIBUTING_REMOVE_FROM_HERE // WHEN_PREPARING_SHELL_REMOVE_FROM_HERE // ADD ABI VERSIONS HERE DO NOT MODIFY + // BEGIN_SDK_49 + abiVersions.add("49.0.0"); + // END_SDK_49 // BEGIN_SDK_48 abiVersions.add("48.0.0"); // END_SDK_48 diff --git a/android/expoview/src/versioned/java/host/exp/exponent/experience/MultipleVersionReactNativeActivity.java b/android/expoview/src/versioned/java/host/exp/exponent/experience/MultipleVersionReactNativeActivity.java index 0464aef7eccb22..d4d33343fb35fd 100644 --- a/android/expoview/src/versioned/java/host/exp/exponent/experience/MultipleVersionReactNativeActivity.java +++ b/android/expoview/src/versioned/java/host/exp/exponent/experience/MultipleVersionReactNativeActivity.java @@ -15,6 +15,10 @@ public class MultipleVersionReactNativeActivity extends ReactNativeActivity impl abi48_0_0.com.facebook.react.modules.core.DefaultHardwareBackBtnHandler, abi48_0_0.com.facebook.react.modules.core.PermissionAwareActivity, // END_SDK_48 + // BEGIN_SDK_49 + abi49_0_0.com.facebook.react.modules.core.DefaultHardwareBackBtnHandler, + abi49_0_0.com.facebook.react.modules.core.PermissionAwareActivity, + // END_SDK_49 // ADD_NEW_SDKS_HERE // WHEN_PREPARING_SHELL_REMOVE_TO_HERE // WHEN_DISTRIBUTING_REMOVE_TO_HERE @@ -34,6 +38,12 @@ public void requestPermissions(String[] strings, int i, abi48_0_0.com.facebook.r super.requestPermissions(strings, i, permissionListener::onRequestPermissionsResult); } // END_SDK_48 + // BEGIN_SDK_49 + @Override + public void requestPermissions(String[] strings, int i, abi49_0_0.com.facebook.react.modules.core.PermissionListener permissionListener) { + super.requestPermissions(strings, i, permissionListener::onRequestPermissionsResult); + } + // END_SDK_49 // ADD_NEW_PERMISSION_AWARE_ACTIVITY_IMPLEMENTATION_HERE // WHEN_PREPARING_SHELL_REMOVE_TO_HERE // WHEN_DISTRIBUTING_REMOVE_TO_HERE diff --git a/android/sdkVersions.json b/android/sdkVersions.json index b211e29389ce15..15fa941addda92 100644 --- a/android/sdkVersions.json +++ b/android/sdkVersions.json @@ -1 +1 @@ -{"sdkVersions":["47.0.0","48.0.0"]} \ No newline at end of file +{"sdkVersions":["47.0.0","48.0.0","49.0.0"]} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 28472d406d54d5..f6b4240b9bb647 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -29,6 +29,7 @@ project(":expo-random").projectDir = new File("../packages/expo-random/android") [ // ADD_NEW_SUPPORTED_ABIS_HERE + "abi49_0_0", "abi48_0_0", "abi47_0_0", ].forEach({ abiVariant -> @@ -51,5 +52,6 @@ useExpoModules([ ]) useVendoredModulesForSettingsGradle('unversioned') +useVendoredModulesForSettingsGradle('sdk49') useVendoredModulesForSettingsGradle('sdk48') useVendoredModulesForSettingsGradle('sdk47') diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/build.gradle b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/build.gradle new file mode 100644 index 00000000000000..f4670f8e37866d --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/build.gradle @@ -0,0 +1,152 @@ +import java.nio.file.Paths + +def resolveModulePath(packageName) { + def basePath = rootDir.toPath().normalize() + + // Node's module resolution algorithm searches up to the root directory, + // after which the base path will be null + while (basePath) { + def candidatePath = Paths.get(basePath.toString(), 'node_modules', packageName) + if (candidatePath.toFile().exists()) { + return candidatePath.toString() + } + + basePath = basePath.getParent() + } + + return null +} + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +def getFlagOrDefault(flagName, defaultValue) { + rootProject.hasProperty(flagName) ? rootProject.properties[flagName] == "true" : defaultValue +} + +def getVersionOrDefault(String flagName, String defaultVersion) { + rootProject.hasProperty(flagName) ? rootProject.properties[flagName] : defaultVersion +} + +configurations { + compileClasspath +} + +buildscript { + // kotlin version is dictated by rootProject extension or property in gradle.properties + ext.asyncStorageKtVersion = rootProject.ext.has('kotlinVersion') + ? rootProject.ext['kotlinVersion'] + : rootProject.hasProperty('AsyncStorage_kotlinVersion') + ? rootProject.properties['AsyncStorage_kotlinVersion'] + : '1.8.10' + + repositories { + mavenCentral() + google() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$asyncStorageKtVersion" + } +} + +// AsyncStorage has default size of 6MB. +// This is a sane limit to protect the user from the app storing too much data in the database. +// This also protects the database from filling up the disk cache and becoming malformed. +// If you really need bigger size, please keep in mind the potential consequences. +long dbSizeInMB = 6L +def newDbSize = rootProject.properties['AsyncStorage_db_size_in_MB'] +if (newDbSize != null && newDbSize.isLong()) { + dbSizeInMB = newDbSize.toLong() +} + +// Instead of reusing AsyncTask thread pool, AsyncStorage can use its own executor +def useDedicatedExecutor = getFlagOrDefault('AsyncStorage_dedicatedExecutor', false) + +// Use next storage implementation +def useNextStorage = getFlagOrDefault("AsyncStorage_useNextStorage", false) + +apply plugin: 'com.android.library' +if (useNextStorage) { + apply plugin: 'kotlin-android' + apply plugin: 'kotlin-kapt' + apply from: './testresults.gradle' +} + +android { + compileSdkVersion safeExtGet('compileSdkVersion', 32) + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', 23) + targetSdkVersion safeExtGet('targetSdkVersion', 32) + buildConfigField "Long", "AsyncStorage_db_size", "${dbSizeInMB}L" + buildConfigField "boolean", "AsyncStorage_useDedicatedExecutor", "${useDedicatedExecutor}" + buildConfigField "boolean", "AsyncStorage_useNextStorage", "${useNextStorage}" + } + lintOptions { + abortOnError false + } + + if (useNextStorage) { + testOptions { + unitTests { + returnDefaultValues = true + includeAndroidResources = true + } + } + } +} + +repositories { + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "${resolveModulePath("react-native")}/android" + } + google() + mavenCentral() +} + +dependencies { + + if (useNextStorage) { + def room_version = getVersionOrDefault('AsyncStorage_next_roomVersion', '2.4.3') + def coroutines_version = "1.6.4" + def coroutinesTest_version = "1.6.4" + // if we don't provide explicit dependency on reflection, kotlin plugin + // would add one automatically, probably a version that is not compatible with + // used kotlin + def kotlinReflect_version = project.ext.asyncStorageKtVersion + def junit_version = "4.13.2" + def robolectric_version = "4.7.3" + def truth_version = "1.1.3" + def androidxtest_version = "1.4.0" + def androidtest_junit_version = "1.1.3" + + implementation "androidx.room:room-runtime:$room_version" + implementation "androidx.room:room-ktx:$room_version" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinReflect_version" + + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + kapt "androidx.room:room-compiler:$room_version" + + testImplementation "junit:junit:$junit_version" + testImplementation "androidx.test:runner:$androidxtest_version" + testImplementation "androidx.test:rules:$androidxtest_version" + testImplementation "androidx.test.ext:junit:$androidtest_junit_version" + testImplementation "org.robolectric:robolectric:$robolectric_version" + testImplementation "com.google.truth:truth:$truth_version" + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesTest_version" + } + + //noinspection GradleDynamicVersion + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + // From node_modules +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/gradle.properties b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/gradle.properties new file mode 100644 index 00000000000000..2d8d1e4dd150cb --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/gradle.properties @@ -0,0 +1 @@ +android.useAndroidX=true \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..e9783aa0cff8fc --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java new file mode 100644 index 00000000000000..db1e6db72b1773 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java @@ -0,0 +1,180 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import javax.annotation.Nullable; +import java.io.File; +import java.util.Arrays; +import java.util.Iterator; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import org.json.JSONException; +import org.json.JSONObject; +import static abi49_0_0.com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.KEY_COLUMN; +import static abi49_0_0.com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.TABLE_CATALYST; +import static abi49_0_0.com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.VALUE_COLUMN; + +/** + * Helper for database operations. + */ +public class AsyncLocalStorageUtil { + + /** + * Build the String required for an SQL select statement: + * WHERE key IN (?, ?, ..., ?) + * without 'WHERE' and with selectionCount '?' + */ + /* package */ static String buildKeySelection(int selectionCount) { + String[] list = new String[selectionCount]; + Arrays.fill(list, "?"); + return KEY_COLUMN + " IN (" + TextUtils.join(", ", list) + ")"; + } + + /** + * Build the String[] arguments needed for an SQL selection, i.e.: + * {a, b, c} + * to be used in the SQL select statement: WHERE key in (?, ?, ?) + */ + /* package */ static String[] buildKeySelectionArgs(ReadableArray keys, int start, int count) { + String[] selectionArgs = new String[count]; + for (int keyIndex = 0; keyIndex < count; keyIndex++) { + selectionArgs[keyIndex] = keys.getString(start + keyIndex); + } + return selectionArgs; + } + + /** + * Returns the value of the given key, or null if not found. + */ + public static @Nullable String getItemImpl(SQLiteDatabase db, String key) { + String[] columns = {VALUE_COLUMN}; + String[] selectionArgs = {key}; + + Cursor cursor = db.query( + TABLE_CATALYST, + columns, + KEY_COLUMN + "=?", + selectionArgs, + null, + null, + null); + + try { + if (!cursor.moveToFirst()) { + return null; + } else { + return cursor.getString(0); + } + } finally { + cursor.close(); + } + } + + /** + * Sets the value for the key given, returns true if successful, false otherwise. + */ + /* package */ static boolean setItemImpl(SQLiteDatabase db, String key, String value) { + ContentValues contentValues = new ContentValues(); + contentValues.put(KEY_COLUMN, key); + contentValues.put(VALUE_COLUMN, value); + + long inserted = db.insertWithOnConflict( + TABLE_CATALYST, + null, + contentValues, + SQLiteDatabase.CONFLICT_REPLACE); + + return (-1 != inserted); + } + + /** + * Does the actual merge of the (key, value) pair with the value stored in the database. + * NB: This assumes that a database lock is already in effect! + * @return the errorCode of the operation + */ + /* package */ static boolean mergeImpl(SQLiteDatabase db, String key, String value) + throws JSONException { + String oldValue = getItemImpl(db, key); + String newValue; + + if (oldValue == null) { + newValue = value; + } else { + JSONObject oldJSON = new JSONObject(oldValue); + JSONObject newJSON = new JSONObject(value); + deepMergeInto(oldJSON, newJSON); + newValue = oldJSON.toString(); + } + + return setItemImpl(db, key, newValue); + } + + /** + * Merges two {@link JSONObject}s. The newJSON object will be merged with the oldJSON object by + * either overriding its values, or merging them (if the values of the same key in both objects + * are of type {@link JSONObject}). oldJSON will contain the result of this merge. + */ + private static void deepMergeInto(JSONObject oldJSON, JSONObject newJSON) + throws JSONException { + Iterator keys = newJSON.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + + JSONObject newJSONObject = newJSON.optJSONObject(key); + JSONObject oldJSONObject = oldJSON.optJSONObject(key); + if (newJSONObject != null && oldJSONObject != null) { + deepMergeInto(oldJSONObject, newJSONObject); + oldJSON.put(key, oldJSONObject); + } else { + oldJSON.put(key, newJSON.get(key)); + } + } + } + /** + * From Pie and up, Android started to use Write-ahead logging (WAL), instead of journal rollback + * for atomic commits and rollbacks. + * Basically, WAL does not write directly to the database file, rather to the supporting WAL file. + * Because of that, migration to the next storage might not be successful, because the content of + * RKStorage might be still in WAL file instead. Committing all data from WAL to db file is called + * a "checkpoint" and is done automatically (by default) when the WAL file reaches a threshold + * size of 1000 pages. + * More here: https://sqlite.org/wal.html + * + * This helper will force checkpoint on RKStorage, if Next storage file does not exists yet. + */ + public static void verifyAndForceSqliteCheckpoint(Context ctx) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + Log.i("AsyncStorage_Next", "SQLite checkpoint not required on this API version."); + } + + File nextStorageFile = ctx.getDatabasePath("AsyncStorage"); + // NOTE(kudo): Expo Go doesn't turn on next storage, having dummy db name to pass build + // File currentStorageFile = ctx.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME); + File currentStorageFile = ctx.getDatabasePath("UNUSED"); + boolean isCheckpointRequired = !nextStorageFile.exists() && currentStorageFile.exists(); + if (!isCheckpointRequired) { + Log.i("AsyncStorage_Next", "SQLite checkpoint not required."); + return; + } + + try { + ReactDatabaseSupplier supplier = ReactDatabaseSupplier.getInstance(ctx); + supplier.get().rawQuery("PRAGMA wal_checkpoint", null).close(); + supplier.closeDatabase(); + Log.i("AsyncStorage_Next", "Forcing SQLite checkpoint successful."); + } catch (Exception e) { + Log.w("AsyncStorage_Next", "Could not force checkpoint on RKStorage, the Next storage might not migrate the data properly: " + e.getMessage()); + } + } +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageErrorUtil.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageErrorUtil.java new file mode 100644 index 00000000000000..8a03c7995ceafb --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageErrorUtil.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import javax.annotation.Nullable; + +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.WritableMap; + +/** + * Helper class for database errors. + */ +public class AsyncStorageErrorUtil { + + /** + * Create Error object to be passed back to the JS callback. + */ + /* package */ static WritableMap getError(@Nullable String key, String errorMessage) { + WritableMap errorMap = Arguments.createMap(); + errorMap.putString("message", errorMessage); + if (key != null) { + errorMap.putString("key", key); + } + return errorMap; + } + + /* package */ static WritableMap getInvalidKeyError(@Nullable String key) { + return getError(key, "Invalid key"); + } + + /* package */ static WritableMap getInvalidValueError(@Nullable String key) { + return getError(key, "Invalid Value"); + } + + /* package */ static WritableMap getDBError(@Nullable String key) { + return getError(key, "Database Error"); + } + + +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageExpoMigration.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageExpoMigration.java new file mode 100644 index 00000000000000..4fcc9eaa3bf03a --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageExpoMigration.java @@ -0,0 +1,157 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import android.content.Context; +import android.os.Build; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; + +// A utility class that migrates a scoped AsyncStorage database to RKStorage. +// This utility only runs if the RKStorage file has not been created yet. +public class AsyncStorageExpoMigration { + static final String LOG_TAG = "AsyncStorageExpoMigration"; + + public static void migrate(Context context) { + // Only migrate if the default async storage file does not exist. + if (isAsyncStorageDatabaseCreated(context)) { + return; + } + + ArrayList expoDatabases = getExpoDatabases(context); + + File expoDatabase = getLastModifiedFile(expoDatabases); + + if (expoDatabase == null) { + Log.v(LOG_TAG, "No scoped database found"); + return; + } + + try { + // Create the storage file + ReactDatabaseSupplier.getInstance(context).get(); + // NOTE(kudo): Don't run migration on Expo Go for backward compatibility + // copyFile(new FileInputStream(expoDatabase), new FileOutputStream(context.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME))); + Log.v(LOG_TAG, "Migrated most recently modified database " + expoDatabase.getName() + " to RKStorage"); + } catch (Exception e) { + Log.v(LOG_TAG, "Failed to migrate scoped database " + expoDatabase.getName()); + e.printStackTrace(); + return; + } + + try { + for (File file : expoDatabases) { + if (file.delete()) { + Log.v(LOG_TAG, "Deleted scoped database " + file.getName()); + } else { + Log.v(LOG_TAG, "Failed to delete scoped database " + file.getName()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + Log.v(LOG_TAG, "Completed the scoped AsyncStorage migration"); + } + + private static boolean isAsyncStorageDatabaseCreated(Context context) { + // NOTE(kudo): Don't run migration on Expo Go for backward compatibility + // return context.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME).exists(); + return true; + } + + // Find all database files that the user may have created while using Expo. + private static ArrayList getExpoDatabases(Context context) { + ArrayList scopedDatabases = new ArrayList<>(); + try { + File databaseDirectory = context.getDatabasePath("noop").getParentFile(); + File[] directoryListing = databaseDirectory.listFiles(); + if (directoryListing != null) { + for (File child : directoryListing) { + // Find all databases matching the Expo scoped key, and skip any database journals. + if (child.getName().startsWith("RKStorage-scoped-experience-") && !child.getName().endsWith("-journal")) { + scopedDatabases.add(child); + } + } + } + } catch (Exception e) { + // Just in case anything happens catch and print, file system rules can tend to be different across vendors. + e.printStackTrace(); + } + return scopedDatabases; + } + + // Returns the most recently modified file. + // If a user publishes an app with Expo, then changes the slug + // and publishes again, a new database will be created. + // We want to select the most recent database and migrate it to RKStorage. + private static File getLastModifiedFile(ArrayList files) { + if (files.size() == 0) { + return null; + } + long lastMod = -1; + File lastModFile = null; + for (File child : files) { + long modTime = getLastModifiedTimeInMillis(child); + if (modTime > lastMod) { + lastMod = modTime; + lastModFile = child; + } + } + if (lastModFile != null) { + return lastModFile; + } + + return files.get(0); + } + + private static long getLastModifiedTimeInMillis(File file) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return getLastModifiedTimeFromBasicFileAttrs(file); + } else { + return file.lastModified(); + } + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private static long getLastModifiedTimeFromBasicFileAttrs(File file) { + try { + return Files.readAttributes(file.toPath(), BasicFileAttributes.class).creationTime().toMillis(); + } catch (Exception e) { + return -1; + } + } + + private static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException { + FileChannel fromChannel = null; + FileChannel toChannel = null; + try { + fromChannel = fromFile.getChannel(); + toChannel = toFile.getChannel(); + fromChannel.transferTo(0, fromChannel.size(), toChannel); + } finally { + try { + if (fromChannel != null) { + fromChannel.close(); + } + } finally { + if (toChannel != null) { + toChannel.close(); + } + } + } + } +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java new file mode 100644 index 00000000000000..7fc1e6e9c7849b --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java @@ -0,0 +1,425 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.os.AsyncTask; + +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.Callback; +import abi49_0_0.com.facebook.react.bridge.GuardedAsyncTask; +import abi49_0_0.com.facebook.react.bridge.LifecycleEventListener; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.WritableArray; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import abi49_0_0.com.facebook.react.common.annotations.VisibleForTesting; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.facebook.react.modules.common.ModuleDataCleaner; + +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +@ReactModule(name = AsyncStorageModule.NAME) +public class AsyncStorageModule + extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable, LifecycleEventListener { + + // changed name to not conflict with AsyncStorage from RN repo + public static final String NAME = "RNC_AsyncSQLiteDBStorage"; + + // SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER: + // https://raw.githubusercontent.com/android/platform_external_sqlite/master/dist/sqlite3.c + private static final int MAX_SQL_KEYS = 999; + + public ReactDatabaseSupplier mReactDatabaseSupplier; + private boolean mShuttingDown = false; + + private final SerialExecutor executor; + + public AsyncStorageModule(ReactApplicationContext reactContext) { + this( + reactContext, + BuildConfig.AsyncStorage_useDedicatedExecutor + ? Executors.newSingleThreadExecutor() + : AsyncTask.THREAD_POOL_EXECUTOR + ); + } + + @VisibleForTesting + AsyncStorageModule(ReactApplicationContext reactContext, Executor executor) { + super(reactContext); + // The migration MUST run before the AsyncStorage database is created for the first time. + AsyncStorageExpoMigration.migrate(reactContext); + + this.executor = new SerialExecutor(executor); + reactContext.addLifecycleEventListener(this); + // Creating the database MUST happen after the migration. + // NOTE(kudo): ExponentAsyncStorageModule will setup the `mReactDatabaseSupplier` + mReactDatabaseSupplier = ReactDatabaseSupplier.getInstance(reactContext); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public void initialize() { + super.initialize(); + mShuttingDown = false; + } + + @Override + public void onCatalystInstanceDestroy() { + mShuttingDown = true; + } + + @Override + public void clearSensitiveData() { + // Clear local storage. If fails, crash, since the app is potentially in a bad state and could + // cause a privacy violation. We're still not recovering from this well, but at least the error + // will be reported to the server. + mReactDatabaseSupplier.clearAndCloseDatabase(); + } + + @Override + public void onHostResume() {} + + @Override + public void onHostPause() {} + + @Override + public void onHostDestroy() { + // ensure we close database when activity is destroyed + mReactDatabaseSupplier.closeDatabase(); + } + + /** + * Given an array of keys, this returns a map of (key, value) pairs for the keys found, and + * (key, null) for the keys that haven't been found. + */ + @ReactMethod + public void multiGet(final ReadableArray keys, final Callback callback) { + if (keys == null) { + callback.invoke(AsyncStorageErrorUtil.getInvalidKeyError(null), null); + return; + } + + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + if (!ensureDatabase()) { + callback.invoke(AsyncStorageErrorUtil.getDBError(null), null); + return; + } + + String[] columns = {ReactDatabaseSupplier.KEY_COLUMN, ReactDatabaseSupplier.VALUE_COLUMN}; + HashSet keysRemaining = new HashSet<>(); + WritableArray data = Arguments.createArray(); + for (int keyStart = 0; keyStart < keys.size(); keyStart += MAX_SQL_KEYS) { + int keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS); + Cursor cursor = mReactDatabaseSupplier.get().query( + ReactDatabaseSupplier.TABLE_CATALYST, + columns, + AsyncLocalStorageUtil.buildKeySelection(keyCount), + AsyncLocalStorageUtil.buildKeySelectionArgs(keys, keyStart, keyCount), + null, + null, + null); + keysRemaining.clear(); + try { + if (cursor.getCount() != keys.size()) { + // some keys have not been found - insert them with null into the final array + for (int keyIndex = keyStart; keyIndex < keyStart + keyCount; keyIndex++) { + keysRemaining.add(keys.getString(keyIndex)); + } + } + + if (cursor.moveToFirst()) { + do { + WritableArray row = Arguments.createArray(); + row.pushString(cursor.getString(0)); + row.pushString(cursor.getString(1)); + data.pushArray(row); + keysRemaining.remove(cursor.getString(0)); + } while (cursor.moveToNext()); + } + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage()), null); + return; + } finally { + cursor.close(); + } + + for (String key : keysRemaining) { + WritableArray row = Arguments.createArray(); + row.pushString(key); + row.pushNull(); + data.pushArray(row); + } + keysRemaining.clear(); + } + + callback.invoke(null, data); + } + }.executeOnExecutor(executor); + } + + /** + * Inserts multiple (key, value) pairs. If one or more of the pairs cannot be inserted, this will + * return AsyncLocalStorageFailure, but all other pairs will have been inserted. + * The insertion will replace conflicting (key, value) pairs. + */ + @ReactMethod + public void multiSet(final ReadableArray keyValueArray, final Callback callback) { + if (keyValueArray.size() == 0) { + callback.invoke(); + return; + } + + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + if (!ensureDatabase()) { + callback.invoke(AsyncStorageErrorUtil.getDBError(null)); + return; + } + + String sql = "INSERT OR REPLACE INTO " + ReactDatabaseSupplier.TABLE_CATALYST + " VALUES (?, ?);"; + SQLiteStatement statement = mReactDatabaseSupplier.get().compileStatement(sql); + WritableMap error = null; + try { + mReactDatabaseSupplier.get().beginTransaction(); + for (int idx=0; idx < keyValueArray.size(); idx++) { + if (keyValueArray.getArray(idx).size() != 2) { + error = AsyncStorageErrorUtil.getInvalidValueError(null); + return; + } + if (keyValueArray.getArray(idx).getString(0) == null) { + error = AsyncStorageErrorUtil.getInvalidKeyError(null); + return; + } + if (keyValueArray.getArray(idx).getString(1) == null) { + error = AsyncStorageErrorUtil.getInvalidValueError(null); + return; + } + + statement.clearBindings(); + statement.bindString(1, keyValueArray.getArray(idx).getString(0)); + statement.bindString(2, keyValueArray.getArray(idx).getString(1)); + statement.execute(); + } + mReactDatabaseSupplier.get().setTransactionSuccessful(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + error = AsyncStorageErrorUtil.getError(null, e.getMessage()); + } finally { + try { + mReactDatabaseSupplier.get().endTransaction(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + if (error == null) { + error = AsyncStorageErrorUtil.getError(null, e.getMessage()); + } + } + } + if (error != null) { + callback.invoke(error); + } else { + callback.invoke(); + } + } + }.executeOnExecutor(executor); + } + + /** + * Removes all rows of the keys given. + */ + @ReactMethod + public void multiRemove(final ReadableArray keys, final Callback callback) { + if (keys.size() == 0) { + callback.invoke(); + return; + } + + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + if (!ensureDatabase()) { + callback.invoke(AsyncStorageErrorUtil.getDBError(null)); + return; + } + + WritableMap error = null; + try { + mReactDatabaseSupplier.get().beginTransaction(); + for (int keyStart = 0; keyStart < keys.size(); keyStart += MAX_SQL_KEYS) { + int keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS); + mReactDatabaseSupplier.get().delete( + ReactDatabaseSupplier.TABLE_CATALYST, + AsyncLocalStorageUtil.buildKeySelection(keyCount), + AsyncLocalStorageUtil.buildKeySelectionArgs(keys, keyStart, keyCount)); + } + mReactDatabaseSupplier.get().setTransactionSuccessful(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + error = AsyncStorageErrorUtil.getError(null, e.getMessage()); + } finally { + try { + mReactDatabaseSupplier.get().endTransaction(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + if (error == null) { + error = AsyncStorageErrorUtil.getError(null, e.getMessage()); + } + } + } + if (error != null) { + callback.invoke(error); + } else { + callback.invoke(); + } + } + }.executeOnExecutor(executor); + } + + /** + * Given an array of (key, value) pairs, this will merge the given values with the stored values + * of the given keys, if they exist. + */ + @ReactMethod + public void multiMerge(final ReadableArray keyValueArray, final Callback callback) { + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + if (!ensureDatabase()) { + callback.invoke(AsyncStorageErrorUtil.getDBError(null)); + return; + } + WritableMap error = null; + try { + mReactDatabaseSupplier.get().beginTransaction(); + for (int idx = 0; idx < keyValueArray.size(); idx++) { + if (keyValueArray.getArray(idx).size() != 2) { + error = AsyncStorageErrorUtil.getInvalidValueError(null); + return; + } + + if (keyValueArray.getArray(idx).getString(0) == null) { + error = AsyncStorageErrorUtil.getInvalidKeyError(null); + return; + } + + if (keyValueArray.getArray(idx).getString(1) == null) { + error = AsyncStorageErrorUtil.getInvalidValueError(null); + return; + } + + if (!AsyncLocalStorageUtil.mergeImpl( + mReactDatabaseSupplier.get(), + keyValueArray.getArray(idx).getString(0), + keyValueArray.getArray(idx).getString(1))) { + error = AsyncStorageErrorUtil.getDBError(null); + return; + } + } + mReactDatabaseSupplier.get().setTransactionSuccessful(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + error = AsyncStorageErrorUtil.getError(null, e.getMessage()); + } finally { + try { + mReactDatabaseSupplier.get().endTransaction(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + if (error == null) { + error = AsyncStorageErrorUtil.getError(null, e.getMessage()); + } + } + } + if (error != null) { + callback.invoke(error); + } else { + callback.invoke(); + } + } + }.executeOnExecutor(executor); + } + + /** + * Clears the database. + */ + @ReactMethod + public void clear(final Callback callback) { + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + if (!mReactDatabaseSupplier.ensureDatabase()) { + callback.invoke(AsyncStorageErrorUtil.getDBError(null)); + return; + } + try { + mReactDatabaseSupplier.clear(); + callback.invoke(); + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage())); + } + } + }.executeOnExecutor(executor); + } + + /** + * Returns an array with all keys from the database. + */ + @ReactMethod + public void getAllKeys(final Callback callback) { + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + if (!ensureDatabase()) { + callback.invoke(AsyncStorageErrorUtil.getDBError(null), null); + return; + } + WritableArray data = Arguments.createArray(); + String[] columns = {ReactDatabaseSupplier.KEY_COLUMN}; + Cursor cursor = mReactDatabaseSupplier.get() + .query(ReactDatabaseSupplier.TABLE_CATALYST, columns, null, null, null, null, null); + try { + if (cursor.moveToFirst()) { + do { + data.pushString(cursor.getString(0)); + } while (cursor.moveToNext()); + } + } catch (Exception e) { + FLog.w(ReactConstants.TAG, e.getMessage(), e); + callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage()), null); + return; + } finally { + cursor.close(); + } + callback.invoke(null, data); + } + }.executeOnExecutor(executor); + } + + /** + * Verify the database is open for reads and writes. + */ + private boolean ensureDatabase() { + return !mShuttingDown && mReactDatabaseSupplier.ensureDatabase(); + } +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java new file mode 100644 index 00000000000000..3b5bf21adafe62 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import android.util.Log; +import abi49_0_0.com.facebook.react.ReactPackage; +import abi49_0_0.com.facebook.react.bridge.JavaScriptModule; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class AsyncStoragePackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + + List moduleList = new ArrayList<>(1); + + if (BuildConfig.AsyncStorage_useNextStorage) { + try { + Class storageClass = Class.forName("com.reactnativecommunity.asyncstorage.next.StorageModule"); + NativeModule inst = (NativeModule) storageClass.getDeclaredConstructor(new Class[]{ReactContext.class}).newInstance(reactContext); + moduleList.add(inst); + AsyncLocalStorageUtil.verifyAndForceSqliteCheckpoint(reactContext); + } catch (Exception e) { + String message = "Something went wrong when initializing module:" + + "\n" + + e.getCause().getClass() + + "\n" + + "Cause:" + e.getCause().getLocalizedMessage(); + Log.e("AsyncStorage_Next", message); + } + } else { + moduleList.add(new AsyncStorageModule(reactContext)); + } + + return moduleList; + } + + // Deprecated in RN 0.47 + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + @SuppressWarnings("rawtypes") + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/ReactDatabaseSupplier.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/ReactDatabaseSupplier.java new file mode 100644 index 00000000000000..98e0bb5c438f02 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/ReactDatabaseSupplier.java @@ -0,0 +1,176 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteOpenHelper; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import javax.annotation.Nullable; + +/** + * Database supplier of the database used by react native. This creates, opens and deletes the + * database as necessary. + */ +public class ReactDatabaseSupplier extends SQLiteOpenHelper { + + // VisibleForTesting + // NOTE(kudo): Dynamic database name for scoped async storage + // public static final String DATABASE_NAME = "RKStorage"; + public String DATABASE_NAME = "RKStorage"; + + private static final int DATABASE_VERSION = 1; + private static final int SLEEP_TIME_MS = 30; + + static final String TABLE_CATALYST = "catalystLocalStorage"; + static final String KEY_COLUMN = "key"; + static final String VALUE_COLUMN = "value"; + + static final String VERSION_TABLE_CREATE = + "CREATE TABLE " + TABLE_CATALYST + " (" + + KEY_COLUMN + " TEXT PRIMARY KEY, " + + VALUE_COLUMN + " TEXT NOT NULL" + + ")"; + + private static @Nullable ReactDatabaseSupplier sReactDatabaseSupplierInstance; + + private Context mContext; + private @Nullable SQLiteDatabase mDb; + private long mMaximumDatabaseSize = BuildConfig.AsyncStorage_db_size * 1024L * 1024L; + + private ReactDatabaseSupplier(Context context) { + // NOTE(kudo): Dynamic database name for scoped async storage + // super(context, databaseName, null, DATABASE_VERSION); + // mContext = context; + super(context, "RKStorage", null, DATABASE_VERSION); + mContext = context; + DATABASE_NAME = "RKStorage"; + } + + // NOTE(kudo): Dynamic database name for scoped async storage + public ReactDatabaseSupplier(Context context, String databaseName) { + super(context, databaseName, null, DATABASE_VERSION); + mContext = context; + DATABASE_NAME = databaseName; + } + + public static ReactDatabaseSupplier getInstance(Context context) { + if (sReactDatabaseSupplierInstance == null) { + sReactDatabaseSupplierInstance = new ReactDatabaseSupplier(context.getApplicationContext()); + } + return sReactDatabaseSupplierInstance; + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(VERSION_TABLE_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion != newVersion) { + deleteDatabase(); + onCreate(db); + } + } + + /** + * Verify the database exists and is open. + */ + /* package */ synchronized boolean ensureDatabase() { + if (mDb != null && mDb.isOpen()) { + return true; + } + // Sometimes retrieving the database fails. We do 2 retries: first without database deletion + // and then with deletion. + SQLiteException lastSQLiteException = null; + for (int tries = 0; tries < 2; tries++) { + try { + if (tries > 0) { + deleteDatabase(); + } + mDb = getWritableDatabase(); + break; + } catch (SQLiteException e) { + lastSQLiteException = e; + } + // Wait before retrying. + try { + Thread.sleep(SLEEP_TIME_MS); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (mDb == null) { + throw lastSQLiteException; + } + // This is a sane limit to protect the user from the app storing too much data in the database. + // This also protects the database from filling up the disk cache and becoming malformed + // (endTransaction() calls will throw an exception, not rollback, and leave the db malformed). + mDb.setMaximumSize(mMaximumDatabaseSize); + return true; + } + + /** + * Create and/or open the database. + */ + public synchronized SQLiteDatabase get() { + ensureDatabase(); + return mDb; + } + + public synchronized void clearAndCloseDatabase() throws RuntimeException { + try { + clear(); + closeDatabase(); + FLog.d(ReactConstants.TAG, "Cleaned " + DATABASE_NAME); + } catch (Exception e) { + // Clearing the database has failed, delete it instead. + if (deleteDatabase()) { + FLog.d(ReactConstants.TAG, "Deleted Local Database " + DATABASE_NAME); + return; + } + // Everything failed, throw + throw new RuntimeException("Clearing and deleting database " + DATABASE_NAME + " failed"); + } + } + + /* package */ synchronized void clear() { + get().delete(TABLE_CATALYST, null, null); + } + + /** + * Sets the maximum size the database will grow to. The maximum size cannot + * be set below the current size. + */ + public synchronized void setMaximumSize(long size) { + mMaximumDatabaseSize = size; + if (mDb != null) { + mDb.setMaximumSize(mMaximumDatabaseSize); + } + } + + private synchronized boolean deleteDatabase() { + closeDatabase(); + return mContext.deleteDatabase(DATABASE_NAME); + } + + public synchronized void closeDatabase() { + if (mDb != null && mDb.isOpen()) { + mDb.close(); + mDb = null; + } + } + + // For testing purposes only! + public static void deleteInstance() { + sReactDatabaseSupplierInstance = null; + } +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/SerialExecutor.java b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/SerialExecutor.java new file mode 100644 index 00000000000000..39140803f0ac42 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/SerialExecutor.java @@ -0,0 +1,40 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage; + +import java.util.ArrayDeque; +import java.util.concurrent.Executor; + +/** + * Detox is using this implementation detail in its environment setup, + * so in order for Next storage to work, this class has been made public + * + * Adapted from https://android.googlesource.com/platform/frameworks/base.git/+/1488a3a19d4681a41fb45570c15e14d99db1cb66/core/java/android/os/AsyncTask.java#237 + */ +public class SerialExecutor implements Executor { + private final ArrayDeque mTasks = new ArrayDeque(); + private Runnable mActive; + private final Executor executor; + + public SerialExecutor(Executor executor) { + this.executor = executor; + } + + public synchronized void execute(final Runnable r) { + mTasks.offer(new Runnable() { + public void run() { + try { + r.run(); + } finally { + scheduleNext(); + } + } + }); + if (mActive == null) { + scheduleNext(); + } + } + synchronized void scheduleNext() { + if ((mActive = mTasks.poll()) != null) { + executor.execute(mActive); + } + } +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ArgumentHelpers.kt b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ArgumentHelpers.kt new file mode 100644 index 00000000000000..da594a6c42b781 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ArgumentHelpers.kt @@ -0,0 +1,86 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage.next + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.ReadableArray +import org.json.JSONException +import org.json.JSONObject + +fun ReadableArray.toEntryList(): List { + val list = mutableListOf() + for (keyValue in this.toArrayList()) { + if (keyValue !is ArrayList<*> || keyValue.size != 2) { + throw AsyncStorageError.invalidKeyValueFormat() + } + val key = keyValue[0] + val value = keyValue[1] + + if (key !is String) { + when (key) { + null -> throw AsyncStorageError.keyIsNull() + else -> throw AsyncStorageError.keyNotString() + } + } + + if (value !is String) { + throw AsyncStorageError.valueNotString(key) + } + + list.add(Entry(key, value)) + } + return list +} + +fun ReadableArray.toKeyList(): List { + val list = this.toArrayList() + + for (item in list) { + if (item !is String) { + throw AsyncStorageError.keyNotString() + } + } + return list as List +} + +fun List.toKeyValueArgument(): ReadableArray { + val args = Arguments.createArray() + + for (entry in this) { + val keyValue = Arguments.createArray() + keyValue.pushString(entry.key) + keyValue.pushString(entry.value) + args.pushArray(keyValue) + } + + return args +} + +fun String?.isValidJson(): Boolean { + if (this == null) return false + + return try { + JSONObject(this) + true + } catch (e: JSONException) { + false + } +} + +fun JSONObject.mergeWith(newObject: JSONObject): JSONObject { + + val keys = newObject.keys() + val mergedObject = JSONObject(this.toString()) + + while (keys.hasNext()) { + val key = keys.next() + val curValue = this.optJSONObject(key) + val newValue = newObject.optJSONObject(key) + + if (curValue != null && newValue != null) { + val merged = curValue.mergeWith(newValue) + mergedObject.put(key, merged) + } else { + mergedObject.put(key, newObject.get(key)) + } + } + return mergedObject +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ErrorHelpers.kt b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ErrorHelpers.kt new file mode 100644 index 00000000000000..fe977c36162299 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ErrorHelpers.kt @@ -0,0 +1,39 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage.next + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.Callback +import kotlinx.coroutines.CoroutineExceptionHandler + +internal fun createExceptionHandler(cb: Callback): CoroutineExceptionHandler { + return CoroutineExceptionHandler { _, throwable -> + val error = Arguments.createMap() + if (throwable !is AsyncStorageError) { + error.putString( + "message", "Unexpected AsyncStorage error: ${throwable.localizedMessage}" + ) + } else { + error.putString("message", throwable.errorMessage) + } + + cb(error) + } +} + +internal class AsyncStorageError private constructor(val errorMessage: String) : + Throwable(errorMessage) { + + companion object { + fun keyIsNull() = AsyncStorageError("Key cannot be null.") + + fun keyNotString() = AsyncStorageError("Provided key is not string. Only strings are supported as storage key.") + + fun valueNotString(key: String?): AsyncStorageError { + val detail = if (key == null) "Provided value" else "Value for key \"$key\"" + return AsyncStorageError("$detail is not a string. Only strings are supported as a value.") + } + + fun invalidKeyValueFormat() = + AsyncStorageError("Invalid key-value format. Expected a list of [key, value] list.") + + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageModule.kt b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageModule.kt new file mode 100644 index 00000000000000..96d114caf7c654 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageModule.kt @@ -0,0 +1,90 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage.next + +import android.content.Context +import androidx.annotation.VisibleForTesting +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.Callback +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule +import abi49_0_0.com.facebook.react.bridge.ReactMethod +import abi49_0_0.com.facebook.react.bridge.ReadableArray +import abi49_0_0.com.reactnativecommunity.asyncstorage.SerialExecutor +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.asExecutor +import kotlinx.coroutines.launch + +class StorageModule(reactContext: ReactContext) : ReactContextBaseJavaModule(), CoroutineScope { + override fun getName() = "RNC_AsyncSQLiteDBStorage" + + // this executor is not used by the module, but it must exists here due to + // Detox relying on this implementation detail to run + @VisibleForTesting + private val executor = SerialExecutor(Dispatchers.Main.asExecutor()) + + override val coroutineContext = + Dispatchers.IO + CoroutineName("AsyncStorageScope") + SupervisorJob() + + private val storage = StorageSupplier.getInstance(reactContext) + + companion object { + @JvmStatic + fun getStorageInstance(ctx: Context): AsyncStorageAccess { + return StorageSupplier.getInstance(ctx) + } + } + + @ReactMethod + fun multiGet(keys: ReadableArray, cb: Callback) { + launch(createExceptionHandler(cb)) { + val entries = storage.getValues(keys.toKeyList()) + cb(null, entries.toKeyValueArgument()) + } + } + + @ReactMethod + fun multiSet(keyValueArray: ReadableArray, cb: Callback) { + launch(createExceptionHandler(cb)) { + val entries = keyValueArray.toEntryList() + storage.setValues(entries) + cb(null) + } + } + + @ReactMethod + fun multiRemove(keys: ReadableArray, cb: Callback) { + launch(createExceptionHandler(cb)) { + storage.removeValues(keys.toKeyList()) + cb(null) + } + } + + @ReactMethod + fun multiMerge(keyValueArray: ReadableArray, cb: Callback) { + launch(createExceptionHandler(cb)) { + val entries = keyValueArray.toEntryList() + storage.mergeValues(entries) + cb(null) + } + } + + @ReactMethod + fun getAllKeys(cb: Callback) { + launch(createExceptionHandler(cb)) { + val keys = storage.getKeys() + val result = Arguments.createArray() + keys.forEach { result.pushString(it) } + cb.invoke(null, result) + } + } + + @ReactMethod + fun clear(cb: Callback) { + launch(createExceptionHandler(cb)) { + storage.clear() + cb(null) + } + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt new file mode 100644 index 00000000000000..139108550e2b6a --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/main/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt @@ -0,0 +1,161 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage.next + +import android.content.Context +import android.util.Log +import androidx.room.ColumnInfo +import androidx.room.Dao +import androidx.room.Database +import androidx.room.Entity +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.PrimaryKey +import androidx.room.Query +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.Transaction +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase +import org.json.JSONObject + +private const val DATABASE_VERSION = 2 +private const val DATABASE_NAME = "AsyncStorage" +private const val TABLE_NAME = "Storage" +private const val COLUMN_KEY = "key" +private const val COLUMN_VALUE = "value" + + +@Entity(tableName = TABLE_NAME) +data class Entry( + @PrimaryKey @ColumnInfo(name = COLUMN_KEY) val key: String, + @ColumnInfo(name = COLUMN_VALUE) val value: String? +) + +@Dao +internal interface StorageDao { + + @Transaction + @Query("SELECT * FROM $TABLE_NAME WHERE `$COLUMN_KEY` IN (:keys)") + suspend fun getValues(keys: List): List + + @Transaction + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun setValues(entries: List) + + @Transaction + @Query("DELETE FROM $TABLE_NAME WHERE `$COLUMN_KEY` in (:keys)") + suspend fun removeValues(keys: List) + + @Transaction + suspend fun mergeValues(entries: List) { + val currentDbEntries = getValues(entries.map { it.key }) + val newEntries = mutableListOf() + + entries.forEach { newEntry -> + val oldEntry = currentDbEntries.find { it.key == newEntry.key } + if (oldEntry?.value == null) { + newEntries.add(newEntry) + } else if (!oldEntry.value.isValidJson() || !newEntry.value.isValidJson()) { + newEntries.add(newEntry) + } else { + val newValue = + JSONObject(oldEntry.value).mergeWith(JSONObject(newEntry.value)).toString() + newEntries.add(newEntry.copy(value = newValue)) + } + } + setValues(newEntries) + } + + @Transaction + @Query("SELECT `$COLUMN_KEY` FROM $TABLE_NAME") + suspend fun getKeys(): List + + @Transaction + @Query("DELETE FROM $TABLE_NAME") + suspend fun clear() +} + + +/** + * Previous version of AsyncStorage is violating the SQL standard (based on bug in SQLite), + * where PrimaryKey ('key' column) should never be null (https://www.sqlite.org/lang_createtable.html#the_primary_key). + * Because of that, we cannot reuse the old DB, because ROOM is guarded against that case (won't compile). + * + * In order to work around this, two steps are necessary: + * - Room DB pre-population from the old database file (https://developer.android.com/training/data-storage/room/prepopulate#from-asset) + * - Version migration, so that we can mark 'key' column as NOT-NULL + * + * This migration will happens only once, when developer enable this feature (when DB is still not created). + */ +@Suppress("ClassName") +private object MIGRATION_TO_NEXT : Migration(1, 2) { + override fun migrate(database: SupportSQLiteDatabase) { + val oldTableName = "catalystLocalStorage" // from ReactDatabaseSupplier + database.execSQL("CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`${COLUMN_KEY}` TEXT NOT NULL, `${COLUMN_VALUE}` TEXT, PRIMARY KEY(`${COLUMN_KEY}`));") + // even if the old AsyncStorage has checks for not nullable keys + // make sure we don't copy any, to not fail migration + database.execSQL("DELETE FROM $oldTableName WHERE `${COLUMN_KEY}` IS NULL") + database.execSQL( + """ + INSERT INTO $TABLE_NAME (`${COLUMN_KEY}`, `${COLUMN_VALUE}`) + SELECT `${COLUMN_KEY}`, `${COLUMN_VALUE}` + FROM $oldTableName; + """.trimIndent() + ) + Log.e("AsyncStorage_Next", "Migration to Next storage completed.") + } +} + +@Database(entities = [Entry::class], version = DATABASE_VERSION, exportSchema = false) +internal abstract class StorageDb : RoomDatabase() { + abstract fun storage(): StorageDao + + companion object { + private var instance: StorageDb? = null + + fun getDatabase(context: Context): StorageDb { + var inst = instance + if (inst != null) { + return inst + } + synchronized(this) { + val oldDbFile = context.getDatabasePath("RKStorage") + val db = Room.databaseBuilder( + context, StorageDb::class.java, DATABASE_NAME + ) + if (oldDbFile.exists()) { + // migrate data from old database, if it exists + db.createFromFile(oldDbFile).addMigrations(MIGRATION_TO_NEXT) + } + inst = db.build() + instance = inst + return instance!! + } + } + } +} + +interface AsyncStorageAccess { + suspend fun getValues(keys: List): List + suspend fun setValues(entries: List) + suspend fun removeValues(keys: List) + suspend fun getKeys(): List + suspend fun clear() + suspend fun mergeValues(entries: List) +} + +class StorageSupplier internal constructor(db: StorageDb) : AsyncStorageAccess { + companion object { + fun getInstance(ctx: Context): AsyncStorageAccess { + return StorageSupplier(StorageDb.getDatabase(ctx)) + } + } + + private val access = db.storage() + + override suspend fun getValues(keys: List) = access.getValues(keys) + override suspend fun setValues(entries: List) = access.setValues(entries) + override suspend fun removeValues(keys: List) = access.removeValues(keys) + override suspend fun mergeValues(entries: List) = access.mergeValues(entries) + override suspend fun getKeys() = access.getKeys() + override suspend fun clear() = access.clear() +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/test/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ArgumentHelpersTest.kt b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/test/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ArgumentHelpersTest.kt new file mode 100644 index 00000000000000..0e2f5476813241 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/test/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/ArgumentHelpersTest.kt @@ -0,0 +1,93 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage.next + +import abi49_0_0.com.facebook.react.bridge.JavaOnlyArray +import abi49_0_0.com.facebook.react.bridge.ReadableArray +import com.google.common.truth.Truth.assertThat +import org.junit.Assert.assertThrows +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +@RunWith(BlockJUnit4ClassRunner::class) +class ArgumentHelpersTest { + + @Test + fun transformsArgumentsToEntryList() { + val args = JavaOnlyArray.of( + arrayListOf("key1", "value1"), + arrayListOf("key2", "value2"), + arrayListOf("key3", "value3") + ) + assertThat(args.toEntryList()).isEqualTo( + listOf( + Entry("key1", "value1"), + Entry("key2", "value2"), + Entry("key3", "value3"), + ) + ) + } + + @Test + fun transfersArgumentsToKeyList() { + val keyList = listOf("key1", "key2", "key3") + val args = keyList.toReadableArray() + assertThat(args.toKeyList()).isEqualTo(keyList) + } + + @Test + fun throwsIfArgumentsNotValidFormat() { + val invalid = arrayListOf("invalid") + val args = JavaOnlyArray.of(invalid) + val error = assertThrows(AsyncStorageError::class.java) { + args.toEntryList() + } + + assertThat(error is AsyncStorageError).isTrue() + assertThat(error).hasMessageThat() + .isEqualTo("Invalid key-value format. Expected a list of [key, value] list.") + } + + @Test + fun throwsIfArgumentKeyIsNullOrNotString() { + val argsInvalidNull = JavaOnlyArray.of(arrayListOf(null, "invalid")) + val errorArgsInvalidNull = assertThrows(AsyncStorageError::class.java) { + argsInvalidNull.toEntryList() + } + assertThat(errorArgsInvalidNull is AsyncStorageError).isTrue() + assertThat(errorArgsInvalidNull).hasMessageThat().isEqualTo("Key cannot be null.") + + val notStringArgs = JavaOnlyArray.of(arrayListOf(123, "invalid")) + val errorNotString = assertThrows(AsyncStorageError::class.java) { + notStringArgs.toEntryList() + } + assertThat(errorNotString is AsyncStorageError).isTrue() + assertThat(errorNotString).hasMessageThat() + .isEqualTo("Provided key is not string. Only strings are supported as storage key.") + } + + @Test + fun throwsIfArgumentValueNotString() { + val invalidArgs = JavaOnlyArray.of(arrayListOf("my_key", 666)) + val error = assertThrows(AsyncStorageError::class.java) { + invalidArgs.toEntryList() + } + assertThat(error is AsyncStorageError).isTrue() + assertThat(error).hasMessageThat() + .isEqualTo("Value for key \"my_key\" is not a string. Only strings are supported as a value.") + } +} + +fun List.toReadableArray(): ReadableArray { + val arr = JavaOnlyArray() + forEach { + when (it) { + null -> arr.pushNull() + is Boolean -> arr.pushBoolean(it) + is Double -> arr.pushDouble(it) + is Int -> arr.pushInt(it) + is String -> arr.pushString(it) + else -> throw NotImplementedError() + } + } + return arr +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/test/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageTest.kt b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/test/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageTest.kt new file mode 100644 index 00000000000000..8315285690f057 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/src/test/java/abi49_0_0/com/reactnativecommunity/asyncstorage/next/StorageTest.kt @@ -0,0 +1,141 @@ +package abi49_0_0.com.reactnativecommunity.asyncstorage.next + +import androidx.room.Room +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking +import org.json.JSONObject +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.random.Random + +@ExperimentalCoroutinesApi +@RunWith(AndroidJUnit4::class) +class AsyncStorageAccessTest { + private lateinit var asyncStorage: AsyncStorageAccess + private lateinit var database: StorageDb + + @Before + fun setup() { + database = Room.inMemoryDatabaseBuilder( + InstrumentationRegistry.getInstrumentation().context, StorageDb::class.java + ).allowMainThreadQueries().build() + asyncStorage = StorageSupplier(database) + } + + @After + fun tearDown() { + database.close() + } + + @Test + fun performsBasicGetSetRemoveOperations() = runBlocking { + val entriesCount = 10 + val entries = createRandomEntries(entriesCount) + val keys = entries.map { it.key } + assertThat(asyncStorage.getValues(keys)).hasSize(0) + asyncStorage.setValues(entries) + assertThat(asyncStorage.getValues(keys)).hasSize(entriesCount) + val indicesToRemove = (1..4).map { Random.nextInt(0, entriesCount) }.distinct() + val toRemove = entries.filterIndexed { index, _ -> indicesToRemove.contains(index) } + asyncStorage.removeValues(toRemove.map { it.key }) + val currentEntries = asyncStorage.getValues(keys) + assertThat(currentEntries).hasSize(entriesCount - toRemove.size) + } + + @Test + fun readsAllKeysAndClearsDb() = runBlocking { + val entries = createRandomEntries(8) + val keys = entries.map { it.key } + asyncStorage.setValues(entries) + val dbKeys = asyncStorage.getKeys() + assertThat(dbKeys).isEqualTo(keys) + asyncStorage.clear() + assertThat(asyncStorage.getValues(keys)).hasSize(0) + } + + @Test + fun mergesDeeplyTwoValues() = runBlocking { + val initialEntry = Entry("key", VALUE_INITIAL) + val overrideEntry = Entry("key", VALUE_OVERRIDES) + asyncStorage.setValues(listOf(initialEntry)) + asyncStorage.mergeValues(listOf(overrideEntry)) + val current = asyncStorage.getValues(listOf("key"))[0] + assertThat(current.value).isEqualTo(VALUE_MERGED) + } + + @Test + fun updatesExistingValues() = runBlocking { + val key = "test_key" + val value = "test_value" + val entries = listOf(Entry(key, value)) + assertThat(asyncStorage.getValues(listOf(key))).hasSize(0) + asyncStorage.setValues(entries) + assertThat(asyncStorage.getValues(listOf(key))).isEqualTo(entries) + val modifiedEntries = listOf(Entry(key, "updatedValue")) + asyncStorage.setValues(modifiedEntries) + assertThat(asyncStorage.getValues(listOf(key))).isEqualTo(modifiedEntries) + } + + + // Test Helpers + private fun createRandomEntries(count: Int = Random.nextInt(10)): List { + val entries = mutableListOf() + for (i in 0 until count) { + entries.add(Entry("key$i", "value$i")) + } + return entries + } + + private val VALUE_INITIAL = JSONObject( + """ + { + "key":"value", + "key2":"override", + "key3":{ + "key4":"value4", + "key6":{ + "key7":"value7", + "key8":"override" + } + } + } +""".trimMargin() + ).toString() + + private val VALUE_OVERRIDES = JSONObject( + """ + { + "key2":"value2", + "key3":{ + "key5":"value5", + "key6":{ + "key8":"value8" + } + } + } +""" + ).toString() + + + private val VALUE_MERGED = JSONObject( + """ + { + "key":"value", + "key2":"value2", + "key3":{ + "key4":"value4", + "key6":{ + "key7":"value7", + "key8":"value8" + }, + "key5":"value5" + } + } +""".trimMargin() + ).toString() +} diff --git a/android/vendored/sdk49/@react-native-async-storage/async-storage/android/testresults.gradle b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/testresults.gradle new file mode 100644 index 00000000000000..50ad3e8ddb6131 --- /dev/null +++ b/android/vendored/sdk49/@react-native-async-storage/async-storage/android/testresults.gradle @@ -0,0 +1,38 @@ + +// pretty print test results +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent +tasks.withType(Test) { + testLogging { + + events TestLogEvent.FAILED, + TestLogEvent.PASSED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_OUT + exceptionFormat TestExceptionFormat.FULL + showExceptions true + showCauses true + showStackTraces true + + debug { + events TestLogEvent.STARTED, + TestLogEvent.FAILED, + TestLogEvent.PASSED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STANDARD_OUT + exceptionFormat TestExceptionFormat.FULL + } + info.events = debug.events + info.exceptionFormat = debug.exceptionFormat + + afterSuite { desc, result -> + if (!desc.parent) { // will match the outermost suite + def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)" + def startItem = '| ', endItem = ' |' + def repeatLength = startItem.length() + output.length() + endItem.length() + println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) + } + } + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-community/slider/android/build.gradle b/android/vendored/sdk49/@react-native-community/slider/android/build.gradle new file mode 100644 index 00000000000000..43a5bdc90bc311 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/build.gradle @@ -0,0 +1,80 @@ +def isNewArchitectureEnabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + +if (isNewArchitectureEnabled()) { + buildscript { + repositories { + mavenCentral() + google() + } + + dependencies { + classpath("com.android.tools.build:gradle:7.1.1") + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("de.undercouch:gradle-download-task:5.0.1") + } + } +} + +apply plugin: 'com.android.library' +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} + +def getExtOrDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeSlider_' + name] +} + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeSlider_' + name]).toInteger() +} + +android { + compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') + buildToolsVersion getExtOrDefault('buildToolsVersion') + + defaultConfig { + minSdkVersion getExtOrIntegerDefault('minSdkVersion') + targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } + + sourceSets { + main { + if (isNewArchitectureEnabled()) { + java.srcDirs += ['src/newarch'] + } else { + java.srcDirs += ['src/oldarch'] + } + } + } +} + +repositories { + google() + mavenCentral() +} + +dependencies { + //noinspection GradleDynamicVersion + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + +} + +if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src") + libraryName = "ReactSlider" + codegenJavaPackageName = "com.reactnativecommunity.slider" + } +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/@react-native-community/slider/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..1db80071e8df9d --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlider.java b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlider.java new file mode 100644 index 00000000000000..fb83a1cb26df20 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlider.java @@ -0,0 +1,294 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package abi49_0_0.com.reactnativecommunity.slider; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.os.Build; +import android.util.AttributeSet; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import androidx.appcompat.widget.AppCompatSeekBar; +import java.net.URL; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import javax.annotation.Nullable; +import abi49_0_0.com.facebook.react.modules.i18nmanager.I18nUtil; +/** + * Slider that behaves more like the iOS one, for consistency. + * + *

On iOS, the value is 0..1. Android SeekBar only supports integer values. For consistency, we + * pretend in JS that the value is 0..1 but set the SeekBar value to 0..100. + * + *

Note that the slider is _not_ a controlled component (setValue isn't called during dragging). + */ +public class ReactSlider extends AppCompatSeekBar { + + /** + * If step is 0 (unset) we default to this total number of steps. Don't use 100 which leads to + * rounding errors (0.200000000001). + */ + private static int DEFAULT_TOTAL_STEPS = 128; + + /** + * We want custom min..max range. Android only supports 0..max range so we implement this + * ourselves. + */ + private double mMinValue = 0; + + private double mMaxValue = 0; + + /** + * Value sent from JS (setState). Doesn't get updated during drag (slider is not a controlled + * component). + */ + private double mValue = 0; + + private boolean isSliding = false; + + /** If zero it's determined automatically. */ + private double mStep = 0; + + private double mStepCalculated = 0; + + private String mAccessibilityUnits; + + private List mAccessibilityIncrements; + + /** Real limit value based on min and max values. This comes from props */ + private double mRealLowerLimit = Long.MIN_VALUE; + + /** Lower limit based on the SeekBar progress 0..total steps */ + private int mLowerLimit; + + /** Real limit value based on min and max values. This comes from props */ + private double mRealUpperLimit = Long.MAX_VALUE; + + /** Upper limit based on the SeekBar progress 0..total steps */ + private int mUpperLimit; + + public ReactSlider(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance(); + super.setLayoutDirection(sharedI18nUtilInstance.isRTL(context) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR); + disableStateListAnimatorIfNeeded(); + } + + private void disableStateListAnimatorIfNeeded() { + // We disable the state list animator for Android 6 and 7; this is a hack to prevent T37452851 + // and https://github.com/facebook/react-native/issues/9979 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + super.setStateListAnimator(null); + } + } + + /* package */ void setMaxValue(double max) { + mMaxValue = max; + updateAll(); + } + + /* package */ void setMinValue(double min) { + mMinValue = min; + updateAll(); + } + + /* package */ void setValue(double value) { + mValue = value; + updateValue(); + } + + /* package */ void setStep(double step) { + mStep = step; + updateAll(); + } + + /* package */ void setLowerLimit(double value) { + mRealLowerLimit = value; + updateLowerLimit(); + } + + /* package */ void setUpperLimit(double value) { + mRealUpperLimit = value; + updateUpperLimit(); + } + + int getLowerLimit() { + return this.mLowerLimit; + } + + int getUpperLimit() { + return this.mUpperLimit; + } + + boolean isSliding() { + return isSliding; + } + + void isSliding(boolean isSliding) { + this.isSliding = isSliding; + } + + void setAccessibilityUnits(String accessibilityUnits) { + mAccessibilityUnits = accessibilityUnits; + } + + void setAccessibilityIncrements(List accessibilityIncrements) { + mAccessibilityIncrements = accessibilityIncrements; + } + + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED || + (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SELECTED && this.isAccessibilityFocused())) { + this.setupAccessibility((int)mValue); + } + } + } + + @Override + public void announceForAccessibility(CharSequence text) { + Context ctx = this.getContext(); + final AccessibilityManager manager = (AccessibilityManager) ctx.getSystemService(Context.ACCESSIBILITY_SERVICE); + + if (manager.isEnabled()) { + final AccessibilityEvent e = AccessibilityEvent.obtain(); + e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); + e.setClassName(this.getClass().getName()); + e.setPackageName(ctx.getPackageName()); + e.getText().add(text); + + TimerTask task = new TimerTask() { + @Override + public void run() { + manager.sendAccessibilityEvent(e); + } + }; + + Timer timer = new Timer(); + timer.schedule(task, 1000); + } + } + + public void setupAccessibility(int index) { + if (mAccessibilityUnits != null && mAccessibilityIncrements != null && mAccessibilityIncrements.size() - 1 == (int)mMaxValue) { + String sliderValue = mAccessibilityIncrements.get(index); + int stringLength = mAccessibilityUnits.length(); + + String spokenUnits = mAccessibilityUnits; + if (sliderValue != null && Integer.parseInt(sliderValue) == 1) { + spokenUnits = spokenUnits.substring(0, stringLength - 1); + } + + this.announceForAccessibility(String.format("%s %s", sliderValue, spokenUnits)); + } + } + + + + /** + * Convert SeekBar's native progress value (e.g. 0..100) to a value passed to JS (e.g. -1.0..2.5). + */ + public double toRealProgress(int seekBarProgress) { + if (seekBarProgress == getMax()) { + return mMaxValue; + } + return seekBarProgress * getStepValue() + mMinValue; + } + + /** Update underlying native SeekBar's values. */ + private void updateAll() { + if (mStep == 0) { + mStepCalculated = (mMaxValue - mMinValue) / (double) DEFAULT_TOTAL_STEPS; + } + setMax(getTotalSteps()); + updateLowerLimit(); + updateUpperLimit(); + updateValue(); + } + + /** Update limit based on props limit, max and min */ + private void updateLowerLimit() { + double limit = Math.max(mRealLowerLimit, mMinValue); + mLowerLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps()); + } + + /** Update limit based on props limit, max and min */ + private void updateUpperLimit() { + double limit = Math.min(mRealUpperLimit, mMaxValue); + mUpperLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps()); + } + + /** Update value only (optimization in case only value is set). */ + private void updateValue() { + setProgress((int) Math.round((mValue - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps())); + } + + private int getTotalSteps() { + return (int) Math.ceil((mMaxValue - mMinValue) / getStepValue()); + } + + private double getStepValue() { + return mStep > 0 ? mStep : mStepCalculated; + } + + private BitmapDrawable getBitmapDrawable(final String uri) { + BitmapDrawable bitmapDrawable = null; + ExecutorService executorService = Executors.newSingleThreadExecutor(); + Future future = executorService.submit(new Callable() { + @Override + public BitmapDrawable call() { + BitmapDrawable bitmapDrawable = null; + try { + Bitmap bitmap = null; + if (uri.startsWith("http://") || uri.startsWith("https://") || + uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:")) { + bitmap = BitmapFactory.decodeStream(new URL(uri).openStream()); + } else { + int drawableId = getResources() + .getIdentifier(uri, "drawable", getContext() + .getPackageName()); + bitmap = BitmapFactory.decodeResource(getResources(), drawableId); + } + + bitmapDrawable = new BitmapDrawable(getResources(), bitmap); + } catch (Exception e) { + e.printStackTrace(); + } + return bitmapDrawable; + } + }); + try { + bitmapDrawable = future.get(); + } catch (Exception e) { + e.printStackTrace(); + } + return bitmapDrawable; + } + + public void setThumbImage(final String uri) { + if (uri != null) { + setThumb(getBitmapDrawable(uri)); + // Enable alpha channel for the thumbImage + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setSplitTrack(false); + } + } else { + setThumb(getThumb()); + } + } +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderEvent.java b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderEvent.java new file mode 100644 index 00000000000000..a6683cf4a8b64c --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderEvent.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.slider; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.uimanager.events.Event; + +/** + * Event emitted by a ReactSliderManager when user changes slider position. + */ +public class ReactSliderEvent extends Event { + + public static final String EVENT_NAME = "topChange"; + + private final double mValue; + private final boolean mFromUser; + + public ReactSliderEvent(int viewId, double value, boolean fromUser) { + super(viewId); + mValue = value; + mFromUser = fromUser; + } + + public double getValue() { + return mValue; + } + + public boolean isFromUser() { + return mFromUser; + } + + + @Override + public String getEventName() { + return EVENT_NAME; + } + + @Override + public short getCoalescingKey() { + return 0; + } + + @Nullable + @Override + protected WritableMap getEventData() { + return serializeEventData(); + } + + private WritableMap serializeEventData() { + WritableMap eventData = Arguments.createMap(); + eventData.putInt("target", getViewTag()); + eventData.putDouble("value", getValue()); + eventData.putBoolean("fromUser", isFromUser()); + return eventData; + } +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManagerImpl.java b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManagerImpl.java new file mode 100644 index 00000000000000..9b39781aa0c7a3 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManagerImpl.java @@ -0,0 +1,141 @@ +package abi49_0_0.com.reactnativecommunity.slider; + +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Build; + +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.common.MapBuilder; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +public class ReactSliderManagerImpl { + + public static final String REACT_CLASS = "RNCSlider"; + + public static ReactSlider createViewInstance(ThemedReactContext context) { + ReactSlider slider = new ReactSlider(context, null); + + if (Build.VERSION.SDK_INT >= 21) { + /** + * The "splitTrack" parameter should have "false" value, + * otherwise the SeekBar progress line doesn't appear when it is rotated. + */ + slider.setSplitTrack(false); + } + + return slider; + } + + public static void setValue(ReactSlider view, double value) { + if (view.isSliding() == false) { + view.setValue(value); + if (view.isAccessibilityFocused() && Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { + view.setupAccessibility((int)value); + } + } + } + + public static void setMinimumValue(ReactSlider view, float value) { + view.setMinValue(value); + } + + public static void setMaximumValue(ReactSlider view, float value) { + view.setMaxValue(value); + } + + public static void setLowerLimit(ReactSlider view, double value) { + view.setLowerLimit(value); + } + + public static void setUpperLimit(ReactSlider view, double value) { + view.setUpperLimit(value); + } + + public static void setStep(ReactSlider view, float value) { + view.setStep(value); + } + + public static void setDisabled(ReactSlider view, boolean disabled) { + view.setEnabled(!disabled); + } + + public static void setThumbTintColor(ReactSlider view, Integer color) { + if (view.getThumb() != null) { + if (color == null) { + view.getThumb().clearColorFilter(); + } else { + view.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + } + } + + public static void setMinimumTrackTintColor(ReactSlider view, Integer color) { + LayerDrawable drawable = (LayerDrawable) view.getProgressDrawable().getCurrent(); + Drawable progress = drawable.findDrawableByLayerId(android.R.id.progress); + if (color == null) { + progress.clearColorFilter(); + } else { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + progress.setColorFilter(new PorterDuffColorFilter((int)color, PorterDuff.Mode.SRC_IN)); + } + else { + progress.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + } + } + + public static void setThumbImage(ReactSlider view, @Nullable ReadableMap source) { + String uri = null; + if (source != null) { + uri = source.getString("uri"); + } + view.setThumbImage(uri); + } + + public static void setMaximumTrackTintColor(ReactSlider view, Integer color) { + LayerDrawable drawable = (LayerDrawable) view.getProgressDrawable().getCurrent(); + Drawable background = drawable.findDrawableByLayerId(android.R.id.background); + if (color == null) { + background.clearColorFilter(); + } else { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + background.setColorFilter(new PorterDuffColorFilter((int)color, PorterDuff.Mode.SRC_IN)); + } + else { + background.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + } + } + + public static void setInverted(ReactSlider view, boolean inverted) { + if (inverted) view.setScaleX(-1f); + else view.setScaleX(1f); + } + + public static void setAccessibilityUnits(ReactSlider view, String accessibilityUnits) { + view.setAccessibilityUnits(accessibilityUnits); + } + + public static void setAccessibilityIncrements(ReactSlider view, ReadableArray accessibilityIncrements) { + List objectList = accessibilityIncrements.toArrayList(); + List stringList = new ArrayList<>(); + for(Object item: objectList) { + stringList.add((String)item); + } + view.setAccessibilityIncrements(stringList); + } + + public static Map getExportedCustomDirectEventTypeConstants() { + return MapBuilder.of(ReactSlidingCompleteEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRNCSliderSlidingComplete"), + ReactSlidingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRNCSliderSlidingStart")); + } +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderPackage.java b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderPackage.java new file mode 100644 index 00000000000000..35fdfdde3aa1a5 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderPackage.java @@ -0,0 +1,29 @@ +package abi49_0_0.com.reactnativecommunity.slider; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import abi49_0_0.com.facebook.react.ReactPackage; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.facebook.react.bridge.JavaScriptModule; + +public class ReactSliderPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + // Deprecated from RN 0.47 + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + @SuppressWarnings("rawtypes") + public List createViewManagers(ReactApplicationContext reactContext) { + return Arrays.asList(new ReactSliderManager()); + } +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java new file mode 100644 index 00000000000000..fa26eb128a2e99 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.slider; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.uimanager.events.Event; + +/** + * Event emitted when the user finishes dragging the slider. + */ +public class ReactSlidingCompleteEvent extends Event { + + public static final String EVENT_NAME = "topSlidingComplete"; + + private final double mValue; + + public ReactSlidingCompleteEvent(int viewId, double value) { + super(viewId); + mValue = value; + } + + public double getValue() { + return mValue; + } + + @Override + public String getEventName() { + return EVENT_NAME; + } + + @Override + public short getCoalescingKey() { + return 0; + } + + @Override + public boolean canCoalesce() { + return false; + } + + @Nullable + @Override + protected WritableMap getEventData() { + return serializeEventData(); + } + + private WritableMap serializeEventData() { + WritableMap eventData = Arguments.createMap(); + eventData.putInt("target", getViewTag()); + eventData.putDouble("value", getValue()); + return eventData; + } + +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlidingStartEvent.java b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlidingStartEvent.java new file mode 100644 index 00000000000000..95a3e7c58f1db6 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/main/java/abi49_0_0/com/reactnativecommunity/slider/ReactSlidingStartEvent.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.reactnativecommunity.slider; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.uimanager.events.Event; + +/** + * Event emitted when the user starts dragging the slider. + */ + +public class ReactSlidingStartEvent extends Event { + public static final String EVENT_NAME = "topSlidingStart"; + + private final double mValue; + + public ReactSlidingStartEvent(int viewId, double value) { + super(viewId); + mValue = value; + } + + public double getValue() { + return mValue; + } + + @Override + public String getEventName() { + return EVENT_NAME; + } + + @Override + public short getCoalescingKey() { + return 0; + } + + @Override + public boolean canCoalesce() { + return false; + } + + @Nullable + @Override + protected WritableMap getEventData() { + return serializeEventData(); + } + + private WritableMap serializeEventData() { + WritableMap eventData = Arguments.createMap(); + eventData.putInt("target", getViewTag()); + eventData.putDouble("value", getValue()); + return eventData; + } + +} \ No newline at end of file diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/newarch/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManager.java b/android/vendored/sdk49/@react-native-community/slider/android/src/newarch/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManager.java new file mode 100644 index 00000000000000..e50e7c0f32ce65 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/newarch/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManager.java @@ -0,0 +1,213 @@ +package abi49_0_0.com.reactnativecommunity.slider; + +import android.widget.SeekBar; +import androidx.annotation.Nullable; + +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.SimpleViewManager; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper; +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.ViewProps; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher; +import java.util.Map; +import abi49_0_0.com.facebook.react.viewmanagers.RNCSliderManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNCSliderManagerDelegate; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; + +/** + * Manages instances of {@code ReactSlider}. + */ +@ReactModule(name = ReactSliderManagerImpl.REACT_CLASS) +public class ReactSliderManager extends SimpleViewManager implements RNCSliderManagerInterface { + + private final ViewManagerDelegate mDelegate; + + public ReactSliderManager() { + mDelegate = new RNCSliderManagerDelegate<>(this); + } + + @Nullable + @Override + protected ViewManagerDelegate getDelegate() { + return mDelegate; + } + + private static final SeekBar.OnSeekBarChangeListener ON_CHANGE_LISTENER = + new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) { + ReactSlider slider = (ReactSlider)seekbar; + + if(progress < slider.getLowerLimit()) { + progress = slider.getLowerLimit(); + seekbar.setProgress(progress); + } else if (progress > slider.getUpperLimit()) { + progress = slider.getUpperLimit(); + seekbar.setProgress(progress); + } + + ReactContext reactContext = (ReactContext) seekbar.getContext(); + int reactTag = seekbar.getId(); + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + .dispatchEvent(new ReactSliderEvent(reactTag, slider.toRealProgress(progress), fromUser)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekbar) { + ReactContext reactContext = (ReactContext) seekbar.getContext(); + int reactTag = seekbar.getId(); + ((ReactSlider)seekbar).isSliding(true); + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + .dispatchEvent(new ReactSlidingStartEvent( + reactTag, + ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress()))); + } + + @Override + public void onStopTrackingTouch(SeekBar seekbar) { + ReactContext reactContext = (ReactContext) seekbar.getContext(); + ((ReactSlider)seekbar).isSliding(false); + int reactTag = seekbar.getId(); + + EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag); + + eventDispatcher.dispatchEvent( + new ReactSlidingCompleteEvent( + reactTag, + ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress())) + ); + eventDispatcher.dispatchEvent( + new ReactSliderEvent( + reactTag, + ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress()), + !((ReactSlider)seekbar).isSliding())); + } + }; + + @Override + public String getName() { + return ReactSliderManagerImpl.REACT_CLASS; + } + + @Override + protected ReactSlider createViewInstance(ThemedReactContext context) { + return ReactSliderManagerImpl.createViewInstance(context); + } + + @Override + @ReactProp(name = "disabled", defaultBoolean = false) + public void setDisabled(ReactSlider view, boolean disabled) { + ReactSliderManagerImpl.setDisabled(view, disabled); + } + + @Override + @ReactProp(name = "value", defaultFloat = 0f) + public void setValue(ReactSlider view, float value) { + ReactSliderManagerImpl.setValue(view, value); + } + + @Override + @ReactProp(name = "minimumValue", defaultFloat = 0f) + public void setMinimumValue(ReactSlider view, float value) { + ReactSliderManagerImpl.setMinimumValue(view, value); + } + + @Override + @ReactProp(name = "maximumValue", defaultFloat = 0f) + public void setMaximumValue(ReactSlider view, float value) { + ReactSliderManagerImpl.setMaximumValue(view, value); + } + + @Override + @ReactProp(name = "step", defaultFloat = 0f) + public void setStep(ReactSlider view, float value) { + ReactSliderManagerImpl.setStep(view, value); + } + + @Override + @ReactProp(name = "thumbTintColor", customType = "Color") + public void setThumbTintColor(ReactSlider view, Integer color) { + ReactSliderManagerImpl.setThumbTintColor(view, color); + } + + @Override + @ReactProp(name = "minimumTrackTintColor", customType = "Color") + public void setMinimumTrackTintColor(ReactSlider view, Integer color) { + ReactSliderManagerImpl.setMinimumTrackTintColor(view, color); + } + + @Override + @ReactProp(name = "maximumTrackTintColor", customType = "Color") + public void setMaximumTrackTintColor(ReactSlider view, Integer color) { + ReactSliderManagerImpl.setMaximumTrackTintColor(view, color); + } + + @Override + @ReactProp(name = "inverted", defaultBoolean = false) + public void setInverted(ReactSlider view, boolean inverted) { + ReactSliderManagerImpl.setInverted(view, inverted); + } + + @Override + @ReactProp(name = "accessibilityUnits") + public void setAccessibilityUnits(ReactSlider view, String accessibilityUnits) { + ReactSliderManagerImpl.setAccessibilityUnits(view, accessibilityUnits); + } + + @Override + @ReactProp(name = "accessibilityIncrements") + public void setAccessibilityIncrements(ReactSlider view, ReadableArray accessibilityIncrements) { + ReactSliderManagerImpl.setAccessibilityIncrements(view, accessibilityIncrements); + } + + @ReactProp(name = "lowerLimit") + public void setLowerLimit(ReactSlider view, float value) { + ReactSliderManagerImpl.setLowerLimit(view, value); + } + + @ReactProp(name = "upperLimit") + public void setUpperLimit(ReactSlider view, float value) { + ReactSliderManagerImpl.setUpperLimit(view, value); + } + + @Override + @ReactProp(name = "thumbImage") + public void setThumbImage(ReactSlider view, @androidx.annotation.Nullable ReadableMap source) { + ReactSliderManagerImpl.setThumbImage(view, source); + } + + @Override + public void setTestID(ReactSlider view, @Nullable String value) { + super.setTestId(view, value); + } + + @Override + protected void addEventEmitters(final ThemedReactContext reactContext, final ReactSlider view) { + view.setOnSeekBarChangeListener(ON_CHANGE_LISTENER); + } + + @Override + public Map getExportedCustomDirectEventTypeConstants() { + return ReactSliderManagerImpl.getExportedCustomDirectEventTypeConstants(); + } + + // these props are not available on Android, however we must override their setters + @Override + public void setMinimumTrackImage(ReactSlider view, @Nullable ReadableMap readableMap) {} + + @Override + public void setMaximumTrackImage(ReactSlider view, @Nullable ReadableMap readableMap) {} + + @Override + public void setTrackImage(ReactSlider view, @Nullable ReadableMap value) {} + + @Override + public void setTapToSeek(ReactSlider view, boolean value) {} + + @Override + public void setVertical(ReactSlider view, boolean value) {} +} diff --git a/android/vendored/sdk49/@react-native-community/slider/android/src/oldarch/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManager.java b/android/vendored/sdk49/@react-native-community/slider/android/src/oldarch/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManager.java new file mode 100644 index 00000000000000..a4f6b60bf8c6b2 --- /dev/null +++ b/android/vendored/sdk49/@react-native-community/slider/android/src/oldarch/java/abi49_0_0/com/reactnativecommunity/slider/ReactSliderManager.java @@ -0,0 +1,210 @@ +package abi49_0_0.com.reactnativecommunity.slider; + +import android.widget.SeekBar; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.LayoutShadowNode; +import abi49_0_0.com.facebook.react.uimanager.SimpleViewManager; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.ViewProps; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; +import java.util.Map; +import android.view.View; +import javax.annotation.Nullable; + +import abi49_0_0.com.facebook.yoga.YogaMeasureFunction; +import abi49_0_0.com.facebook.yoga.YogaMeasureMode; +import abi49_0_0.com.facebook.yoga.YogaMeasureOutput; +import abi49_0_0.com.facebook.yoga.YogaNode; + +/** + * Manages instances of {@code ReactSlider}. + */ +public class ReactSliderManager extends SimpleViewManager { + + private static final SeekBar.OnSeekBarChangeListener ON_CHANGE_LISTENER = + new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) { + ReactSlider slider = (ReactSlider)seekbar; + + if(progress < slider.getLowerLimit()) { + progress = slider.getLowerLimit(); + seekbar.setProgress(progress); + } else if(progress > slider.getUpperLimit()) { + progress = slider.getUpperLimit(); + seekbar.setProgress(progress); + } + + ReactContext reactContext = (ReactContext) seekbar.getContext(); + if(fromUser) { + reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent( + new ReactSliderEvent( + seekbar.getId(), + slider.toRealProgress(progress), true)); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekbar) { + ReactContext reactContext = (ReactContext) seekbar.getContext(); + ((ReactSlider)seekbar).isSliding(true); + reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent( + new ReactSlidingStartEvent( + seekbar.getId(), + ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress()))); + } + + @Override + public void onStopTrackingTouch(SeekBar seekbar) { + ReactContext reactContext = (ReactContext) seekbar.getContext(); + ((ReactSlider)seekbar).isSliding(false); + reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent( + new ReactSlidingCompleteEvent( + seekbar.getId(), + ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress()))); + reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent( + new ReactSliderEvent( + seekbar.getId(), + ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress()), + !((ReactSlider)seekbar).isSliding())); + } + }; + + @Override + public String getName() { + return ReactSliderManagerImpl.REACT_CLASS; + } + + static class ReactSliderShadowNode extends LayoutShadowNode implements + YogaMeasureFunction { + + private int mWidth; + private int mHeight; + private boolean mMeasured; + + private ReactSliderShadowNode() { + initMeasureFunction(); + } + + private void initMeasureFunction() { + setMeasureFunction(this); + } + + @Override + public long measure( + YogaNode node, + float width, + YogaMeasureMode widthMode, + float height, + YogaMeasureMode heightMode) { + if (!mMeasured) { + SeekBar reactSlider = new ReactSlider(getThemedContext(), null); + final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + reactSlider.measure(spec, spec); + mWidth = reactSlider.getMeasuredWidth(); + mHeight = reactSlider.getMeasuredHeight(); + mMeasured = true; + } + + return YogaMeasureOutput.make(mWidth, mHeight); + } + } + + @Override + public LayoutShadowNode createShadowNodeInstance() { + return new ReactSliderShadowNode(); + } + + @Override + public Class getShadowNodeClass() { + return ReactSliderShadowNode.class; + } + + @Override + protected ReactSlider createViewInstance(ThemedReactContext context) { + return ReactSliderManagerImpl.createViewInstance(context); + } + + @ReactProp(name = "disabled", defaultBoolean = false) + public void setDisabled(ReactSlider view, boolean disabled) { + ReactSliderManagerImpl.setDisabled(view, disabled); + } + + @ReactProp(name = "value", defaultFloat = 0f) + public void setValue(ReactSlider view, float value) { + ReactSliderManagerImpl.setValue(view, value); + } + + @ReactProp(name = "minimumValue", defaultFloat = 0f) + public void setMinimumValue(ReactSlider view, float value) { + ReactSliderManagerImpl.setMinimumValue(view, value); + } + + @ReactProp(name = "maximumValue", defaultFloat = 1f) + public void setMaximumValue(ReactSlider view, float value) { + ReactSliderManagerImpl.setMaximumValue(view, value); + } + + @ReactProp(name = "lowerLimit") + public void setLowerLimit(ReactSlider view, float value) { + ReactSliderManagerImpl.setLowerLimit(view, value); + } + + @ReactProp(name = "upperLimit") + public void setUpperLimit(ReactSlider view, float value) { + ReactSliderManagerImpl.setUpperLimit(view, value); + } + + @ReactProp(name = "step", defaultFloat = 0f) + public void setStep(ReactSlider view, float value) { + ReactSliderManagerImpl.setStep(view, value); + } + + @ReactProp(name = "thumbTintColor", customType = "Color") + public void setThumbTintColor(ReactSlider view, Integer color) { + ReactSliderManagerImpl.setThumbTintColor(view, color); + } + + @ReactProp(name = "minimumTrackTintColor", customType = "Color") + public void setMinimumTrackTintColor(ReactSlider view, Integer color) { + ReactSliderManagerImpl.setMinimumTrackTintColor(view, color); + } + + @ReactProp(name = "thumbImage") + public void setThumbImage(ReactSlider view, @Nullable ReadableMap source) { + ReactSliderManagerImpl.setThumbImage(view, source); + } + + @ReactProp(name = "maximumTrackTintColor", customType = "Color") + public void setMaximumTrackTintColor(ReactSlider view, Integer color) { + ReactSliderManagerImpl.setMaximumTrackTintColor(view, color); + } + + @ReactProp(name = "inverted", defaultBoolean = false) + public void setInverted(ReactSlider view, boolean inverted) { + ReactSliderManagerImpl.setInverted(view, inverted); + } + + @ReactProp(name = "accessibilityUnits") + public void setAccessibilityUnits(ReactSlider view, String accessibilityUnits) { + ReactSliderManagerImpl.setAccessibilityUnits(view, accessibilityUnits); + } + + @ReactProp(name = "accessibilityIncrements") + public void setAccessibilityIncrements(ReactSlider view, ReadableArray accessibilityIncrements) { + ReactSliderManagerImpl.setAccessibilityIncrements(view, accessibilityIncrements); + } + + @Override + protected void addEventEmitters(final ThemedReactContext reactContext, final ReactSlider view) { + view.setOnSeekBarChangeListener(ON_CHANGE_LISTENER); + } + + @Override + public Map getExportedCustomDirectEventTypeConstants() { + return ReactSliderManagerImpl.getExportedCustomDirectEventTypeConstants(); + } +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/build.gradle b/android/vendored/sdk49/@shopify/flash-list/android/build.gradle new file mode 100644 index 00000000000000..7b2f73194d8fee --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/build.gradle @@ -0,0 +1,81 @@ +apply plugin: 'com.android.library' + +apply plugin: 'kotlin-android' + +def _ext = rootProject.ext + +def _reactNativeVersion = _ext.has('reactNative') ? _ext.reactNative : '+' +def _compileSdkVersion = _ext.has('compileSdkVersion') ? _ext.compileSdkVersion : 30 +def _buildToolsVersion = _ext.has('buildToolsVersion') ? _ext.buildToolsVersion : '30.0.2' +def _minSdkVersion = _ext.has('minSdkVersion') ? _ext.minSdkVersion : 21 +def _targetSdkVersion = _ext.has('targetSdkVersion') ? _ext.targetSdkVersion : 30 +def _junitVersion = _ext.has('junitVersion') ? _ext.junitVersion : '4.13.2' +def _mockitoVersion = _ext.has('mockitoVersion') ? _ext.mockitoVersion : '3.2.0' +def _androidTestRunnerVersion = _ext.has('androidTestRunnerVersion') ? _ext.androidTestRunnerVersion : '1.1.0' + +buildscript { + // buildscript is evaluated before any other task is executed, so this must be defined here + ext._kotlinVersion = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get('kotlinVersion') : '1.5.30' + + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${_kotlinVersion}") + } +} + +android { + compileSdkVersion _compileSdkVersion + buildToolsVersion _buildToolsVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + debug.java.srcDirs += 'src/debug/kotlin' + test.java.srcDirs += 'src/test/kotlin' + androidTest.java.srcDirs += 'src/androidTest/kotlin' + } + + defaultConfig { + minSdkVersion _minSdkVersion + targetSdkVersion _targetSdkVersion + versionCode 1 + versionName "1.0" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + lintOptions { + abortOnError false + } + + testOptions { + unitTests.returnDefaultValues = true + } +} + +dependencies { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${_kotlinVersion}" + testImplementation "junit:junit:${_junitVersion}" + testImplementation "org.mockito.kotlin:mockito-kotlin:${_mockitoVersion}" + testImplementation "org.mockito:mockito-inline:${_mockitoVersion}" + testImplementation 'com.google.code.gson:gson:2.8.9' + androidTestImplementation("androidx.test:runner:${_androidTestRunnerVersion}") + androidTestImplementation("androidx.test:rules:${_androidTestRunnerVersion}") +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/@shopify/flash-list/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..705d6beeadb6b8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutShadow.kt b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutShadow.kt new file mode 100644 index 00000000000000..58aa7ab422ed4a --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutShadow.kt @@ -0,0 +1,105 @@ +package abi49_0_0.com.shopify.reactnative.flash_list + +class AutoLayoutShadow { + var horizontal: Boolean = false + var scrollOffset: Int = 0 + var offsetFromStart: Int = 0 + var windowSize: Int = 0 + var renderOffset = 0 + + var blankOffsetAtStart = 0 // Tracks blank area from the top + var blankOffsetAtEnd = 0 // Tracks blank area from the bottom + + var lastMaxBoundOverall = 0 // Tracks where the last pixel is drawn in the overall + + private var lastMaxBound = 0 // Tracks where the last pixel is drawn in the visible window + private var lastMinBound = 0 // Tracks where first pixel is drawn in the visible window + + /** Checks for overlaps or gaps between adjacent items and then applies a correction (Only Grid layouts with varying spans) + * Performance: RecyclerListView renders very small number of views and this is not going to trigger multiple layouts on Android side. Not expecting any major perf issue. */ + fun clearGapsAndOverlaps(sortedItems: Array) { + var maxBound = 0 + var minBound = Int.MAX_VALUE + var maxBoundNeighbour = 0 + lastMaxBoundOverall = 0 + for (i in 0 until sortedItems.size - 1) { + val cell = sortedItems[i] + val neighbour = sortedItems[i + 1] + // Only apply correction if the next cell is consecutive. + val isNeighbourConsecutive = neighbour.index == cell.index + 1 + if (isWithinBounds(cell)) { + if (!horizontal) { + maxBound = kotlin.math.max(maxBound, cell.bottom); + minBound = kotlin.math.min(minBound, cell.top); + maxBoundNeighbour = maxBound + if (isNeighbourConsecutive) { + if (cell.left < neighbour.left) { + if (cell.right != neighbour.left) { + neighbour.right = cell.right + neighbour.width + neighbour.left = cell.right + } + if (cell.top != neighbour.top) { + neighbour.bottom = cell.top + neighbour.height + neighbour.top = cell.top + } + } else { + neighbour.bottom = maxBound + neighbour.height + neighbour.top = maxBound + } + } + if (isWithinBounds(neighbour)) { + maxBoundNeighbour = kotlin.math.max(maxBound, neighbour.bottom) + } + } else { + maxBound = kotlin.math.max(maxBound, cell.right); + minBound = kotlin.math.min(minBound, cell.left); + maxBoundNeighbour = maxBound + if (isNeighbourConsecutive) { + if (cell.top < neighbour.top) { + if (cell.bottom != neighbour.top) { + neighbour.bottom = cell.bottom + neighbour.height + neighbour.top = cell.bottom + } + if (cell.left != neighbour.left) { + neighbour.right = cell.left + neighbour.width + neighbour.left = cell.left + } + } else { + neighbour.right = maxBound + neighbour.width + neighbour.left = maxBound + } + } + if (isWithinBounds(neighbour)) { + maxBoundNeighbour = kotlin.math.max(maxBound, neighbour.right) + } + } + } + lastMaxBoundOverall = kotlin.math.max(lastMaxBoundOverall, if (horizontal) cell.right else cell.bottom) + lastMaxBoundOverall = kotlin.math.max(lastMaxBoundOverall, if (horizontal) neighbour.right else neighbour.bottom) + } + lastMaxBound = maxBoundNeighbour + lastMinBound = minBound + } + + /** Offset provided by react can be one frame behind the real one, it's important that this method is called with offset taken directly from + * scrollview object */ + fun computeBlankFromGivenOffset(actualScrollOffset: Int, distanceFromWindowStart: Int, distanceFromWindowEnd: Int): Int { + val actualScrollOffset = actualScrollOffset - offsetFromStart; + blankOffsetAtStart = lastMinBound - actualScrollOffset - distanceFromWindowStart + blankOffsetAtEnd = actualScrollOffset + windowSize - renderOffset - lastMaxBound - distanceFromWindowEnd + return kotlin.math.max(blankOffsetAtStart, blankOffsetAtEnd) + } + + /** It's important to avoid correcting views outside the render window. An item that isn't being recycled might still remain in the view tree. If views outside get considered then gaps between + * unused items will cause algorithm to fail.*/ + private fun isWithinBounds(cell: CellContainer): Boolean { + val scrollOffset = scrollOffset - offsetFromStart; + return if (!horizontal) { + (cell.top >= (scrollOffset - renderOffset) || cell.bottom >= (scrollOffset - renderOffset)) && + (cell.top <= scrollOffset + windowSize || cell.bottom <= scrollOffset + windowSize) + } else { + (cell.left >= (scrollOffset - renderOffset) || cell.right >= (scrollOffset - renderOffset)) && + (cell.left <= scrollOffset + windowSize || cell.right <= scrollOffset + windowSize) + } + } +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutView.kt b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutView.kt new file mode 100644 index 00000000000000..2c768849ebc92c --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutView.kt @@ -0,0 +1,150 @@ +package abi49_0_0.com.shopify.reactnative.flash_list + +import android.content.Context +import android.graphics.Canvas +import android.util.DisplayMetrics +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.widget.HorizontalScrollView +import android.widget.ScrollView +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup + + +/** Container for all RecyclerListView children. This will automatically remove all gaps and overlaps for GridLayouts with flexible spans. + * Note: This cannot work for masonry layouts i.e, pinterest like layout */ +class AutoLayoutView(context: Context) : ReactViewGroup(context) { + val alShadow = AutoLayoutShadow() + var enableInstrumentation = false + var disableAutoLayout = false + + var pixelDensity = 1.0; + + /** Overriding draw instead of onLayout. RecyclerListView uses absolute positions for each and every item which means that changes in child layouts may not trigger onLayout on this container. The same layout + * can still cause views to overlap. Therefore, it makes sense to override draw to do correction. */ + override fun dispatchDraw(canvas: Canvas?) { + fixLayout() + fixFooter() + super.dispatchDraw(canvas) + + val parentScrollView = getParentScrollView() + if (enableInstrumentation && parentScrollView != null) { + /** Since we need to call this method with scrollOffset on the UI thread and not with the one react has we're querying parent's parent + directly which will be a ScrollView. If it isn't reported values will be incorrect but the component will not break. + RecyclerListView is expected not to change the hierarchy of children. */ + + val scrollContainerSize = if (alShadow.horizontal) parentScrollView.width else parentScrollView.height + + val scrollOffset = if (alShadow.horizontal) parentScrollView.scrollX else parentScrollView.scrollY + + val startOffset = if (alShadow.horizontal) left else top + val endOffset = if (alShadow.horizontal) right else bottom + + val distanceFromWindowStart = kotlin.math.max(startOffset - scrollOffset, 0) + val distanceFromWindowEnd = kotlin.math.max(scrollOffset + scrollContainerSize - endOffset, 0) + + alShadow.computeBlankFromGivenOffset(scrollOffset, distanceFromWindowStart, distanceFromWindowEnd) + emitBlankAreaEvent() + } + } + + /** Sorts views by index and then invokes clearGaps which does the correction. + * Performance: Sort is needed. Given relatively low number of views in RecyclerListView render tree this should be a non issue.*/ + private fun fixLayout() { + if (childCount > 1 && !disableAutoLayout) { + val positionSortedViews: Array = Array(childCount) { + val child = getChildAt(it) + if (child is CellContainer) { + child + } else { + throw IllegalStateException("CellRendererComponent outer view should always be CellContainer. Learn more here: https://shopify.github.io/flash-list/docs/usage#cellrenderercomponent.") + } + } + positionSortedViews.sortBy { it.index } + alShadow.offsetFromStart = if (alShadow.horizontal) left else top + alShadow.clearGapsAndOverlaps(positionSortedViews) + } + } + + /** Fixes footer position along with rest of the items */ + private fun fixFooter() { + val parentScrollView = getParentScrollView() + if (disableAutoLayout || parentScrollView == null) { + return + } + val isAutoLayoutEndVisible = if (alShadow.horizontal) right <= parentScrollView.width else bottom <= parentScrollView.height + if (!isAutoLayoutEndVisible) { + return + } + val autoLayoutParent = parent as? View + val footer = getFooter(); + val diff = getFooterDiff() + if (diff == 0 || footer == null || autoLayoutParent == null) { + return + } + + if (alShadow.horizontal) { + footer.offsetLeftAndRight(diff) + right += diff + autoLayoutParent.right += diff + } else { + footer.offsetTopAndBottom(diff) + bottom += diff + autoLayoutParent.bottom += diff + } + } + + private fun getFooterDiff(): Int { + if (childCount == 0) { + alShadow.lastMaxBoundOverall = 0 + } else if (childCount == 1) { + val firstChild = getChildAt(0) + alShadow.lastMaxBoundOverall = if (alShadow.horizontal) { + firstChild.right + } else { + firstChild.bottom + } + } + val autoLayoutEnd = if (alShadow.horizontal) right - left else bottom - top + return alShadow.lastMaxBoundOverall - autoLayoutEnd + } + + private fun getFooter(): View? { + return (parent as? ViewGroup)?.let { + for (i in 0 until it.childCount) { + val view = it.getChildAt(i) + if (view is CellContainer && view.index == -1) { + return@let view + } + } + return@let null + } + } + + private fun getParentScrollView(): View? { + var autoLayoutParent = parent; + while (autoLayoutParent != null) { + if (autoLayoutParent is ScrollView || autoLayoutParent is HorizontalScrollView) { + return autoLayoutParent as View + } + autoLayoutParent = autoLayoutParent.parent; + } + return null + } + + + /** TODO: Check migration to Fabric */ + private fun emitBlankAreaEvent() { + val event: WritableMap = Arguments.createMap() + event.putDouble("offsetStart", alShadow.blankOffsetAtStart / pixelDensity) + event.putDouble("offsetEnd", alShadow.blankOffsetAtEnd / pixelDensity) + val reactContext = context as ReactContext + reactContext + .getJSModule(RCTEventEmitter::class.java) + .receiveEvent(id, "onBlankAreaEvent", event) + } +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutViewManager.kt b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutViewManager.kt new file mode 100644 index 00000000000000..11e7b6d000d4f6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/AutoLayoutViewManager.kt @@ -0,0 +1,69 @@ +package abi49_0_0.com.shopify.reactnative.flash_list + +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup +import abi49_0_0.com.facebook.react.views.view.ReactViewManager +import abi49_0_0.com.facebook.react.common.MapBuilder +import kotlin.math.roundToInt + +/** ViewManager for AutoLayoutView - Container for all RecyclerListView children. Automatically removes all gaps and overlaps for GridLayouts with flexible spans. + * Note: This cannot work for masonry layouts i.e, pinterest like layout */ +@ReactModule(name = AutoLayoutViewManager.REACT_CLASS) +class AutoLayoutViewManager: ReactViewManager() { + + companion object { + const val REACT_CLASS = "AutoLayoutView" + } + + override fun getName(): String { + return REACT_CLASS + } + + override fun createViewInstance(context: ThemedReactContext): ReactViewGroup { + return AutoLayoutView(context).also { it.pixelDensity = context.resources.displayMetrics.density.toDouble() } + } + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap { + return MapBuilder.builder().put( + "onBlankAreaEvent", + MapBuilder.of( + "registrationName", "onBlankAreaEvent") + ).build(); + } + + @ReactProp(name = "horizontal") + fun setHorizontal(view: AutoLayoutView, isHorizontal: Boolean) { + view.alShadow.horizontal = isHorizontal + } + + @ReactProp(name = "disableAutoLayout") + fun setDisableAutoLayout(view: AutoLayoutView, disableAutoLayout: Boolean) { + view.disableAutoLayout = disableAutoLayout + } + + @ReactProp(name = "scrollOffset") + fun setScrollOffset(view: AutoLayoutView, scrollOffset: Double) { + view.alShadow.scrollOffset = convertToPixelLayout(scrollOffset, view.pixelDensity) + } + + @ReactProp(name = "windowSize") + fun setWindowSize(view: AutoLayoutView, windowSize: Double) { + view.alShadow.windowSize = convertToPixelLayout(windowSize, view.pixelDensity) + } + + @ReactProp(name = "renderAheadOffset") + fun setRenderAheadOffset(view: AutoLayoutView, renderOffset: Double) { + view.alShadow.renderOffset = convertToPixelLayout(renderOffset, view.pixelDensity) + } + + @ReactProp(name = "enableInstrumentation") + fun setEnableInstrumentation(view: AutoLayoutView, enableInstrumentation: Boolean) { + view.enableInstrumentation = enableInstrumentation + } + + private fun convertToPixelLayout(dp: Double, density: Double): Int { + return (dp * density).roundToInt() + } +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainer.java b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainer.java new file mode 100644 index 00000000000000..19cb0a046575bd --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainer.java @@ -0,0 +1,16 @@ +package abi49_0_0.com.shopify.reactnative.flash_list; + +public interface CellContainer { + void setIndex(int value); + int getIndex(); + void setLeft(int value); + int getLeft(); + void setTop(int value); + int getTop(); + void setRight(int value); + int getRight(); + void setBottom(int value); + int getBottom(); + int getHeight(); + int getWidth(); +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainerImpl.kt b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainerImpl.kt new file mode 100644 index 00000000000000..a7feabeb9093cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainerImpl.kt @@ -0,0 +1,16 @@ +package abi49_0_0.com.shopify.reactnative.flash_list + +import android.content.Context +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup + +class CellContainerImpl(context: Context) : ReactViewGroup(context), CellContainer { + private var index = -1 + override fun setIndex(value: Int) { + index = value + } + + override fun getIndex(): Int { + return index + } + +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainerManager.kt b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainerManager.kt new file mode 100644 index 00000000000000..863a3c57b43613 --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/CellContainerManager.kt @@ -0,0 +1,27 @@ +package abi49_0_0.com.shopify.reactnative.flash_list + +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup +import abi49_0_0.com.facebook.react.views.view.ReactViewManager + +@ReactModule(name = AutoLayoutViewManager.REACT_CLASS) +class CellContainerManager: ReactViewManager() { + companion object { + const val REACT_CLASS = "CellContainer" + } + + override fun getName(): String { + return REACT_CLASS + } + + override fun createViewInstance(context: ThemedReactContext): ReactViewGroup { + return CellContainerImpl(context) + } + + @ReactProp(name = "index") + fun setIndex(view: CellContainerImpl, index: Int) { + view.index = index + } +} diff --git a/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/FlashListPackage.kt b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/FlashListPackage.kt new file mode 100644 index 00000000000000..bd43ff71230985 --- /dev/null +++ b/android/vendored/sdk49/@shopify/flash-list/android/src/main/kotlin/abi49_0_0/com/shopify/reactnative/flash_list/FlashListPackage.kt @@ -0,0 +1,19 @@ +package abi49_0_0.com.shopify.reactnative.flash_list + +import abi49_0_0.com.facebook.react.ReactPackage +import abi49_0_0.com.facebook.react.bridge.NativeModule +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.uimanager.ViewManager + +class ReactNativeFlashListPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return listOf() + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf( + AutoLayoutViewManager(), + CellContainerManager() + ) + } +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/CMakeLists.txt b/android/vendored/sdk49/@shopify/react-native-skia/android/CMakeLists.txt new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/build.gradle b/android/vendored/sdk49/@shopify/react-native-skia/android/build.gradle new file mode 100644 index 00000000000000..0f14a6e9a1885f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/build.gradle @@ -0,0 +1,299 @@ +import java.nio.file.Paths + +// android/build.gradle + +// based on: +// +// * https://github.com/facebook/versioned-react-native/packages/react-native/blob/0.60-stable/template/android/build.gradle +// previous location: +// - https://github.com/facebook/versioned-react-native/packages/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle +// +// * https://github.com/facebook/versioned-react-native/packages/react-native/blob/0.60-stable/template/android/app/build.gradle +// previous location: +// - https://github.com/facebook/versioned-react-native/packages/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle + +// FBJNI build is based on: +// https://github.com/facebookincubator/fbjni/blob/main/docs/android_setup.md + +// These defaults should reflect the SDK versions used by +// the minimum React Native version supported. +def DEFAULT_COMPILE_SDK_VERSION = 28 +def DEFAULT_BUILD_TOOLS_VERSION = '28.0.3' +def DEFAULT_MIN_SDK_VERSION = 16 +def DEFAULT_TARGET_SDK_VERSION = 28 + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +apply plugin: 'com.android.library' + +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +static def findNodeModules(baseDir) { + def basePath = baseDir.toPath().normalize() + // Node's module resolution algorithm searches up to the root directory, + // after which the base path will be null + while (basePath) { + def nodeModulesPath = Paths.get(basePath.toString(), "node_modules") + def reactNativePath = Paths.get(nodeModulesPath.toString(), "react-native") + if (nodeModulesPath.toFile().exists() && reactNativePath.toFile().exists()) { + return nodeModulesPath.toString() + } + basePath = basePath.getParent() + } + throw new GradleException("React-Native-Skia: Failed to find node_modules/ path!") +} + +def nodeModules = Paths.get(projectDir.getPath(), '../../../../..').toString() +logger.warn("react-native-skia: node_modules/ found at: ${nodeModules}") + +def sourceBuild = false +def defaultDir + +if (rootProject.ext.has('reactNativeAndroidRoot')) { + defaultDir = rootProject.ext.get('reactNativeAndroidRoot') +} else if (findProject(':packages:react-native:ReactAndroid') != null) { + sourceBuild = false + defaultDir = project(':packages:react-native:ReactAndroid').projectDir +} else { + defaultDir = file("$nodeModules/react-native") +} + +if (!defaultDir.exists()) { + throw new GradleException( + "${project.name}: React Native android directory (node_modules/versioned-react-native/packages/react-native/android) does not exist! Resolved node_modules to: ${nodeModules}" + ) +} + +def prebuiltDir = sourceBuild + ? "$nodeModules/versioned-react-native/packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib" + : "$buildDir/react-native-0*/jni" + + +def buildType = "debug" +if (gradle.startParameter.taskRequests.args[0].toString().contains("Release")) { + buildType = "release" +} else if (gradle.startParameter.taskRequests.args[0].toString().contains("Debug")) { + buildType = "debug" +} + +def reactProperties = new Properties() +file("$defaultDir/gradle.properties").withInputStream { reactProperties.load(it) } +def FULL_RN_VERSION = (System.getenv("REACT_NATIVE_OVERRIDE_VERSION") ?: reactProperties.getProperty("VERSION_NAME")) +def REACT_NATIVE_VERSION = FULL_RN_VERSION.split("\\.")[1].toInteger() +def ENABLE_PREFAB = REACT_NATIVE_VERSION > 68 + +logger.warn("react-native-skia: RN Version: ${REACT_NATIVE_VERSION} / ${FULL_RN_VERSION}") +logger.warn("react-native-skia: isSourceBuild: ${sourceBuild}") +logger.warn("react-native-skia: PrebuiltDir: ${prebuiltDir}") +logger.warn("react-native-skia: buildType: ${buildType}") +logger.warn("react-native-skia: buildDir: ${buildDir}") +logger.warn("react-native-skia: node_modules: ${nodeModules}") +logger.warn("react-native-skia: Enable Prefab: ${ENABLE_PREFAB}") + +buildscript { + // The Android Gradle plugin is only required when opening the android folder stand-alone. + // This avoids unnecessary downloads and potential conflicts when the library is included as a + // module dependency in an application project. + // ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies + if (project == rootProject) { + repositories { + google() + } + dependencies { + // This should reflect the Gradle plugin version used by + // the minimum React Native version supported. + classpath 'com.android.tools.build:gradle:3.4.1' + } + } +} + +android { + compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) + buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) + targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) + versionCode 1 + versionName "1.0" + + externalNativeBuild { + cmake { + cppFlags "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID" + abiFilters (*reactNativeArchitectures()) + arguments '-DANDROID_STL=c++_shared', + "-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}", + "-DNODE_MODULES_DIR=${nodeModules}", + "-DPREBUILT_DIR=${prebuiltDir}" + + } + } + } + lintOptions { + abortOnError false + } + + externalNativeBuild { + cmake { + path file('CMakeLists.txt') + } + } + + packagingOptions { + excludes = [ + "**/libc++_shared.so", + "**/libfbjni.so", + "**/libjsi.so", + "**/libreact_nativemodule_core.so", + "**/libturbomodulejsijni.so", + "META-INF/**" + ] + } + + if (ENABLE_PREFAB) { + buildFeatures { + prefab true + prefabPublishing true + } + prefab { + rnskia_abi49_0_0 { + headers "${project.buildDir}/headers/rnskia/" + } + } + } + + // Create new configurations that can be referred to in dependencies. + // The Android Gradle Plugin 3.* does not allow hooking into existing + // configurations like `implementation`. + configurations { + extractHeaders + extractJNI + } +} + +repositories { + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url("$rootDir/../node_modules/versioned-react-native/packages/react-native/android") + } + maven { + // Android JSC is installed from npm + url("$rootDir/../node_modules/jsc-android/dist") + } + mavenCentral { + // We don't want to fetch react-native from Maven Central as there are + // older versions over there. + content { + excludeGroup "com.facebook.react" + } + } + google() + maven { url 'https://www.jitpack.io' } +} + +dependencies { + //noinspection GradleDynamicVersion + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + // From node_modules + + if (REACT_NATIVE_VERSION < 71) { + logger.warn("react-native-skia: Extracting files from AAR (pre RN 0.71)") + //noinspection GradleDynamicVersion + extractHeaders("com.facebook.fbjni:fbjni:0.2.2:headers") + //noinspection GradleDynamicVersion + extractJNI("com.facebook.fbjni:fbjni:0.2.2") + } + + if (!sourceBuild) { + def rnAarMatcher = "**/versioned-react-native/packages/react-native/**/*${buildType}.aar" + if (REACT_NATIVE_VERSION < 69) { + logger.warn("react-native-skia: aar state pre 69. match **/**/*.aar") + rnAarMatcher = "**/**/*.aar" + } else if (REACT_NATIVE_VERSION >= 71) { + logger.warn("react-native-skia: aar state post 70, do nothing") + return + } + def rnAAR = fileTree("${nodeModules}/versioned-react-native/packages/react-native/android").matching({ it.include rnAarMatcher }).singleFile + logger.warn("react-native-skia: Extracting JNI files (pre RN 0.71) ${rnAAR}") + extractJNI(files(rnAAR)) + } +} + +task extractAARHeaders { + doLast { + configurations.extractHeaders.files.each { + def file = it.absoluteFile + copy { + from zipTree(file) + into "$buildDir/$file.name" + include "**/*.h" + } + } + } +} + +task extractJNIFiles { + doLast { + configurations.extractJNI.files.each { + def file = it.absoluteFile + copy { + from zipTree(file) + into "$buildDir/$file.name" + include "jni/**/*" + } + } + } +} + +extractJNIFiles.mustRunAfter extractAARHeaders + +if (ENABLE_PREFAB) { + // Package all the cpp code in a flattened directory structure + task prepareHeaders(type: Copy) { + from("./cpp") + into "${project.buildDir}/headers/rnskia/" + includeEmptyDirs = false + include "**/*.h" + duplicatesStrategy = 'include' + eachFile { + String path = it.path + + // Skip flattening third_party dir + if (path.contains("api/third_party")) { + path = path.substring("api/".length()) + } else { + // flatten anything else + path = path.substring(path.lastIndexOf("/") + 1) + } + it.path = path + } + } + preBuild.dependsOn(prepareHeaders) +} + +def nativeBuildDependsOn(dependsOnTask, variant) { + def buildTasks = tasks.findAll({ task -> + !task.name.contains("Clean") && (task.name.contains("externalNative") || task.name.contains("CMake")) }) + if (variant != null) { + buildTasks = buildTasks.findAll({ task -> task.name.contains(variant) }) + } + buildTasks.forEach { task -> task.dependsOn(dependsOnTask) } +} + +afterEvaluate { + nativeBuildDependsOn(extractAARHeaders, null) + nativeBuildDependsOn(extractJNIFiles, null) +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniLoad.cpp b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniLoad.cpp new file mode 100644 index 00000000000000..0ac2c33690a43d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniLoad.cpp @@ -0,0 +1,17 @@ +#include "JniPlatformContext.h" +#include "JniSkiaDomView.h" +#include "JniSkiaDrawView.h" +#include "JniSkiaManager.h" +#include "JniSkiaPictureView.h" +#include +#include + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::jni::initialize(vm, [] { + RNSkia::JniSkiaManager::registerNatives(); + RNSkia::JniSkiaDrawView::registerNatives(); + RNSkia::JniSkiaPictureView::registerNatives(); + RNSkia::JniSkiaDomView::registerNatives(); + RNSkia::JniPlatformContext::registerNatives(); + }); +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniPlatformContext.cpp b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniPlatformContext.cpp new file mode 100644 index 00000000000000..07e3786e87c262 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniPlatformContext.cpp @@ -0,0 +1,219 @@ +#include "JniPlatformContext.h" + +#include +#include +#include + +#include "SkData.h" +#include "SkRefCnt.h" +#include "SkStream.h" +#include "SkTypes.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBitmap.h" +#include "SkPixmap.h" + +#pragma clang diagnostic pop + +static SkAlphaType alpha_type(int32_t flags) { + switch ((flags >> ANDROID_BITMAP_FLAGS_ALPHA_SHIFT) & + ANDROID_BITMAP_FLAGS_ALPHA_MASK) { + case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE: + return kOpaque_SkAlphaType; + case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL: + return kPremul_SkAlphaType; + case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: + return kUnpremul_SkAlphaType; + default: + break; + } + + return kUnknown_SkAlphaType; +} + +static SkColorType color_type(int32_t format) { + switch (format) { + case ANDROID_BITMAP_FORMAT_RGBA_8888: + return kRGBA_8888_SkColorType; + case ANDROID_BITMAP_FORMAT_RGB_565: + return kRGB_565_SkColorType; + case ANDROID_BITMAP_FORMAT_RGBA_4444: + return kARGB_4444_SkColorType; + case ANDROID_BITMAP_FORMAT_RGBA_F16: + return kRGBA_F16_SkColorType; + case ANDROID_BITMAP_FORMAT_A_8: + return kAlpha_8_SkColorType; + default: + break; + } + + return kUnknown_SkColorType; +} + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +using TSelf = jni::local_ref; + +void JniPlatformContext::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JniPlatformContext::initHybrid), + makeNativeMethod("notifyDrawLoop", + JniPlatformContext::notifyDrawLoopExternal), + makeNativeMethod("notifyTaskReady", + JniPlatformContext::notifyTaskReadyExternal), + }); +} + +TSelf JniPlatformContext::initHybrid(jni::alias_ref jThis, + float pixelDensity) { + return makeCxxInstance(jThis, pixelDensity); +} + +sk_sp JniPlatformContext::takeScreenshotFromViewTag(size_t tag) { + // Call the java method for creating a view screenshot as a bitmap: + auto env = jni::Environment::current(); + static auto method = javaPart_->getClass()->getMethod( + "takeScreenshotFromViewTag"); + + auto bitmap = method(javaPart_.get(), tag).release(); + + // Let's convert to a native bitmap and get some info about the bitmap + AndroidBitmapInfo bmi; + AndroidBitmap_getInfo(env, bitmap, &bmi); + + // Convert android bitmap info to a Skia bitmap info + auto colorType = color_type(bmi.format); + auto alphaType = alpha_type(bmi.flags); + + auto skInfo = SkImageInfo::Make(SkISize::Make(bmi.width, bmi.height), + colorType, alphaType); + + // Lock pixels + void *pixels; + AndroidBitmap_lockPixels(env, bitmap, &pixels); + + // Create pixmap from pixels and make a copy of it so that + // the SkImage owns its own pixels + SkPixmap pm(skInfo, pixels, bmi.stride); + auto skImage = SkImages::RasterFromPixmapCopy(pm); + + // Unlock pixels + AndroidBitmap_unlockPixels(env, bitmap); + + // Return our newly created SkImage! + return skImage; +} + +void JniPlatformContext::startDrawLoop() { + jni::ThreadScope ts; + // Start drawing loop + static auto method = + javaPart_->getClass()->getMethod("beginDrawLoop"); + method(javaPart_.get()); +} + +void JniPlatformContext::stopDrawLoop() { + jni::ThreadScope ts; + // Stop drawing loop + static auto method = + javaPart_->getClass()->getMethod("endDrawLoop"); + method(javaPart_.get()); +} + +void JniPlatformContext::notifyDrawLoopExternal() { + jni::ThreadScope ts; + _onNotifyDrawLoop(); +} + +void JniPlatformContext::runTaskOnMainThread(std::function task) { + _taskMutex->lock(); + _taskCallbacks.push(task); + _taskMutex->unlock(); + + // Notify Java that task is ready + static auto method = javaPart_->getClass()->getMethod( + "notifyTaskReadyOnMainThread"); + method(javaPart_.get()); +} + +void JniPlatformContext::notifyTaskReadyExternal() { + jni::ThreadScope ts; + _taskMutex->lock(); + auto task = _taskCallbacks.front(); + if (task != nullptr) { + _taskCallbacks.pop(); + _taskMutex->unlock(); + task(); + } else { + _taskMutex->unlock(); + } +} + +void JniPlatformContext::performStreamOperation( + const std::string &sourceUri, + const std::function)> &op) { + static auto method = javaPart_->getClass()->getMethod( + "getJniStreamFromSource"); + + auto loader = [=]() -> void { + jni::ThreadScope ts; + jstring jstr = + (*jni::Environment::current()).NewStringUTF(sourceUri.c_str()); + + // Get the array with data from input stream from Java + auto array = method(javaPart_.get(), jstr); + + if (array == nullptr) { + printf("Calling getJniStreamFromSource failed\n"); + return; + } + + // Allocate buffer for java byte array + jsize num_bytes = jni::Environment::current()->GetArrayLength(array.get()); + char *buffer = reinterpret_cast(malloc(num_bytes + 1)); + + if (!buffer) { + printf("Buff Fail\n"); + return; + } + + jbyte *elements = + jni::Environment::current()->GetByteArrayElements(array.get(), nullptr); + if (!elements) { + printf("Element Fail\n"); + return; + } + + // Copy data from java array to buffer + memcpy(buffer, elements, num_bytes); + buffer[num_bytes] = 0; + + jni::Environment::current()->ReleaseByteArrayElements(array.get(), elements, + JNI_ABORT); + + // Copy malloced data and give ownership to SkData + auto data = SkData::MakeFromMalloc(buffer, num_bytes); + auto skStream = SkMemoryStream::Make(data); + + // Perform operation + op(std::move(skStream)); + }; + + // Fire and forget the thread - will be resolved on completion + std::thread(loader).detach(); +} + +void JniPlatformContext::raiseError(const std::exception &err) { + jni::ThreadScope ts; + static auto method = + javaPart_->getClass()->getMethod("raise"); + method(javaPart_.get(), std::string(err.what())); +} + +} // namespace RNSkia \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniSkiaManager.cpp b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniSkiaManager.cpp new file mode 100644 index 00000000000000..07968ac55d4f71 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/JniSkiaManager.cpp @@ -0,0 +1,42 @@ +#include "JniSkiaManager.h" + +#include +#include +#include +#include + +#include "JniSkiaDrawView.h" +#include + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +// JNI binding +void JniSkiaManager::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JniSkiaManager::initHybrid), + makeNativeMethod("initializeRuntime", JniSkiaManager::initializeRuntime), + makeNativeMethod("invalidate", JniSkiaManager::invalidate), + }); +} + +// JNI init +jni::local_ref::jhybriddata> +JniSkiaManager::initHybrid(jni::alias_ref jThis, jlong jsContext, + JSCallInvokerHolder jsCallInvokerHolder, + JavaPlatformContext skiaContext) { + + // cast from JNI hybrid objects to C++ instances + return makeCxxInstance(jThis, reinterpret_cast(jsContext), + jsCallInvokerHolder->cthis()->getCallInvoker(), + skiaContext->cthis()); +} + +void JniSkiaManager::initializeRuntime() { + // Create the cross platform skia manager + _skManager = + std::make_shared(_jsRuntime, _jsCallInvoker, _context); +} + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniPlatformContext.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniPlatformContext.h new file mode 100644 index 00000000000000..80ba8bb80870cc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniPlatformContext.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "RNSkPlatformContext.h" + +class SkStreamAsset; +namespace RNSkia { + +namespace jsi = facebook::jsi; +namespace jni = facebook::jni; + +using JSCallInvokerHolder = + jni::alias_ref; + +class JniPlatformContext : public jni::HybridClass { +public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/shopify/reactnative/skia/PlatformContext;"; + + static jni::local_ref + initHybrid(jni::alias_ref jThis, const float); + + static void registerNatives(); + + void performStreamOperation( + const std::string &sourceUri, + const std::function)> &op); + + void raiseError(const std::exception &err); + + void startDrawLoop(); + void stopDrawLoop(); + + void notifyDrawLoopExternal(); + + void notifyTaskReadyExternal(); + + void runTaskOnMainThread(std::function task); + + float getPixelDensity() { return _pixelDensity; } + + sk_sp takeScreenshotFromViewTag(size_t tag); + + void setOnNotifyDrawLoop(const std::function &callback) { + _onNotifyDrawLoop = callback; + } + +private: + friend HybridBase; + jni::global_ref javaPart_; + + float _pixelDensity; + + std::function _onNotifyDrawLoop; + + std::queue> _taskCallbacks; + + std::shared_ptr _taskMutex; + + explicit JniPlatformContext( + jni::alias_ref jThis, + const float pixelDensity) + : _taskMutex(std::make_shared()), + javaPart_(jni::make_global(jThis)), _pixelDensity(pixelDensity) {} +}; +} // namespace RNSkia \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaBaseView.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaBaseView.h new file mode 100644 index 00000000000000..cc2ae3176ff9e1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaBaseView.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JniSkiaBaseView { +public: + JniSkiaBaseView(jni::alias_ref skiaManager, + std::shared_ptr skiaView) + : _manager(skiaManager->cthis()), _skiaView(skiaView) {} + + ~JniSkiaBaseView() {} + + std::shared_ptr getSkiaManager() { + return _manager->getSkiaManager(); + } + +protected: + virtual void updateTouchPoints(jni::JArrayDouble touches) { + _skiaView->updateTouchPoints(touches); + } + + virtual void surfaceAvailable(jobject surface, int width, int height) { + _skiaView->surfaceAvailable(surface, width, height); + } + + virtual void surfaceSizeChanged(int width, int height) { + _skiaView->surfaceSizeChanged(width, height); + } + + virtual void surfaceDestroyed() { _skiaView->surfaceDestroyed(); } + + virtual void setMode(std::string mode) { _skiaView->setMode(mode); } + + virtual void setDebugMode(bool show) { _skiaView->setShowDebugInfo(show); } + + virtual void registerView(int nativeId) { + getSkiaManager()->registerSkiaView(nativeId, _skiaView->getSkiaView()); + } + + virtual void unregisterView() { + getSkiaManager()->setSkiaView(_skiaView->getSkiaView()->getNativeId(), + nullptr); + getSkiaManager()->unregisterSkiaView( + _skiaView->getSkiaView()->getNativeId()); + _skiaView->viewDidUnmount(); + } + +private: + JniSkiaManager *_manager; + std::shared_ptr _skiaView; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaDomView.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaDomView.h new file mode 100644 index 00000000000000..ad6bd6523fe11a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaDomView.h @@ -0,0 +1,89 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace RNSkia { + +namespace jsi = facebook::jsi; +namespace jni = facebook::jni; + +class JniSkiaDomView : public jni::HybridClass, + public JniSkiaBaseView { +public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/shopify/reactnative/skia/SkiaDomView;"; + + static jni::local_ref + initHybrid(jni::alias_ref jThis, + jni::alias_ref skiaManager) { + return makeCxxInstance(jThis, skiaManager); + } + + static void registerNatives() { + registerHybrid( + {makeNativeMethod("initHybrid", JniSkiaDomView::initHybrid), + makeNativeMethod("surfaceAvailable", JniSkiaDomView::surfaceAvailable), + makeNativeMethod("surfaceDestroyed", JniSkiaDomView::surfaceDestroyed), + makeNativeMethod("surfaceSizeChanged", + JniSkiaDomView::surfaceSizeChanged), + makeNativeMethod("setMode", JniSkiaDomView::setMode), + makeNativeMethod("setDebugMode", JniSkiaDomView::setDebugMode), + makeNativeMethod("updateTouchPoints", + JniSkiaDomView::updateTouchPoints), + makeNativeMethod("registerView", JniSkiaDomView::registerView), + makeNativeMethod("unregisterView", JniSkiaDomView::unregisterView)}); + } + +protected: + void updateTouchPoints(jni::JArrayDouble touches) override { + JniSkiaBaseView::updateTouchPoints(touches); + } + + void surfaceAvailable(jobject surface, int width, int height) override { + JniSkiaBaseView::surfaceAvailable(surface, width, height); + } + + void surfaceSizeChanged(int width, int height) override { + JniSkiaBaseView::surfaceSizeChanged(width, height); + } + + void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); } + + void setMode(std::string mode) override { JniSkiaBaseView::setMode(mode); } + + void setDebugMode(bool show) override { JniSkiaBaseView::setDebugMode(show); } + + void registerView(int nativeId) override { + JniSkiaBaseView::registerView(nativeId); + } + + void unregisterView() override { JniSkiaBaseView::unregisterView(); } + +private: + friend HybridBase; + + explicit JniSkiaDomView( + jni::alias_ref jThis, + jni::alias_ref skiaManager) + : JniSkiaBaseView(skiaManager, + std::make_shared>( + skiaManager->cthis()->getPlatformContext())) {} + + jni::global_ref javaPart_; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaDrawView.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaDrawView.h new file mode 100644 index 00000000000000..d3a9102ad7a567 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaDrawView.h @@ -0,0 +1,90 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; +namespace jni = facebook::jni; + +class JniSkiaDrawView : public jni::HybridClass, + public JniSkiaBaseView { +public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/shopify/reactnative/skia/SkiaDrawView;"; + + static jni::local_ref + initHybrid(jni::alias_ref jThis, + jni::alias_ref skiaManager) { + return makeCxxInstance(jThis, skiaManager); + } + + static void registerNatives() { + registerHybrid( + {makeNativeMethod("initHybrid", JniSkiaDrawView::initHybrid), + makeNativeMethod("surfaceAvailable", + JniSkiaDrawView::surfaceAvailable), + makeNativeMethod("surfaceDestroyed", + JniSkiaDrawView::surfaceDestroyed), + makeNativeMethod("surfaceSizeChanged", + JniSkiaDrawView::surfaceSizeChanged), + makeNativeMethod("setMode", JniSkiaDrawView::setMode), + makeNativeMethod("setDebugMode", JniSkiaDrawView::setDebugMode), + makeNativeMethod("updateTouchPoints", + JniSkiaDrawView::updateTouchPoints), + makeNativeMethod("registerView", JniSkiaDrawView::registerView), + makeNativeMethod("unregisterView", JniSkiaDrawView::unregisterView)}); + } + +protected: + void updateTouchPoints(jni::JArrayDouble touches) override { + JniSkiaBaseView::updateTouchPoints(touches); + } + + void surfaceAvailable(jobject surface, int width, int height) override { + JniSkiaBaseView::surfaceAvailable(surface, width, height); + } + + void surfaceSizeChanged(int width, int height) override { + JniSkiaBaseView::surfaceSizeChanged(width, height); + } + + void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); } + + void setMode(std::string mode) override { JniSkiaBaseView::setMode(mode); } + + void setDebugMode(bool show) override { JniSkiaBaseView::setDebugMode(show); } + + void registerView(int nativeId) override { + JniSkiaBaseView::registerView(nativeId); + } + + void unregisterView() override { JniSkiaBaseView::unregisterView(); } + +private: + friend HybridBase; + + explicit JniSkiaDrawView( + jni::alias_ref jThis, + jni::alias_ref skiaManager) + : JniSkiaBaseView(skiaManager, + std::make_shared>( + skiaManager->cthis()->getPlatformContext())) {} + + jni::global_ref javaPart_; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaManager.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaManager.h new file mode 100644 index 00000000000000..a9d019acc10287 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaManager.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace RNSkia { + +class RNSkManager; + +namespace jsi = facebook::jsi; + +using JSCallInvokerHolder = + jni::alias_ref; + +using JavaPlatformContext = jni::alias_ref; + +class JniSkiaManager : public jni::HybridClass { +public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/shopify/reactnative/skia/SkiaManager;"; + static auto constexpr TAG = "ReactNativeSkia"; + + static jni::local_ref::jhybriddata> + initHybrid(jni::alias_ref jThis, jlong jsContext, + JSCallInvokerHolder jsCallInvokerHolder, + JavaPlatformContext platformContext); + + static void registerNatives(); + + JniSkiaManager() {} + ~JniSkiaManager() { RNSkLogger::logToConsole("JniSkiaManager dtor"); } + + explicit JniSkiaManager( + jni::alias_ref jThis, + jsi::Runtime *runtime, + std::shared_ptr jsCallInvoker, + JniPlatformContext *platformContext) + : _javaPart(jni::make_global(jThis)), _jsRuntime(runtime), + _jsCallInvoker(jsCallInvoker), + _context(std::make_shared( + platformContext, runtime, jsCallInvoker)) {} + + std::shared_ptr getPlatformContext() { + return _context; + } + std::shared_ptr getSkiaManager() { return _skManager; } + + void invalidate() { + _context->stopDrawLoop(); + _context->notifyDrawLoop(true); + _skManager = nullptr; + _context = nullptr; + } + +private: + friend HybridBase; + + std::shared_ptr _skManager; + + jni::global_ref _javaPart; + + jsi::Runtime *_jsRuntime; + std::shared_ptr _jsCallInvoker; + std::shared_ptr _context; + + void initializeRuntime(); +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaPictureView.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaPictureView.h new file mode 100644 index 00000000000000..949241056f16b3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/jni/include/JniSkiaPictureView.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; +namespace jni = facebook::jni; + +class JniSkiaPictureView : public jni::HybridClass, + public JniSkiaBaseView { +public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/shopify/reactnative/skia/SkiaPictureView;"; + + static jni::local_ref + initHybrid(jni::alias_ref jThis, + jni::alias_ref skiaManager) { + return makeCxxInstance(jThis, skiaManager); + } + + static void registerNatives() { + registerHybrid( + {makeNativeMethod("initHybrid", JniSkiaPictureView::initHybrid), + makeNativeMethod("surfaceAvailable", + JniSkiaPictureView::surfaceAvailable), + makeNativeMethod("surfaceDestroyed", + JniSkiaPictureView::surfaceDestroyed), + makeNativeMethod("surfaceSizeChanged", + JniSkiaPictureView::surfaceSizeChanged), + makeNativeMethod("setMode", JniSkiaPictureView::setMode), + makeNativeMethod("setDebugMode", JniSkiaPictureView::setDebugMode), + makeNativeMethod("updateTouchPoints", + JniSkiaPictureView::updateTouchPoints), + makeNativeMethod("registerView", JniSkiaPictureView::registerView), + makeNativeMethod("unregisterView", + JniSkiaPictureView::unregisterView)}); + } + +protected: + void updateTouchPoints(jni::JArrayDouble touches) override { + JniSkiaBaseView::updateTouchPoints(touches); + } + + void surfaceAvailable(jobject surface, int width, int height) override { + JniSkiaBaseView::surfaceAvailable(surface, width, height); + } + + void surfaceSizeChanged(int width, int height) override { + JniSkiaBaseView::surfaceSizeChanged(width, height); + } + + void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); } + + void setMode(std::string mode) override { JniSkiaBaseView::setMode(mode); } + + void setDebugMode(bool show) override { JniSkiaBaseView::setDebugMode(show); } + + void registerView(int nativeId) override { + JniSkiaBaseView::registerView(nativeId); + } + + void unregisterView() override { JniSkiaBaseView::unregisterView(); } + +private: + friend HybridBase; + + explicit JniSkiaPictureView( + jni::alias_ref jThis, + jni::alias_ref skiaManager) + : JniSkiaBaseView( + skiaManager, + std::make_shared>( + skiaManager->cthis()->getPlatformContext())) {} + + jni::global_ref javaPart_; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h new file mode 100644 index 00000000000000..2a85adb54c3b8d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; + +class RNSkAndroidPlatformContext : public RNSkPlatformContext { +public: + RNSkAndroidPlatformContext( + JniPlatformContext *jniPlatformContext, jsi::Runtime *runtime, + std::shared_ptr jsCallInvoker) + : RNSkPlatformContext(runtime, jsCallInvoker, + jniPlatformContext->getPixelDensity()), + _jniPlatformContext(jniPlatformContext) { + // Hook onto the notify draw loop callback in the platform context + jniPlatformContext->setOnNotifyDrawLoop( + [this]() { notifyDrawLoop(false); }); + } + + ~RNSkAndroidPlatformContext() { stopDrawLoop(); } + + void performStreamOperation( + const std::string &sourceUri, + const std::function)> &op) override { + _jniPlatformContext->performStreamOperation(sourceUri, op); + } + + void raiseError(const std::exception &err) override { + _jniPlatformContext->raiseError(err); + } + + sk_sp makeOffscreenSurface(int width, int height) override { + return MakeOffscreenGLSurface(width, height); + } + + void runOnMainThread(std::function task) override { + _jniPlatformContext->runTaskOnMainThread(task); + } + + sk_sp takeScreenshotFromViewTag(size_t tag) override { + return _jniPlatformContext->takeScreenshotFromViewTag(tag); + } + + void startDrawLoop() override { _jniPlatformContext->startDrawLoop(); } + + void stopDrawLoop() override { _jniPlatformContext->stopDrawLoop(); } + +private: + JniPlatformContext *_jniPlatformContext; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkAndroidView.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkAndroidView.h new file mode 100644 index 00000000000000..3ee87baecad6e3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkAndroidView.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace RNSkia { + +class RNSkBaseAndroidView { +public: + virtual void surfaceAvailable(jobject surface, int width, int height) = 0; + + virtual void surfaceDestroyed() = 0; + + virtual void surfaceSizeChanged(int width, int height) = 0; + + virtual float getPixelDensity() = 0; + + virtual void updateTouchPoints(jni::JArrayDouble touches) = 0; + + virtual void setMode(std::string mode) = 0; + + virtual void setShowDebugInfo(bool show) = 0; + + virtual void viewDidUnmount() = 0; + + virtual std::shared_ptr getSkiaView() = 0; +}; + +template +class RNSkAndroidView : public T, public RNSkBaseAndroidView { +public: + explicit RNSkAndroidView(std::shared_ptr context) + : T(context, + std::make_shared( + std::bind(&RNSkia::RNSkView::requestRedraw, this), context)) {} + + void surfaceAvailable(jobject surface, int width, int height) override { + std::static_pointer_cast(T::getCanvasProvider()) + ->surfaceAvailable(surface, width, height); + + // Try to render directly when the surface has been set so that + // we don't have to wait until the draw loop returns. + RNSkView::renderImmediate(); + } + + void surfaceDestroyed() override { + std::static_pointer_cast(T::getCanvasProvider()) + ->surfaceDestroyed(); + } + + void surfaceSizeChanged(int width, int height) override { + std::static_pointer_cast(T::getCanvasProvider()) + ->surfaceSizeChanged(width, height); + } + + float getPixelDensity() override { + return T::getPlatformContext()->getPixelDensity(); + } + + void setMode(std::string mode) override { + if (mode.compare("continuous") == 0) { + T::setDrawingMode(RNSkDrawingMode::Continuous); + } else { + T::setDrawingMode(RNSkDrawingMode::Default); + } + } + + void setShowDebugInfo(bool show) override { T::setShowDebugOverlays(show); } + + void viewDidUnmount() override { T::endDrawingLoop(); } + + void updateTouchPoints(jni::JArrayDouble touches) override { + // Create touch points + std::vector points; + auto pin = touches.pin(); + auto scale = getPixelDensity(); + points.reserve(pin.size() / 5); + for (size_t i = 0; i < pin.size(); i += 5) { + RNSkTouchInfo point; + point.x = pin[i] / scale; + point.y = pin[i + 1] / scale; + point.force = pin[i + 2]; + point.type = (RNSkia::RNSkTouchInfo::TouchType)pin[i + 3]; + point.id = pin[i + 4]; + points.push_back(point); + } + T::updateTouchState(points); + } + + std::shared_ptr getSkiaView() override { + return T::shared_from_this(); + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp new file mode 100644 index 00000000000000..5764b75b8c97c9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp @@ -0,0 +1,89 @@ +#include + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCanvas.h" +#include "SkSurface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +RNSkOpenGLCanvasProvider::RNSkOpenGLCanvasProvider( + std::function requestRedraw, + std::shared_ptr context) + : RNSkCanvasProvider(requestRedraw), _context(context) {} + +RNSkOpenGLCanvasProvider::~RNSkOpenGLCanvasProvider() {} + +float RNSkOpenGLCanvasProvider::getScaledWidth() { return _width; } + +float RNSkOpenGLCanvasProvider::getScaledHeight() { return _height; } + +bool RNSkOpenGLCanvasProvider::renderToCanvas( + const std::function &cb) { + if (_renderer != nullptr) { + return _renderer->run(cb, _width, _height); + } + return false; +} + +void RNSkOpenGLCanvasProvider::surfaceAvailable(jobject surface, int width, + int height) { + _width = width; + _height = height; + + if (_renderer == nullptr) { + // Create renderer! + _renderer = std::make_unique(surface); + + // Redraw + _requestRedraw(); + } +} +void RNSkOpenGLCanvasProvider::surfaceDestroyed() { + if (_renderer != nullptr) { + // teardown + _renderer->teardown(); + + // Teardown renderer on the render thread since OpenGL demands + // same thread access for OpenGL contexts. + std::condition_variable cv; + std::mutex m; + std::unique_lock lock(m); + + _context->runOnRenderThread([&cv, &m, weakSelf = weak_from_this()]() { + // Lock + std::unique_lock lock(m); + + auto self = weakSelf.lock(); + if (self) { + if (self->_renderer != nullptr) { + self->_renderer->run(nullptr, 0, 0); + } + // Remove renderer + self->_renderer = nullptr; + } + cv.notify_one(); + }); + + cv.wait(lock); + } +} + +void RNSkOpenGLCanvasProvider::surfaceSizeChanged(int width, int height) { + if (width == 0 && height == 0) { + // Setting width/height to zero is nothing we need to care about when + // it comes to invalidating the surface. + return; + } + _width = width; + _height = height; + + // Redraw after size change + _requestRedraw(); +} +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h new file mode 100644 index 00000000000000..f340b4e18ea013 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include + +#include + +#include "SkiaOpenGLRenderer.h" +#include + +namespace RNSkia { + +class RNSkOpenGLCanvasProvider + : public RNSkia::RNSkCanvasProvider, + public std::enable_shared_from_this { +public: + RNSkOpenGLCanvasProvider( + std::function requestRedraw, + std::shared_ptr context); + + ~RNSkOpenGLCanvasProvider(); + + float getScaledWidth() override; + + float getScaledHeight() override; + + bool renderToCanvas(const std::function &cb) override; + + void surfaceAvailable(jobject surface, int width, int height); + + void surfaceDestroyed(); + + void surfaceSizeChanged(int width, int height); + +private: + std::unique_ptr _renderer = nullptr; + std::shared_ptr _context; + float _width = -1; + float _height = -1; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp new file mode 100644 index 00000000000000..353d4a4fedcca9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp @@ -0,0 +1,345 @@ +#include "SkiaOpenGLRenderer.h" + +#include +#include +#include + +#define STENCIL_BUFFER_SIZE 8 + +namespace RNSkia { +/** Static members */ +sk_sp MakeOffscreenGLSurface(int width, int height) { + EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == EGL_NO_DISPLAY) { + RNSkLogger::logToConsole("eglGetdisplay failed : %i", glGetError()); + return nullptr; + } + + EGLint major; + EGLint minor; + if (!eglInitialize(eglDisplay, &major, &minor)) { + RNSkLogger::logToConsole("eglInitialize failed : %i", glGetError()); + return nullptr; + } + + EGLint att[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_ALPHA_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_RED_SIZE, + 8, + EGL_DEPTH_SIZE, + 0, + EGL_STENCIL_SIZE, + 0, + EGL_NONE}; + + EGLint numConfigs; + EGLConfig eglConfig; + eglConfig = 0; + if (!eglChooseConfig(eglDisplay, att, &eglConfig, 1, &numConfigs) || + numConfigs == 0) { + RNSkLogger::logToConsole("Failed to choose a config %d\n", eglGetError()); + return nullptr; + } + + EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + + EGLContext eglContext = + eglCreateContext(eglDisplay, eglConfig, NULL, contextAttribs); + + if (eglContext == EGL_NO_CONTEXT) { + RNSkLogger::logToConsole("eglCreateContext failed: %d\n", eglGetError()); + return nullptr; + } + + const EGLint offScreenSurfaceAttribs[] = {EGL_WIDTH, width, EGL_HEIGHT, + height, EGL_NONE}; + EGLSurface eglSurface = + eglCreatePbufferSurface(eglDisplay, eglConfig, offScreenSurfaceAttribs); + if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { + RNSkLogger::logToConsole("eglMakeCurrent failed: %d\n", eglGetError()); + return nullptr; + } + GLint buffer; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buffer); + + GLint stencil; + glGetIntegerv(GL_STENCIL_BITS, &stencil); + + GLint samples; + glGetIntegerv(GL_SAMPLES, &samples); + + // Create the Skia backend context + auto backendInterface = GrGLMakeNativeInterface(); + auto grContext = GrDirectContext::MakeGL(backendInterface); + if (grContext == nullptr) { + RNSkLogger::logToConsole("GrDirectContext::MakeGL failed"); + return nullptr; + } + auto maxSamples = + grContext->maxSurfaceSampleCountForColorType(kRGBA_8888_SkColorType); + + if (samples > maxSamples) + samples = maxSamples; + + GrGLFramebufferInfo fbInfo; + fbInfo.fFBOID = buffer; + fbInfo.fFormat = 0x8058; + + auto renderTarget = + GrBackendRenderTarget(width, height, samples, stencil, fbInfo); + + struct OffscreenRenderContext { + EGLDisplay display; + EGLSurface surface; + }; + auto ctx = new OffscreenRenderContext({eglDisplay, eglSurface}); + + auto surface = SkSurface::MakeFromBackendRenderTarget( + grContext.get(), renderTarget, kBottomLeft_GrSurfaceOrigin, + kRGBA_8888_SkColorType, nullptr, nullptr, + [](void *addr) { + auto ctx = reinterpret_cast(addr); + eglDestroySurface(ctx->display, ctx->surface); + delete ctx; + }, + reinterpret_cast(ctx)); + return surface; +} + +std::shared_ptr +SkiaOpenGLRenderer::getThreadDrawingContext() { + auto threadId = std::this_thread::get_id(); + if (threadContexts.count(threadId) == 0) { + auto drawingContext = std::make_shared(); + drawingContext->glContext = EGL_NO_CONTEXT; + drawingContext->glDisplay = EGL_NO_DISPLAY; + drawingContext->glConfig = 0; + drawingContext->skContext = nullptr; + threadContexts.emplace(threadId, drawingContext); + } + return threadContexts.at(threadId); +} + +SkiaOpenGLRenderer::SkiaOpenGLRenderer(jobject surface) { + _nativeWindow = + ANativeWindow_fromSurface(facebook::jni::Environment::current(), surface); +} + +SkiaOpenGLRenderer::~SkiaOpenGLRenderer() { + // Release surface + ANativeWindow_release(_nativeWindow); + _nativeWindow = nullptr; +} + +bool SkiaOpenGLRenderer::run(const std::function &cb, + int width, int height) { + switch (_renderState) { + case RenderState::Initializing: { + _renderState = RenderState::Rendering; + // Just let the case drop to drawing - we have initialized + // and we should be able to render (if the picture is set) + } + case RenderState::Rendering: { + // Make sure to initialize the rendering pipeline + if (!ensureInitialised()) { + return false; + } + + if (cb != nullptr) { + // RNSkLogger::logToConsole("SKIARENDER - Render begin"); + + getThreadDrawingContext()->skContext->resetContext(); + + SkColorType colorType; + // setup surface for fbo0 + GrGLFramebufferInfo fboInfo; + fboInfo.fFBOID = 0; + fboInfo.fFormat = 0x8058; + colorType = kN32_SkColorType; + + GrBackendRenderTarget backendRT(width, height, 0, STENCIL_BUFFER_SIZE, + fboInfo); + + SkSurfaceProps props(0, kUnknown_SkPixelGeometry); + + sk_sp renderTarget(SkSurface::MakeFromBackendRenderTarget( + getThreadDrawingContext()->skContext.get(), backendRT, + kBottomLeft_GrSurfaceOrigin, colorType, nullptr, &props)); + + auto canvas = renderTarget->getCanvas(); + + // Draw picture into surface + cb(canvas); + + // Flush + canvas->flush(); + + if (!eglSwapBuffers(getThreadDrawingContext()->glDisplay, _glSurface)) { + RNSkLogger::logToConsole("eglSwapBuffers failed: %d\n", eglGetError()); + return false; + } + + // RNSkLogger::logToConsole("SKIARENDER - render done"); + return true; + } + + return false; + } + case RenderState::Finishing: { + _renderState = RenderState::Done; + + // Release GL surface + if (_glSurface != EGL_NO_SURFACE && + getThreadDrawingContext()->glDisplay != EGL_NO_DISPLAY) { + eglDestroySurface(getThreadDrawingContext()->glDisplay, _glSurface); + _glSurface = EGL_NO_SURFACE; + } + + return true; + } + case RenderState::Done: { + // Do nothing. We're done. + return true; + } + } +} + +bool SkiaOpenGLRenderer::ensureInitialised() { + // Set up static OpenGL context + if (!initStaticGLContext()) { + return false; + } + + // Set up OpenGL Surface + if (!initGLSurface()) { + return false; + } + + // Init skia static context + if (!initStaticSkiaContext()) { + return false; + } + + return true; +} + +void SkiaOpenGLRenderer::teardown() { _renderState = RenderState::Finishing; } + +bool SkiaOpenGLRenderer::initStaticGLContext() { + if (getThreadDrawingContext()->glContext != EGL_NO_CONTEXT) { + return true; + } + + getThreadDrawingContext()->glDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (getThreadDrawingContext()->glDisplay == EGL_NO_DISPLAY) { + RNSkLogger::logToConsole("eglGetdisplay failed : %i", glGetError()); + return false; + } + + EGLint major; + EGLint minor; + if (!eglInitialize(getThreadDrawingContext()->glDisplay, &major, &minor)) { + RNSkLogger::logToConsole("eglInitialize failed : %i", glGetError()); + return false; + } + + EGLint att[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT, + EGL_ALPHA_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_RED_SIZE, + 8, + EGL_DEPTH_SIZE, + 0, + EGL_STENCIL_SIZE, + 0, + EGL_NONE}; + + EGLint numConfigs; + getThreadDrawingContext()->glConfig = 0; + if (!eglChooseConfig(getThreadDrawingContext()->glDisplay, att, + &getThreadDrawingContext()->glConfig, 1, &numConfigs) || + numConfigs == 0) { + RNSkLogger::logToConsole("Failed to choose a config %d\n", eglGetError()); + return false; + } + + EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + + getThreadDrawingContext()->glContext = eglCreateContext( + getThreadDrawingContext()->glDisplay, getThreadDrawingContext()->glConfig, + NULL, contextAttribs); + + if (getThreadDrawingContext()->glContext == EGL_NO_CONTEXT) { + RNSkLogger::logToConsole("eglCreateContext failed: %d\n", eglGetError()); + return false; + } + + return true; +} + +bool SkiaOpenGLRenderer::initStaticSkiaContext() { + if (getThreadDrawingContext()->skContext != nullptr) { + return true; + } + + // Create the Skia backend context + auto backendInterface = GrGLMakeNativeInterface(); + getThreadDrawingContext()->skContext = + GrDirectContext::MakeGL(backendInterface); + if (getThreadDrawingContext()->skContext == nullptr) { + RNSkLogger::logToConsole("GrDirectContext::MakeGL failed"); + return false; + } + + return true; +} + +bool SkiaOpenGLRenderer::initGLSurface() { + if (_nativeWindow == nullptr) { + return false; + } + + if (_glSurface != EGL_NO_SURFACE) { + if (!eglMakeCurrent(getThreadDrawingContext()->glDisplay, _glSurface, + _glSurface, getThreadDrawingContext()->glContext)) { + RNSkLogger::logToConsole("eglMakeCurrent failed: %d\n", eglGetError()); + return false; + } + return true; + } + + // Create the opengl surface + _glSurface = eglCreateWindowSurface(getThreadDrawingContext()->glDisplay, + getThreadDrawingContext()->glConfig, + _nativeWindow, nullptr); + + if (_glSurface == EGL_NO_SURFACE) { + RNSkLogger::logToConsole("eglCreateWindowSurface failed: %d\n", + eglGetError()); + return false; + } + + if (!eglMakeCurrent(getThreadDrawingContext()->glDisplay, _glSurface, + _glSurface, getThreadDrawingContext()->glContext)) { + RNSkLogger::logToConsole("eglMakeCurrent failed: %d\n", eglGetError()); + return false; + } + + return true; +} +} // namespace RNSkia \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/SkiaOpenGLRenderer.h b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/SkiaOpenGLRenderer.h new file mode 100644 index 00000000000000..9b6330cfcdeb64 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/cpp/rnskia-android/SkiaOpenGLRenderer.h @@ -0,0 +1,121 @@ +#pragma once + +#include + +#include "EGL/egl.h" +#include "GLES2/gl2.h" +#include "android/native_window.h" +#include +#include + +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCanvas.h" +#include "SkColorSpace.h" +#include "SkPicture.h" +#include "SkSurface.h" +#include "include/gpu/GrDirectContext.h" +#include "include/gpu/gl/GrGLInterface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { +sk_sp MakeOffscreenGLSurface(int width, int height); + +using OpenGLDrawingContext = struct { + EGLContext glContext; + EGLDisplay glDisplay; + EGLConfig glConfig; + sk_sp skContext; +}; + +static std::unordered_map> + threadContexts; + +enum RenderState : int { + Initializing, + Rendering, + Finishing, + Done, +}; + +class SkiaOpenGLRenderer { +public: + explicit SkiaOpenGLRenderer(jobject surface); + ~SkiaOpenGLRenderer(); + + /** + * Initializes, renders and tears down the render pipeline depending on the + * state of the renderer. All OpenGL/Skia context operations are done on a + * separate thread which must be the same for all calls to the render method. + * + * @param callback Render callback + * @param width Width of surface to render if there is a picture + * @param height Height of surface to render if there is a picture + */ + bool run(const std::function &cb, int width, int height); + + /** + * Sets the state to finishing. Next time the renderer will be called it + * will tear down and release its resources. It is important that this + * is done on the same thread as the other OpenGL context stuff is handled. + * + * Teardown can be called fom whatever thread we want - but we must ensure + * that at least one call to render on the render thread is done after calling + * teardown. + */ + void teardown(); + +private: + /** + * Initializes all required OpenGL and Skia objects + * @return True if initialization went well. + */ + bool ensureInitialised(); + + /** + * Initializes the static OpenGL context that is shared between + * all instances of the renderer. + * @return True if initialization went well + */ + bool initStaticGLContext(); + + /** + * Initializes the static Skia context that is shared between + * all instances of the renderer + * @return True if initialization went well + */ + bool initStaticSkiaContext(); + + /** + * Inititalizes the OpenGL surface from the native view pointer we + * got on initialization. Each renderer has its own OpenGL surface to + * render on. + * @return True if initialization went well + */ + bool initGLSurface(); + + /** + * To be able to use static contexts (and avoid reloading the skia context for + * each new view, we track the OpenGL and Skia drawing context per thread. + * @return The drawing context for the current thread + */ + static std::shared_ptr getThreadDrawingContext(); + + EGLSurface _glSurface = EGL_NO_SURFACE; + + ANativeWindow *_nativeWindow = nullptr; + + int _prevWidth = 0; + int _prevHeight = 0; + + std::atomic _renderState = {RenderState::Initializing}; +}; +} // namespace RNSkia \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..8045cd14f7c323 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/PlatformContext.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/PlatformContext.java new file mode 100644 index 00000000000000..dfd6817de2f545 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/PlatformContext.java @@ -0,0 +1,191 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import android.app.Application; +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.Choreographer; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.turbomodule.core.CallInvokerHolderImpl; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class PlatformContext { + @DoNotStrip + private final HybridData mHybridData; + + private final ReactContext mContext; + + private boolean _drawLoopActive = false; + private boolean _isPaused = false; + + private final String TAG = "PlatformContext"; + + public PlatformContext(ReactContext reactContext) { + mContext = reactContext; + mHybridData = initHybrid(reactContext.getResources().getDisplayMetrics().density); + } + + private byte[] getStreamAsBytes(InputStream is) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[4 * 0x400]; + while ((nRead = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + return buffer.toByteArray(); + } + + private void postFrameLoop() { + Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + if (_isPaused) { + return; + } + notifyDrawLoop(); + if (_drawLoopActive) { + postFrameLoop(); + } + } + }; + Choreographer.getInstance().postFrameCallback(frameCallback); + } + + @DoNotStrip + public void notifyTaskReadyOnMainThread() { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + notifyTaskReady(); + } + }); + } + + @DoNotStrip + Object takeScreenshotFromViewTag(int tag) { + return ViewScreenshotService.makeViewScreenshotFromTag(mContext, tag); + } + + @DoNotStrip + public void raise(final String message) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + mContext.handleException(new Exception(message)); + } + }); + } + + @DoNotStrip + public void beginDrawLoop() { + if (_drawLoopActive) { + return; + } + _drawLoopActive = true; + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + postFrameLoop(); + } + }); + } + + @DoNotStrip + public void endDrawLoop() { + if (_drawLoopActive) { + _drawLoopActive = false; + } + } + + @DoNotStrip + public byte[] getJniStreamFromSource(String sourceUri) throws IOException { + // First try loading the input as a resource directly + int resourceId = mContext.getResources().getIdentifier(sourceUri, "drawable", mContext.getPackageName()); + + // Test to see if we have a raw resource (for SVG) + if (resourceId == 0) { + resourceId = mContext.getResources().getIdentifier(sourceUri, "raw", mContext.getPackageName()); + } + + if (resourceId != 0) { + // We can just return the input stream directly + return getStreamAsBytes(mContext.getResources().openRawResource(resourceId)); + } + + // We should try to open a connection and return a stream to download this + // object + URI uri = null; + try { + uri = new URI(sourceUri); + + String scheme = uri.getScheme(); + + if (scheme == null) + throw new Exception("Invalid URI scheme"); + + // TODO: Base64?? + + URL url = uri.toURL(); + URLConnection connection = url.openConnection(); + connection.connect(); + + BufferedInputStream b = new BufferedInputStream(url.openStream(), 8192); + return getStreamAsBytes(b); + + } catch (URISyntaxException e) { + e.printStackTrace(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + void onPause() { + Log.i(TAG, "Paused"); + _isPaused = true; + } + + void onResume() { + _isPaused = false; + Log.i(TAG, "Resume"); + if(_drawLoopActive) { + // Restart draw loop + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + postFrameLoop(); + } + }); + } + } + + @Override + protected void finalize() throws Throwable { + mHybridData.resetNative(); + super.finalize(); + } + + // Private c++ native methods + private native HybridData initHybrid(float pixelDensity); + private native void notifyDrawLoop(); + private native void notifyTaskReady(); +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/RNSkiaModule.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/RNSkiaModule.java new file mode 100644 index 00000000000000..4cc8f70c61d08e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/RNSkiaModule.java @@ -0,0 +1,88 @@ +// RnskiaModule.java + +package abi49_0_0.com.shopify.reactnative.skia; + +import android.util.Log; + +import abi49_0_0.com.facebook.react.bridge.LifecycleEventListener; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; + +import java.lang.ref.WeakReference; + +@ReactModule(name="RNSkia") +public class RNSkiaModule extends ReactContextBaseJavaModule implements LifecycleEventListener { + public static final String NAME = "RNSkia"; + + private final WeakReference weakReactContext; + private SkiaManager skiaManager; + + public RNSkiaModule(ReactApplicationContext reactContext) { + super(reactContext); + this.weakReactContext = new WeakReference<>(reactContext); + reactContext.addLifecycleEventListener(this); + } + + @Override + public void invalidate() { + super.invalidate(); + + if (getReactApplicationContext() != null) { + getReactApplicationContext().removeLifecycleEventListener(this); + } + + if (this.skiaManager != null) { + this.skiaManager.invalidate(); + this.skiaManager.destroy(); + this.skiaManager = null; + } + } + + @Override + public String getName() { + return NAME; + } + + public SkiaManager getSkiaManager() { + return skiaManager; + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public boolean install() { + if (skiaManager != null) { + // Already initialized, ignore call. + return true; + } + + try { + System.loadLibrary("rnskia_abi49_0_0"); + ReactApplicationContext context = weakReactContext.get(); + if (context == null) { + Log.e(NAME, "React Application Context was null!"); + return false; + } + skiaManager = new SkiaManager(context); + return true; + } catch (Exception exception) { + Log.e(NAME, "Failed to initialize Skia Manager!", exception); + return false; + } + } + + @Override + public void onHostResume() { + if(skiaManager != null) skiaManager.onHostResume(); + } + + @Override + public void onHostPause() { + if(skiaManager != null) skiaManager.onHostPause(); + } + + @Override + public void onHostDestroy() { + + } +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/RNSkiaPackage.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/RNSkiaPackage.java new file mode 100644 index 00000000000000..d1ce8482bd8a89 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/RNSkiaPackage.java @@ -0,0 +1,24 @@ +// RnskiaPackage.java + +package abi49_0_0.com.shopify.reactnative.skia; + +import java.util.Arrays; +import java.util.List; + +import abi49_0_0.com.facebook.react.ReactPackage; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; + +public class RNSkiaPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new RNSkiaModule(reactContext)); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Arrays.asList(new SkiaDrawViewManager(), + new SkiaPictureViewManager(), new SkiaDomViewManager()); + } +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaBaseView.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaBaseView.java new file mode 100644 index 00000000000000..eb3136bcff1ed4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaBaseView.java @@ -0,0 +1,149 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import android.content.Context; +import android.graphics.SurfaceTexture; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.TextureView; + +import com.facebook.jni.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.uimanager.PointerEvents; +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup; + +public abstract class SkiaBaseView extends ReactViewGroup implements TextureView.SurfaceTextureListener { + + @DoNotStrip + private Surface mSurface; + private TextureView mTexture; + + public SkiaBaseView(Context context) { + super(context); + mTexture = new TextureView(context); + mTexture.setSurfaceTextureListener(this); + mTexture.setOpaque(false); + addView(mTexture); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + mTexture.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight()); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + // https://developer.android.com/training/gestures/multi + int action = ev.getActionMasked(); + + MotionEvent.PointerCoords r = new MotionEvent.PointerCoords(); + + double[] points; + + // If this is a pointer_up/down event we need to handle it a bit specialized + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_POINTER_UP: { + points = new double[5]; + int pointerIndex = ev.getActionIndex(); + ev.getPointerCoords(pointerIndex, r); + points[0] = r.x; + points[1] = r.y; + points[2] = ev.getPressure(pointerIndex); + points[3] = motionActionToType(action); + points[4] = ev.getPointerId(pointerIndex); + + updateTouchPoints(points); + + break; + } + default: { + // For the rest we can just handle it like expected + int count = ev.getPointerCount(); + int pointerIndex = 0; + points = new double[5 * count]; + for (int i = 0; i < count; i++) { + ev.getPointerCoords(i, r); + points[pointerIndex++] = r.x; + points[pointerIndex++] = r.y; + points[pointerIndex++] = ev.getPressure(i); + points[pointerIndex++] = motionActionToType(action); + points[pointerIndex++] = ev.getPointerId(i); + } + + updateTouchPoints(points); + + break; + } + } + + return true; + } + + private static int motionActionToType(int action) { + int actionType = 3; + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + actionType = 0; + break; + case MotionEvent.ACTION_MOVE: + actionType = 1; + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + actionType = 2; + break; + case MotionEvent.ACTION_CANCEL: + actionType = 3; + break; + } + return actionType; + } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + mSurface = new Surface(surface); + surfaceAvailable(mSurface, width, height); + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + surfaceSizeChanged(width, height); + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + // Notify the native side + surfaceDestroyed(); + // https://developer.android.com/reference/android/view/TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed(android.graphics.SurfaceTexture) + // Invoked when the specified SurfaceTexture is about to be destroyed. If returns true, + // no rendering should happen inside the surface texture after this method is invoked. + // We've measured this and it seems like we need to call release and return true - and + // then handle the issue with this being ripped out underneath the native layer in the C++ + // code. + mSurface.release(); + // Return true - we promise that no more rendering will be done now. + return true; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + // Nothing special to do here + } + + protected abstract void surfaceAvailable(Object surface, int width, int height); + + protected abstract void surfaceSizeChanged(int width, int height); + + protected abstract void surfaceDestroyed(); + + protected abstract void setMode(String mode); + + protected abstract void setDebugMode(boolean show); + + protected abstract void updateTouchPoints(double[] points); + + protected abstract void registerView(int nativeId); + + protected abstract void unregisterView(); +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaBaseViewManager.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaBaseViewManager.java new file mode 100644 index 00000000000000..166c68cf4957ee --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaBaseViewManager.java @@ -0,0 +1,34 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup; +import abi49_0_0.com.facebook.react.views.view.ReactViewManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public abstract class SkiaBaseViewManager extends ReactViewManager { + + @Override + public void setNativeId(@NonNull ReactViewGroup view, @Nullable String nativeId) { + super.setNativeId(view, nativeId); + int nativeIdResolved = Integer.parseInt(nativeId); + ((SkiaBaseView)view).registerView(nativeIdResolved); + } + + @ReactProp(name = "mode") + public void setMode(ReactViewGroup view, String mode) { + ((SkiaBaseView)view).setMode(mode); + } + + @ReactProp(name = "debug") + public void setDebug(ReactViewGroup view, boolean show) { + ((SkiaBaseView)view).setDebugMode(show); + } + + @Override + public void onDropViewInstance(@NonNull ReactViewGroup view) { + super.onDropViewInstance(view); + ((SkiaBaseView)view).unregisterView(); + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDomView.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDomView.java new file mode 100644 index 00000000000000..42ec7313e965c5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDomView.java @@ -0,0 +1,45 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import android.content.Context; + +import com.facebook.jni.HybridData; +import com.facebook.jni.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +public class SkiaDomView extends SkiaBaseView { + @DoNotStrip + private HybridData mHybridData; + + public SkiaDomView(Context context) { + super(context); + RNSkiaModule skiaModule = ((ReactContext) context).getNativeModule(RNSkiaModule.class); + mHybridData = initHybrid(skiaModule.getSkiaManager()); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + mHybridData.resetNative(); + } + + private native HybridData initHybrid(SkiaManager skiaManager); + + protected native void surfaceAvailable(Object surface, int width, int height); + + protected native void surfaceSizeChanged(int width, int height); + + protected native void surfaceDestroyed(); + + protected native void setBgColor(int color); + + protected native void setMode(String mode); + + protected native void setDebugMode(boolean show); + + protected native void updateTouchPoints(double[] points); + + protected native void registerView(int nativeId); + + protected native void unregisterView(); + +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDomViewManager.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDomViewManager.java new file mode 100644 index 00000000000000..8be6ce90dbb473 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDomViewManager.java @@ -0,0 +1,19 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import androidx.annotation.NonNull; + +public class SkiaDomViewManager extends SkiaBaseViewManager { + + @NonNull + @Override + public String getName() { + return "SkiaDomView"; + } + + @NonNull + @Override + public SkiaDomView createViewInstance(@NonNull ThemedReactContext reactContext) { + return new SkiaDomView(reactContext); + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDrawView.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDrawView.java new file mode 100644 index 00000000000000..e62b42476ba85d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDrawView.java @@ -0,0 +1,45 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import android.content.Context; + +import com.facebook.jni.HybridData; +import com.facebook.jni.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +public class SkiaDrawView extends SkiaBaseView { + @DoNotStrip + private HybridData mHybridData; + + public SkiaDrawView(Context context) { + super(context); + RNSkiaModule skiaModule = ((ReactContext) context).getNativeModule(RNSkiaModule.class); + mHybridData = initHybrid(skiaModule.getSkiaManager()); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + mHybridData.resetNative(); + } + + private native HybridData initHybrid(SkiaManager skiaManager); + + protected native void surfaceAvailable(Object surface, int width, int height); + + protected native void surfaceSizeChanged(int width, int height); + + protected native void surfaceDestroyed(); + + protected native void setBgColor(int color); + + protected native void setMode(String mode); + + protected native void setDebugMode(boolean show); + + protected native void updateTouchPoints(double[] points); + + protected native void registerView(int nativeId); + + protected native void unregisterView(); + +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDrawViewManager.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDrawViewManager.java new file mode 100644 index 00000000000000..9b973ab2ae1c56 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaDrawViewManager.java @@ -0,0 +1,19 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import androidx.annotation.NonNull; + +public class SkiaDrawViewManager extends SkiaBaseViewManager { + + @NonNull + @Override + public String getName() { + return "SkiaDrawView"; + } + + @NonNull + @Override + public SkiaDrawView createViewInstance(@NonNull ThemedReactContext reactContext) { + return new SkiaDrawView(reactContext); + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaManager.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaManager.java new file mode 100644 index 00000000000000..7e293eaaf93a11 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaManager.java @@ -0,0 +1,57 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.turbomodule.core.CallInvokerHolderImpl; + +@DoNotStrip +public class SkiaManager { + + @DoNotStrip + private HybridData mHybridData; + + @DoNotStrip + private ReactContext mContext; + + @DoNotStrip + private PlatformContext mPlatformContext; + + @DoNotStrip + SkiaManager(ReactContext context) { + super(); + mContext = context; + + CallInvokerHolderImpl holder = (CallInvokerHolderImpl) context.getCatalystInstance().getJSCallInvokerHolder(); + + mPlatformContext = new PlatformContext(context); + + mHybridData = initHybrid(context.getJavaScriptContextHolder().get(), holder, mPlatformContext); + + initializeRuntime(); + } + + public void destroy() { + mHybridData.resetNative(); + } + + public float getPixelDensity() { + return mContext.getResources().getDisplayMetrics().density; + } + + public PlatformContext getPlatformContext() { + return mPlatformContext; + } + + public void onHostResume() { mPlatformContext.onResume(); } + + public void onHostPause() { mPlatformContext.onPause(); } + + // private C++ functions + private native HybridData initHybrid(long jsContext, CallInvokerHolderImpl jsCallInvokerHolder, + PlatformContext platformContext); + + private native void initializeRuntime(); + public native void invalidate(); + +} \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaPictureView.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaPictureView.java new file mode 100644 index 00000000000000..1731dd526f72be --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaPictureView.java @@ -0,0 +1,45 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import android.content.Context; + +import com.facebook.jni.HybridData; +import com.facebook.jni.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +public class SkiaPictureView extends SkiaBaseView { + @DoNotStrip + private HybridData mHybridData; + + public SkiaPictureView(Context context) { + super(context); + RNSkiaModule skiaModule = ((ReactContext) context).getNativeModule(RNSkiaModule.class); + mHybridData = initHybrid(skiaModule.getSkiaManager()); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + mHybridData.resetNative(); + } + + private native HybridData initHybrid(SkiaManager skiaManager); + + protected native void surfaceAvailable(Object surface, int width, int height); + + protected native void surfaceSizeChanged(int width, int height); + + protected native void surfaceDestroyed(); + + protected native void setBgColor(int color); + + protected native void setMode(String mode); + + protected native void setDebugMode(boolean show); + + protected native void updateTouchPoints(double[] points); + + protected native void registerView(int nativeId); + + protected native void unregisterView(); + +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaPictureViewManager.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaPictureViewManager.java new file mode 100644 index 00000000000000..ac335a17a90cf9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/SkiaPictureViewManager.java @@ -0,0 +1,19 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import androidx.annotation.NonNull; + +public class SkiaPictureViewManager extends SkiaBaseViewManager { + + @NonNull + @Override + public String getName() { + return "SkiaPictureView"; + } + + @NonNull + @Override + public SkiaPictureView createViewInstance(@NonNull ThemedReactContext reactContext) { + return new SkiaPictureView(reactContext); + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/ViewScreenshotService.java b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/ViewScreenshotService.java new file mode 100644 index 00000000000000..872b980d85c5b7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/java/abi49_0_0/com/shopify/reactnative/skia/ViewScreenshotService.java @@ -0,0 +1,181 @@ +package abi49_0_0.com.shopify.reactnative.skia; + +import static android.view.View.VISIBLE; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.PixelCopy; +import android.view.SurfaceView; +import android.view.TextureView; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; + +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + + +public class ViewScreenshotService { + private static final long SURFACE_VIEW_READ_PIXELS_TIMEOUT = 5; + private static final String TAG = "SkiaScreenshot"; + + public static Bitmap makeViewScreenshotFromTag(ReactContext context, int tag) { + UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); + View view = uiManager.resolveView(tag); + if (view == null) { + throw new RuntimeException("Could not resolve view from view tag " + tag); + } + + // Measure and get size of view + int width = view.getWidth(); + int height = view.getHeight(); + + if (width <= 0 || height <= 0) { + return null; + } + + // The following code is taken from react-native-view-shot to be able to handle and + // correctly render all kinds of views, also including TextureViews and SurfaceViews + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + + final Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setFilterBitmap(true); + paint.setDither(true); + + // Render the main view and its children + final Canvas canvas = new Canvas(bitmap); + + // Renders view with child views to canvas + renderViewToCanvas(canvas, view, paint); + + return bitmap; + } + + private static void renderViewToCanvas(Canvas canvas, View view, Paint paint) { + // Apply transformations for the current view + canvas.save(); + applyTransformations(canvas, view); + + // Draw children if the view has children + if ((view instanceof ViewGroup)) { + // Draw children + ViewGroup group = (ViewGroup) view; + + // Hide visible children - this needs to be done because view.draw(canvas) + // will render all visible non-texture/surface views directly - causing + // views to be rendered twice - once by view.draw() and once when we + // enumerate children. We therefore need to turn off rendering of visible + // children before we call view.draw: + List visibleChildren = new ArrayList<>(); + for (int i = 0; i < group.getChildCount(); i++) { + View child = group.getChildAt(i); + if (child.getVisibility() == VISIBLE) { + visibleChildren.add(child); + child.setVisibility(View.INVISIBLE); + } + } + + // Draw ourselves + view.draw(canvas); + + // Enable children again + for (int i = 0; i < visibleChildren.size(); i++) { + View child = visibleChildren.get(i); + child.setVisibility(VISIBLE); + } + + // Draw children + for (int i = 0; i < group.getChildCount(); i++) { + View child = group.getChildAt(i); + + // skip all invisible to user child views + if (child.getVisibility() != VISIBLE) continue; + + // skip any child that we don't know how to process + if (child instanceof TextureView) { + final TextureView tvChild = (TextureView) child; + tvChild.setOpaque(false); // <-- switch off background fill + + canvas.save(); + applyTransformations(canvas, child); + + // TextureView should use bitmaps with matching size, + // otherwise content of the TextureView will be scaled to provided bitmap dimensions + final Bitmap childBitmapBuffer = tvChild.getBitmap(Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888)); + canvas.drawBitmap(childBitmapBuffer, 0, 0, paint); + + canvas.restore(); + + } else if (child instanceof SurfaceView) { + final SurfaceView svChild = (SurfaceView) child; + final CountDownLatch latch = new CountDownLatch(1); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + final Bitmap childBitmapBuffer = Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888); + try { + PixelCopy.request(svChild, childBitmapBuffer, copyResult -> { + canvas.save(); + applyTransformations(canvas, child); + canvas.drawBitmap(childBitmapBuffer, 0, 0, paint); + canvas.restore(); + latch.countDown(); + }, new Handler(Looper.getMainLooper())); + latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS); + } catch (Exception e) { + Log.e(TAG, "Cannot PixelCopy for " + svChild, e); + } + } else { + Bitmap cache = svChild.getDrawingCache(); + if (cache != null) { + canvas.save(); + applyTransformations(canvas, child); + canvas.drawBitmap(svChild.getDrawingCache(), 0, 0, paint); + canvas.restore(); + } + } + } else { + // Regular views needs to be rendered again to ensure correct z-index + // order with texture views and surface views. + renderViewToCanvas(canvas, child, paint); + } + } + } else { + // Draw ourselves + view.draw(canvas); + } + + // Restore canvas + canvas.restore(); + } + + @NonNull + private static void applyTransformations(final Canvas c, @NonNull final View view) { + // Get the transformation matrix of the view + final Matrix matrix = view.getMatrix(); + + // Create a new matrix for translation + final Matrix translateMatrix = new Matrix(); + final float dx = view.getLeft() + view.getPaddingLeft() + view.getTranslationX(); + final float dy = view.getTop() + view.getPaddingTop() + view.getTranslationY(); + translateMatrix.setTranslate(dx, dy); + + // Pre-concatenate the current matrix of the canvas with the translation and transformation matrices of the view + c.concat(translateMatrix); + c.concat(matrix); + } +} diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libjsi_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..d7ea20b9700292 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libreact_nativemodule_core_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libreact_nativemodule_core_abi49_0_0.so new file mode 100644 index 00000000000000..17218b22b894c1 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libreact_nativemodule_core_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/librnskia_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/librnskia_abi49_0_0.so new file mode 100644 index 00000000000000..45beab871423f2 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/librnskia_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libturbomodulejsijni_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libturbomodulejsijni_abi49_0_0.so new file mode 100644 index 00000000000000..663159297cb40a Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/arm64-v8a/libturbomodulejsijni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libjsi_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..967a7a3fa36e8e Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libreact_nativemodule_core_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libreact_nativemodule_core_abi49_0_0.so new file mode 100644 index 00000000000000..c505679faa74e9 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libreact_nativemodule_core_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/librnskia_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/librnskia_abi49_0_0.so new file mode 100644 index 00000000000000..3ec96d7ffc4635 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/librnskia_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libturbomodulejsijni_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libturbomodulejsijni_abi49_0_0.so new file mode 100644 index 00000000000000..3c6147d904cdea Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/armeabi-v7a/libturbomodulejsijni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libjsi_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..feda4776839fe0 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libreact_nativemodule_core_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libreact_nativemodule_core_abi49_0_0.so new file mode 100644 index 00000000000000..cc21b8b465fbcc Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libreact_nativemodule_core_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/librnskia_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/librnskia_abi49_0_0.so new file mode 100644 index 00000000000000..b5808729acd741 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/librnskia_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libturbomodulejsijni_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libturbomodulejsijni_abi49_0_0.so new file mode 100644 index 00000000000000..bc71d34adedd64 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86/libturbomodulejsijni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libjsi_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..9019353cac3769 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libreact_nativemodule_core_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libreact_nativemodule_core_abi49_0_0.so new file mode 100644 index 00000000000000..a470b7f874c106 Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libreact_nativemodule_core_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/librnskia_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/librnskia_abi49_0_0.so new file mode 100644 index 00000000000000..e571318e7275be Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/librnskia_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libturbomodulejsijni_abi49_0_0.so b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libturbomodulejsijni_abi49_0_0.so new file mode 100644 index 00000000000000..a2b96fab04a65e Binary files /dev/null and b/android/vendored/sdk49/@shopify/react-native-skia/android/src/main/jniLibs/x86_64/libturbomodulejsijni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkApi.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkApi.h new file mode 100644 index 00000000000000..5e71ed87f8d62f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkApi.h @@ -0,0 +1,105 @@ +#pragma once + +#include + +#include "RNSkPlatformContext.h" + +#include "JsiSkHostObjects.h" + +#include "JsiSkColor.h" +#include "JsiSkColorFilter.h" +#include "JsiSkColorFilterFactory.h" +#include "JsiSkContourMeasureIter.h" +#include "JsiSkDataFactory.h" +#include "JsiSkFont.h" +#include "JsiSkImage.h" +#include "JsiSkImageFactory.h" +#include "JsiSkImageFilter.h" +#include "JsiSkImageFilterFactory.h" +#include "JsiSkMaskFilter.h" +#include "JsiSkMaskFilterFactory.h" +#include "JsiSkMatrix.h" +#include "JsiSkPaint.h" +#include "JsiSkPath.h" +#include "JsiSkPathEffect.h" +#include "JsiSkPathEffectFactory.h" +#include "JsiSkPathFactory.h" +#include "JsiSkPictureFactory.h" +#include "JsiSkPictureRecorder.h" +#include "JsiSkPoint.h" +#include "JsiSkRRect.h" +#include "JsiSkRSXform.h" +#include "JsiSkRect.h" +#include "JsiSkRuntimeEffect.h" +#include "JsiSkRuntimeEffectFactory.h" +#include "JsiSkRuntimeShaderBuilder.h" +#include "JsiSkSVG.h" +#include "JsiSkSVGFactory.h" +#include "JsiSkShader.h" +#include "JsiSkShaderFactory.h" +#include "JsiSkSurfaceFactory.h" +#include "JsiSkTextBlobFactory.h" +#include "JsiSkTypeface.h" +#include "JsiSkTypefaceFactory.h" +#include "JsiSkVertices.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkApi : public JsiSkHostObject { +public: + /** + * Constructs the Skia Api object that can be installed into a runtime + * and provide functions for accessing and creating the Skia wrapper objects + * @param context Platform context + */ + JsiSkApi(jsi::Runtime &runtime, std::shared_ptr context) + : JsiSkHostObject(context) { + + installFunction("Font", JsiSkFont::createCtor(context)); + installFunction("Paint", JsiSkPaint::createCtor(context)); + installFunction("RSXform", JsiSkRSXform::createCtor(context)); + installFunction("Matrix", JsiSkMatrix::createCtor(context)); + installFunction("XYWHRect", JsiSkRect::createCtor(context)); + installFunction("RRectXY", JsiSkRRect::createCtor(context)); + installFunction("Point", JsiSkPoint::createCtor(context)); + installFunction("RuntimeShaderBuilder", + JsiSkRuntimeShaderBuilder::createCtor(context)); + installFunction("ContourMeasureIter", + JsiSkContourMeasureIter::createCtor(context)); + installFunction("MakeVertices", JsiSkVertices::createCtor(context)); + installFunction("PictureRecorder", + JsiSkPictureRecorder::createCtor(context)); + installFunction("Color", JsiSkColor::createCtor()); + + installReadonlyProperty("SVG", std::make_shared(context)); + installReadonlyProperty("Image", + std::make_shared(context)); + installReadonlyProperty("Typeface", + std::make_shared(context)); + installReadonlyProperty("Data", + std::make_shared(context)); + installReadonlyProperty("ImageFilter", + std::make_shared(context)); + installReadonlyProperty("PathEffect", + std::make_shared(context)); + installReadonlyProperty("Path", + std::make_shared(context)); + installReadonlyProperty("ColorFilter", + std::make_shared(context)); + installReadonlyProperty("MaskFilter", + std::make_shared(context)); + installReadonlyProperty( + "RuntimeEffect", std::make_shared(context)); + installReadonlyProperty("Shader", + std::make_shared(context)); + installReadonlyProperty("TextBlob", + std::make_shared(context)); + installReadonlyProperty("Surface", + std::make_shared(context)); + installReadonlyProperty("Picture", + std::make_shared(context)); + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkCanvas.h new file mode 100644 index 00000000000000..3be658bc8bdaf7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkCanvas.h @@ -0,0 +1,548 @@ +#pragma once + +#include +#include +#include + +#include "JsiSkFont.h" +#include "JsiSkHostObjects.h" +#include "JsiSkImage.h" +#include "JsiSkMatrix.h" +#include "JsiSkPaint.h" +#include "JsiSkPath.h" +#include "JsiSkPicture.h" +#include "JsiSkPoint.h" +#include "JsiSkRRect.h" +#include "JsiSkSVG.h" +#include "JsiSkTextBlob.h" +#include "JsiSkVertices.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCanvas.h" +#include "SkFont.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPicture.h" +#include "SkRegion.h" +#include "SkSurface.h" +#include "SkTypeface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { +namespace jsi = facebook::jsi; + +class JsiSkCanvas : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(drawPaint) { + auto paint = JsiSkPaint::fromValue(runtime, arguments[0]); + _canvas->drawPaint(*paint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawLine) { + SkScalar x1 = arguments[0].asNumber(); + SkScalar y1 = arguments[1].asNumber(); + SkScalar x2 = arguments[2].asNumber(); + SkScalar y2 = arguments[3].asNumber(); + auto paint = JsiSkPaint::fromValue(runtime, arguments[4]); + _canvas->drawLine(x1, y1, x2, y2, *paint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawRect) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[1]); + _canvas->drawRect(*rect, *paint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImage) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto x = arguments[1].asNumber(); + auto y = arguments[2].asNumber(); + std::shared_ptr paint; + if (count == 4) { + paint = JsiSkPaint::fromValue(runtime, arguments[3]); + } + _canvas->drawImage(image, x, y, SkSamplingOptions(), paint.get()); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImageRect) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto src = JsiSkRect::fromValue(runtime, arguments[1]); + auto dest = JsiSkRect::fromValue(runtime, arguments[2]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[3]); + auto fastSample = count < 5 ? false : arguments[4].getBool(); + _canvas->drawImageRect(image, *src, *dest, SkSamplingOptions(), paint.get(), + fastSample ? SkCanvas::kFast_SrcRectConstraint + : SkCanvas::kStrict_SrcRectConstraint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImageCubic) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto x = arguments[1].asNumber(); + auto y = arguments[2].asNumber(); + float B = arguments[3].asNumber(); + float C = arguments[4].asNumber(); + std::shared_ptr paint; + if (count == 6) { + if (!arguments[5].isNull()) { + paint = JsiSkPaint::fromValue(runtime, arguments[5]); + } + } + _canvas->drawImage(image, x, y, SkSamplingOptions({B, C}), paint.get()); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImageOptions) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto x = arguments[1].asNumber(); + auto y = arguments[2].asNumber(); + auto fm = (SkFilterMode)arguments[3].asNumber(); + auto mm = (SkMipmapMode)arguments[4].asNumber(); + std::shared_ptr paint; + if (count == 6) { + if (!arguments[5].isNull()) { + paint = JsiSkPaint::fromValue(runtime, arguments[5]); + } + } + _canvas->drawImage(image, x, y, SkSamplingOptions(fm, mm), paint.get()); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImageNine) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto center = JsiSkRect::fromValue(runtime, arguments[1]); + auto dest = JsiSkRect::fromValue(runtime, arguments[2]); + auto fm = (SkFilterMode)arguments[3].asNumber(); + std::shared_ptr paint; + if (count == 5) { + if (!arguments[4].isNull()) { + paint = JsiSkPaint::fromValue(runtime, arguments[4]); + } + } + _canvas->drawImageNine(image.get(), center->round(), *dest, fm, + paint.get()); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImageRectCubic) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto src = JsiSkRect::fromValue(runtime, arguments[1]); + auto dest = JsiSkRect::fromValue(runtime, arguments[2]); + float B = arguments[3].asNumber(); + float C = arguments[4].asNumber(); + std::shared_ptr paint; + if (count == 6) { + if (!arguments[5].isNull()) { + paint = JsiSkPaint::fromValue(runtime, arguments[5]); + } + } + auto constraint = + SkCanvas::kStrict_SrcRectConstraint; // TODO: get from caller + _canvas->drawImageRect(image.get(), *src, *dest, SkSamplingOptions({B, C}), + paint.get(), constraint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawImageRectOptions) { + auto image = JsiSkImage::fromValue(runtime, arguments[0]); + auto src = JsiSkRect::fromValue(runtime, arguments[1]); + auto dest = JsiSkRect::fromValue(runtime, arguments[2]); + auto filter = (SkFilterMode)arguments[3].asNumber(); + auto mipmap = (SkMipmapMode)arguments[4].asNumber(); + std::shared_ptr paint; + if (count == 6) { + if (!arguments[5].isNull()) { + paint = JsiSkPaint::fromValue(runtime, arguments[5]); + } + } + auto constraint = SkCanvas::kStrict_SrcRectConstraint; + _canvas->drawImageRect(image.get(), *src, *dest, {filter, mipmap}, + paint.get(), constraint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawCircle) { + SkScalar cx = arguments[0].asNumber(); + SkScalar cy = arguments[1].asNumber(); + SkScalar radius = arguments[2].asNumber(); + + auto paint = JsiSkPaint::fromValue(runtime, arguments[3]); + _canvas->drawCircle(cx, cy, radius, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawArc) { + auto oval = JsiSkRect::fromValue(runtime, arguments[0]); + + SkScalar startAngle = arguments[1].asNumber(); + SkScalar sweepAngle = arguments[2].asNumber(); + bool useCenter = arguments[3].getBool(); + + auto paint = JsiSkPaint::fromValue(runtime, arguments[4]); + _canvas->drawArc(*oval, startAngle, sweepAngle, useCenter, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawRRect) { + auto rect = JsiSkRRect::fromValue(runtime, arguments[0]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[1]); + + _canvas->drawRRect(*rect, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawDRRect) { + auto outer = JsiSkRRect::fromValue(runtime, arguments[0]); + auto inner = JsiSkRRect::fromValue(runtime, arguments[1]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[2]); + + _canvas->drawDRRect(*outer, *inner, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawOval) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[1]); + + _canvas->drawOval(*rect, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(restoreToCount) { + auto c = arguments[0].asNumber(); + _canvas->restoreToCount(c); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(getSaveCount) { + return static_cast(_canvas->getSaveCount()); + } + + JSI_HOST_FUNCTION(drawPoints) { + auto pointMode = arguments[0].asNumber(); + std::vector points; + + auto jsiPoints = arguments[1].asObject(runtime).asArray(runtime); + auto pointsSize = jsiPoints.size(runtime); + points.reserve(pointsSize); + + for (int i = 0; i < pointsSize; i++) { + std::shared_ptr point = JsiSkPoint::fromValue( + runtime, jsiPoints.getValueAtIndex(runtime, i).asObject(runtime)); + points.push_back(*point.get()); + } + + auto paint = JsiSkPaint::fromValue(runtime, arguments[2]); + + _canvas->drawPoints((SkCanvas::PointMode)pointMode, pointsSize, + points.data(), *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawVertices) { + auto vertices = JsiSkVertices::fromValue(runtime, arguments[0]); + auto blendMode = (SkBlendMode)arguments[1].getNumber(); + auto paint = JsiSkPaint::fromValue(runtime, arguments[2]); + _canvas->drawVertices(vertices, blendMode, *paint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawPatch) { + std::vector cubics; + std::vector colors; + std::vector texs; + + auto jsiCubics = arguments[0].asObject(runtime).asArray(runtime); + auto cubicsSize = jsiCubics.size(runtime); + cubics.reserve(cubicsSize); + for (int i = 0; i < cubicsSize; i++) { + std::shared_ptr point = JsiSkPoint::fromValue( + runtime, jsiCubics.getValueAtIndex(runtime, i).asObject(runtime)); + cubics.push_back(*point.get()); + } + + if (count >= 2 && !arguments[1].isNull() && !arguments[1].isUndefined()) { + auto jsiColors = arguments[1].asObject(runtime).asArray(runtime); + auto colorsSize = jsiColors.size(runtime); + colors.reserve(colorsSize); + for (int i = 0; i < colorsSize; i++) { + SkColor color = JsiSkColor::fromValue( + runtime, jsiColors.getValueAtIndex(runtime, i)); + colors.push_back(color); + } + } + + if (count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + auto jsiTexs = arguments[2].asObject(runtime).asArray(runtime); + auto texsSize = jsiTexs.size(runtime); + texs.reserve(texsSize); + for (int i = 0; i < texsSize; i++) { + auto point = JsiSkPoint::fromValue( + runtime, jsiTexs.getValueAtIndex(runtime, i).asObject(runtime)); + texs.push_back(*point.get()); + } + } + + auto paint = + count >= 4 ? JsiSkPaint::fromValue(runtime, arguments[4]) : nullptr; + auto blendMode = static_cast(arguments[3].asNumber()); + _canvas->drawPatch(cubics.data(), colors.data(), texs.data(), blendMode, + *paint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawPath) { + auto path = JsiSkPath::fromValue(runtime, arguments[0]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[1]); + + _canvas->drawPath(*path, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawText) { + auto textVal = arguments[0].asString(runtime).utf8(runtime); + auto text = textVal.c_str(); + SkScalar x = arguments[1].asNumber(); + SkScalar y = arguments[2].asNumber(); + + auto paint = JsiSkPaint::fromValue(runtime, arguments[3]); + auto font = JsiSkFont::fromValue(runtime, arguments[4]); + + _canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, x, y, + *font, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawTextBlob) { + auto blob = JsiSkTextBlob::fromValue(runtime, arguments[0]); + SkScalar x = arguments[1].asNumber(); + SkScalar y = arguments[2].asNumber(); + auto paint = JsiSkPaint::fromValue(runtime, arguments[3]); + _canvas->drawTextBlob(blob, x, y, *paint); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawGlyphs) { + auto jsiGlyphs = arguments[0].asObject(runtime).asArray(runtime); + auto jsiPositions = arguments[1].asObject(runtime).asArray(runtime); + auto x = arguments[2].asNumber(); + auto y = arguments[3].asNumber(); + auto font = JsiSkFont::fromValue(runtime, arguments[4]); + auto paint = JsiSkPaint::fromValue(runtime, arguments[5]); + SkPoint origin = SkPoint::Make(x, y); + + std::vector positions; + int pointsSize = static_cast(jsiPositions.size(runtime)); + positions.reserve(pointsSize); + for (int i = 0; i < pointsSize; i++) { + std::shared_ptr point = JsiSkPoint::fromValue( + runtime, jsiPositions.getValueAtIndex(runtime, i).asObject(runtime)); + positions.push_back(*point.get()); + } + + std::vector glyphs; + int glyphsSize = static_cast(jsiGlyphs.size(runtime)); + glyphs.reserve(glyphsSize); + for (int i = 0; i < glyphsSize; i++) { + glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber()); + } + + _canvas->drawGlyphs(glyphsSize, glyphs.data(), positions.data(), origin, + *font, *paint); + + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawSvg) { + auto svgdom = JsiSkSVG::fromValue(runtime, arguments[0]); + if (count == 3) { + // read size + auto w = arguments[1].asNumber(); + auto h = arguments[2].asNumber(); + svgdom->setContainerSize(SkSize::Make(w, h)); + } else { + auto canvasSize = _canvas->getBaseLayerSize(); + svgdom->setContainerSize(SkSize::Make(canvasSize)); + } + svgdom->render(_canvas); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(clipPath) { + auto path = JsiSkPath::fromValue(runtime, arguments[0]); + auto op = (SkClipOp)arguments[1].asNumber(); + auto doAntiAlias = arguments[2].getBool(); + _canvas->clipPath(*path, op, doAntiAlias); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(clipRect) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto op = (SkClipOp)arguments[1].asNumber(); + auto doAntiAlias = arguments[2].getBool(); + _canvas->clipRect(*rect, op, doAntiAlias); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(clipRRect) { + auto rrect = JsiSkRRect::fromValue(runtime, arguments[0]); + auto op = (SkClipOp)arguments[1].asNumber(); + auto doAntiAlias = arguments[2].getBool(); + _canvas->clipRRect(*rrect, op, doAntiAlias); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(save) { return jsi::Value(_canvas->save()); } + + JSI_HOST_FUNCTION(saveLayer) { + SkPaint *paint = (count >= 1 && !arguments[0].isUndefined()) + ? JsiSkPaint::fromValue(runtime, arguments[0]).get() + : nullptr; + SkRect *bounds = + count >= 2 && !arguments[1].isNull() && !arguments[1].isUndefined() + ? JsiSkRect::fromValue(runtime, arguments[1]).get() + : nullptr; + SkImageFilter *backdrop = + count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined() + ? JsiSkImageFilter::fromValue(runtime, arguments[2]).get() + : nullptr; + SkCanvas::SaveLayerFlags flags = count >= 4 ? arguments[3].asNumber() : 0; + return jsi::Value(_canvas->saveLayer( + SkCanvas::SaveLayerRec(bounds, paint, backdrop, flags))); + } + + JSI_HOST_FUNCTION(restore) { + _canvas->restore(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(rotate) { + SkScalar degrees = arguments[0].asNumber(); + SkScalar rx = arguments[1].asNumber(); + SkScalar ry = arguments[2].asNumber(); + _canvas->rotate(degrees, rx, ry); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(translate) { + SkScalar dx = arguments[0].asNumber(); + SkScalar dy = arguments[1].asNumber(); + _canvas->translate(dx, dy); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(scale) { + SkScalar sx = arguments[0].asNumber(); + SkScalar sy = arguments[1].asNumber(); + _canvas->scale(sx, sy); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(skew) { + SkScalar sx = arguments[0].asNumber(); + SkScalar sy = arguments[1].asNumber(); + _canvas->skew(sx, sy); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawColor) { + SkColor cl = JsiSkColor::fromValue(runtime, arguments[0]); + if (count == 1) { + _canvas->drawColor(cl); + } else { + auto mode = static_cast(arguments[1].asNumber()); + _canvas->drawColor(cl, mode); + } + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(clear) { + SkColor cl = JsiSkColor::fromValue(runtime, arguments[0]); + _canvas->clear(cl); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(concat) { + auto matrix = JsiSkMatrix::fromValue(runtime, arguments[0]); + _canvas->concat(*matrix.get()); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(drawPicture) { + auto picture = JsiSkPicture::fromValue(runtime, arguments[0]); + _canvas->drawPicture(picture); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkCanvas, drawPaint), + JSI_EXPORT_FUNC(JsiSkCanvas, drawLine), + JSI_EXPORT_FUNC(JsiSkCanvas, drawRect), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImage), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImageRect), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImageCubic), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImageOptions), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImageNine), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImageRectCubic), + JSI_EXPORT_FUNC(JsiSkCanvas, drawImageRectOptions), + JSI_EXPORT_FUNC(JsiSkCanvas, drawCircle), + JSI_EXPORT_FUNC(JsiSkCanvas, drawArc), + JSI_EXPORT_FUNC(JsiSkCanvas, drawRRect), + JSI_EXPORT_FUNC(JsiSkCanvas, drawDRRect), + JSI_EXPORT_FUNC(JsiSkCanvas, drawOval), + JSI_EXPORT_FUNC(JsiSkCanvas, restoreToCount), + JSI_EXPORT_FUNC(JsiSkCanvas, getSaveCount), + JSI_EXPORT_FUNC(JsiSkCanvas, drawPoints), + JSI_EXPORT_FUNC(JsiSkCanvas, drawPatch), + JSI_EXPORT_FUNC(JsiSkCanvas, drawPath), + JSI_EXPORT_FUNC(JsiSkCanvas, drawVertices), + JSI_EXPORT_FUNC(JsiSkCanvas, drawText), + JSI_EXPORT_FUNC(JsiSkCanvas, drawTextBlob), + JSI_EXPORT_FUNC(JsiSkCanvas, drawGlyphs), + JSI_EXPORT_FUNC(JsiSkCanvas, drawSvg), + JSI_EXPORT_FUNC(JsiSkCanvas, clipPath), + JSI_EXPORT_FUNC(JsiSkCanvas, clipRect), + JSI_EXPORT_FUNC(JsiSkCanvas, clipRRect), + JSI_EXPORT_FUNC(JsiSkCanvas, save), + JSI_EXPORT_FUNC(JsiSkCanvas, saveLayer), + JSI_EXPORT_FUNC(JsiSkCanvas, restore), + JSI_EXPORT_FUNC(JsiSkCanvas, rotate), + JSI_EXPORT_FUNC(JsiSkCanvas, translate), + JSI_EXPORT_FUNC(JsiSkCanvas, scale), + JSI_EXPORT_FUNC(JsiSkCanvas, skew), + JSI_EXPORT_FUNC(JsiSkCanvas, drawColor), + JSI_EXPORT_FUNC(JsiSkCanvas, clear), + JSI_EXPORT_FUNC(JsiSkCanvas, concat), + JSI_EXPORT_FUNC(JsiSkCanvas, drawPicture)) + + explicit JsiSkCanvas(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} + + JsiSkCanvas(std::shared_ptr context, SkCanvas *canvas) + : JsiSkCanvas(std::move(context)) { + setCanvas(canvas); + } + + void setCanvas(SkCanvas *canvas) { _canvas = canvas; } + SkCanvas *getCanvas() { return _canvas; } + +private: + SkCanvas *_canvas; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColor.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColor.h new file mode 100644 index 00000000000000..3edda895637f0d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColor.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "third_party/CSSColorParser.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColor.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkColor : public RNJsi::JsiHostObject { +public: + JsiSkColor() : JsiHostObject() {} + + ~JsiSkColor() {} + + static jsi::Object toValue(jsi::Runtime &runtime, SkColor color) { + auto result = runtime.global() + .getPropertyAsFunction(runtime, "Float32Array") + .callAsConstructor(runtime, 4) + .getObject(runtime); + jsi::ArrayBuffer buffer = + result + .getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer")) + .asObject(runtime) + .getArrayBuffer(runtime); + auto bfrPtr = reinterpret_cast(buffer.data(runtime)); + auto color4f = SkColor4f::FromColor(color).array(); + std::copy(color4f.begin(), color4f.end(), bfrPtr); + return result; + } + + static SkColor fromValue(jsi::Runtime &runtime, const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + jsi::ArrayBuffer buffer = + object + .getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer")) + .asObject(runtime) + .getArrayBuffer(runtime); + auto bfrPtr = reinterpret_cast(buffer.data(runtime)); + if (bfrPtr[0] > 1 || bfrPtr[1] > 1 || bfrPtr[2] > 1 || bfrPtr[3] > 1) { + return SK_ColorBLACK; + } + return SkColorSetARGB(bfrPtr[3] * 255, bfrPtr[0] * 255, bfrPtr[1] * 255, + bfrPtr[2] * 255); + } + + /** + * Creates the function for construction a new instance of the SkColor + * wrapper + * @return A function for creating a new host object wrapper for the SkColor + * class + */ + static const jsi::HostFunctionType createCtor() { + return JSI_HOST_FUNCTION_LAMBDA { + if (arguments[0].isNumber()) { + return JsiSkColor::toValue(runtime, arguments[0].getNumber()); + } else if (arguments[0].isString()) { + auto text = arguments[0].asString(runtime).utf8(runtime); + auto color = CSSColorParser::parse(text); + if (color.a == -1.0f) { + return JsiSkColor::toValue(runtime, SK_ColorBLACK); + } + return JsiSkColor::toValue( + runtime, SkColorSetARGB(color.a * 255, color.r, color.g, color.b)); + } else if (arguments[0].isObject()) { + return arguments[0].getObject(runtime); + } + return jsi::Value::undefined(); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColorFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColorFilter.h new file mode 100644 index 00000000000000..06410738e20ab1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColorFilter.h @@ -0,0 +1,30 @@ +#pragma once + +#include "JsiSkHostObjects.h" +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColorFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkColorFilter : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkColorFilter(std::shared_ptr context, + sk_sp colorFilter) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(colorFilter)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkColorFilter, "ColorFilter") + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkColorFilter, dispose)) +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColorFilterFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColorFilterFactory.h new file mode 100644 index 00000000000000..4106ef271ab46b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkColorFilterFactory.h @@ -0,0 +1,101 @@ +#pragma once + +#include "JsiSkColor.h" +#include "JsiSkColorFilter.h" +#include "JsiSkHostObjects.h" +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColorFilter.h" +#include "SkLumaColorFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkColorFilterFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeMatrix) { + auto jsiMatrix = arguments[0].asObject(runtime).asArray(runtime); + float matrix[20]; + for (int i = 0; i < 20; i++) { + if (jsiMatrix.size(runtime) > i) { + matrix[i] = jsiMatrix.getValueAtIndex(runtime, i).asNumber(); + } + } + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkColorFilters::Matrix(std::move(matrix)))); + } + + JSI_HOST_FUNCTION(MakeBlend) { + auto color = JsiSkColor::fromValue(runtime, arguments[0]); + SkBlendMode blend = (SkBlendMode)arguments[1].asNumber(); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkColorFilters::Blend(color, blend))); + } + + JSI_HOST_FUNCTION(MakeCompose) { + auto outer = JsiSkColorFilter::fromValue(runtime, arguments[0]); + auto inner = JsiSkColorFilter::fromValue(runtime, arguments[1]); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkColorFilters::Compose(std::move(outer), + std::move(inner)))); + } + + JSI_HOST_FUNCTION(MakeLerp) { + auto t = arguments[0].asNumber(); + auto dst = JsiSkColorFilter::fromValue(runtime, arguments[1]); + auto src = JsiSkColorFilter::fromValue(runtime, arguments[2]); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkColorFilters::Lerp(t, std::move(dst), std::move(src)))); + } + + JSI_HOST_FUNCTION(MakeSRGBToLinearGamma) { + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkColorFilters::SRGBToLinearGamma())); + } + + JSI_HOST_FUNCTION(MakeLinearToSRGBGamma) { + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkColorFilters::LinearToSRGBGamma())); + } + + JSI_HOST_FUNCTION(MakeLumaColorFilter) { + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), + SkLumaColorFilter::Make())); + } + + JSI_EXPORT_FUNCTIONS( + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeMatrix), + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeBlend), + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeCompose), + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeLerp), + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeSRGBToLinearGamma), + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeLinearToSRGBGamma), + JSI_EXPORT_FUNC(JsiSkColorFilterFactory, MakeLumaColorFilter)) + + explicit JsiSkColorFilterFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkContourMeasure.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkContourMeasure.h new file mode 100644 index 00000000000000..3dff4ebdd856c0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkContourMeasure.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkContourMeasure.h" + +#include "JsiSkPath.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkContourMeasure + : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkContourMeasure(std::shared_ptr context, + const sk_sp contourMeasure) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(contourMeasure)) { + if (contourMeasure == nullptr) { + throw jsi::JSError(*context->getJsRuntime(), "Contour measure is null"); + } + } + + JSI_HOST_FUNCTION(getPosTan) { + auto dist = arguments[0].asNumber(); + SkPoint position; + SkPoint tangent; + auto result = getObject()->getPosTan(dist, &position, &tangent); + if (!result) { + throw jsi::JSError(runtime, "getSegment() failed"); + } + auto posTan = jsi::Array(runtime, 2); + auto pos = jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), position)); + auto tan = jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), tangent)); + posTan.setValueAtIndex(runtime, 0, pos); + posTan.setValueAtIndex(runtime, 1, tan); + return posTan; + } + + JSI_HOST_FUNCTION(length) { + return jsi::Value(SkScalarToDouble(getObject()->length())); + } + + JSI_HOST_FUNCTION(isClosed) { return jsi::Value(getObject()->isClosed()); } + + JSI_HOST_FUNCTION(getSegment) { + auto start = arguments[0].asNumber(); + auto end = arguments[1].asNumber(); + auto startWithMoveTo = arguments[2].getBool(); + SkPath path; + auto result = getObject()->getSegment(start, end, &path, startWithMoveTo); + if (!result) { + throw jsi::JSError(runtime, "getSegment() failed"); + } + return JsiSkPath::toValue(runtime, getContext(), std::move(path)); + } + + EXPORT_JSI_API_TYPENAME(JsiSkContourMeasure, "ContourMeasure") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkContourMeasure, getPosTan), + JSI_EXPORT_FUNC(JsiSkContourMeasure, length), + JSI_EXPORT_FUNC(JsiSkContourMeasure, isClosed), + JSI_EXPORT_FUNC(JsiSkContourMeasure, getSegment), + JSI_EXPORT_FUNC(JsiSkContourMeasure, dispose)) +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkContourMeasureIter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkContourMeasureIter.h new file mode 100644 index 00000000000000..8ea8d7cd1da242 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkContourMeasureIter.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include "JsiSkContourMeasure.h" +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkContourMeasure.h" + +#include "JsiSkPath.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkContourMeasureIter + : public JsiSkWrappingSharedPtrHostObject { +public: + JsiSkContourMeasureIter(std::shared_ptr context, + const SkPath &path, bool forceClosed, + SkScalar resScale = 1) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared( + path, forceClosed, resScale)) {} + + JSI_HOST_FUNCTION(next) { + auto next = getObject()->next(); + if (next == nullptr) { + return jsi::Value::undefined(); + } + auto nextObject = + std::make_shared(getContext(), std::move(next)); + + return jsi::Object::createFromHostObject(runtime, std::move(nextObject)); + } + + EXPORT_JSI_API_TYPENAME(JsiSkContourMeasureIter, "ContourMeasureIter") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkContourMeasureIter, next), + JSI_EXPORT_FUNC(JsiSkContourMeasureIter, dispose)) + + /** + * Creates the function for construction a new instance of the + * SkContourMeasureIter wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the + * SkContourMeasureIter class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto path = JsiSkPath::fromValue(runtime, arguments[0]); + auto forceClosed = arguments[1].getBool(); + auto resScale = arguments[2].asNumber(); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + std::move(context), *path, forceClosed, resScale)); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkData.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkData.h new file mode 100644 index 00000000000000..3e24df5119f45c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkData.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkFont.h" +#include "SkStream.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkData : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkData(std::shared_ptr context, sk_sp asset) + : JsiSkWrappingSkPtrHostObject(std::move(context), std::move(asset)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkData, "Data") + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkData, dispose)) +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkDataFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkDataFactory.h new file mode 100644 index 00000000000000..7c9317655114f2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkDataFactory.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include + +#include +#include + +#include "SkBase64.h" + +#include "JsiSkData.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; +namespace react = facebook::react; + +class JsiSkDataFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(fromURI) { + auto jsiLocalUri = arguments[0].asString(runtime); + auto localUri = jsiLocalUri.utf8(runtime); + auto context = getContext(); + return react::createPromiseAsJSIValue( + runtime, + [context = std::move(context), localUri = std::move(localUri)]( + jsi::Runtime &runtime, + std::shared_ptr promise) -> void { + // Create a stream operation - this will be run in a + // separate thread + context->performStreamOperation( + localUri, + [&runtime, context = std::move(context), + promise = std::move(promise)]( + std::unique_ptr stream) -> void { + // Schedule drawCallback on the Javascript thread + auto result = + SkData::MakeFromStream(stream.get(), stream->getLength()); + context->runOnJavascriptThread([&runtime, + context = std::move(context), + promise = std::move(promise), + result = std::move(result)]() { + promise->resolve(jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), + std::move(result)))); + }); + }); + }); + }; + + JSI_HOST_FUNCTION(fromBytes) { + auto array = arguments[0].asObject(runtime); + jsi::ArrayBuffer buffer = + array.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer")) + .asObject(runtime) + .getArrayBuffer(runtime); + + auto data = + SkData::MakeWithCopy(buffer.data(runtime), buffer.size(runtime)); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(data))); + } + + JSI_HOST_FUNCTION(fromBase64) { + auto base64 = arguments[0].asString(runtime); + auto base64Str = base64.utf8(runtime); + auto size = base64Str.size(); + + // Calculate length + size_t len; + auto err = + SkBase64::Decode(&base64.utf8(runtime).c_str()[0], size, nullptr, &len); + if (err != SkBase64::Error::kNoError) { + throw jsi::JSError(runtime, "Error decoding base64 string"); + return jsi::Value::undefined(); + } + + // Create data object and decode + auto data = SkData::MakeUninitialized(len); + err = SkBase64::Decode(&base64.utf8(runtime).c_str()[0], size, + data->writable_data(), &len); + if (err != SkBase64::Error::kNoError) { + throw jsi::JSError(runtime, "Error decoding base64 string"); + return jsi::Value::undefined(); + } + + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(data))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkDataFactory, fromURI), + JSI_EXPORT_FUNC(JsiSkDataFactory, fromBytes), + JSI_EXPORT_FUNC(JsiSkDataFactory, fromBase64)) + + explicit JsiSkDataFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkFont.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkFont.h new file mode 100644 index 00000000000000..917791ee90538a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkFont.h @@ -0,0 +1,300 @@ +#pragma once + +#include +#include +#include +#include + +#include "JsiSkHostObjects.h" +#include "RNSkLog.h" +#include + +#include "JsiSkPaint.h" +#include "JsiSkPoint.h" +#include "JsiSkRect.h" +#include "JsiSkTypeface.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkFont.h" +#include "SkFontMetrics.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkFont : public JsiSkWrappingSharedPtrHostObject { +public: + JSI_HOST_FUNCTION(getGlyphWidths) { + auto jsiGlyphs = arguments[0].asObject(runtime).asArray(runtime); + std::vector glyphs; + int glyphsSize = static_cast(jsiGlyphs.size(runtime)); + + std::vector widthPtrs; + widthPtrs.resize(glyphsSize); + + glyphs.reserve(glyphsSize); + for (int i = 0; i < glyphsSize; i++) { + glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber()); + } + if (count > 1) { + auto paint = JsiSkPaint::fromValue(runtime, arguments[1]); + getObject()->getWidthsBounds(glyphs.data(), glyphsSize, + static_cast(widthPtrs.data()), + nullptr, paint.get()); + } else { + getObject()->getWidthsBounds(glyphs.data(), glyphsSize, + static_cast(widthPtrs.data()), + nullptr, nullptr); + } + auto jsiWidths = jsi::Array(runtime, glyphsSize); + for (int i = 0; i < glyphsSize; i++) { + jsiWidths.setValueAtIndex( + runtime, i, + jsi::Value( + SkScalarToDouble(static_cast(widthPtrs.data())[i]))); + } + return jsiWidths; + } + + JSI_HOST_FUNCTION(getTextWidth) { + auto str = arguments[0].asString(runtime).utf8(runtime); + auto numGlyphIDs = getObject()->countText(str.c_str(), str.length(), + SkTextEncoding::kUTF8); + std::vector glyphs; + glyphs.resize(numGlyphIDs); + int glyphsSize = static_cast(numGlyphIDs); + getObject()->textToGlyphs(str.c_str(), str.length(), SkTextEncoding::kUTF8, + static_cast(glyphs.data()), + glyphsSize); + std::vector widthPtrs; + widthPtrs.resize(numGlyphIDs); + if (count > 1) { + auto paint = JsiSkPaint::fromValue(runtime, arguments[1]); + getObject()->getWidthsBounds(glyphs.data(), glyphsSize, + static_cast(widthPtrs.data()), + nullptr, paint.get()); + } else { + getObject()->getWidthsBounds(glyphs.data(), glyphsSize, + static_cast(widthPtrs.data()), + nullptr, nullptr); + } + return jsi::Value(std::accumulate(widthPtrs.begin(), widthPtrs.end(), 0)); + } + + JSI_HOST_FUNCTION(getMetrics) { + SkFontMetrics fm; + getObject()->getMetrics(&fm); + auto metrics = jsi::Object(runtime); + metrics.setProperty(runtime, "ascent", fm.fAscent); + metrics.setProperty(runtime, "descent", fm.fDescent); + metrics.setProperty(runtime, "leading", fm.fLeading); + if (!(fm.fFlags & SkFontMetrics::kBoundsInvalid_Flag)) { + auto bounds = SkRect::MakeLTRB(fm.fXMin, fm.fTop, fm.fXMax, fm.fBottom); + auto jsiBounds = + JsiSkRect::toValue(runtime, getContext(), std::move(bounds)); + metrics.setProperty(runtime, "bounds", std::move(jsiBounds)); + } + return metrics; + } + + JSI_HOST_FUNCTION(getGlyphIDs) { + auto str = arguments[0].asString(runtime).utf8(runtime); + int numGlyphIDs = + count > 1 && !arguments[1].isNull() && !arguments[1].isUndefined() + ? static_cast(arguments[1].asNumber()) + : getObject()->countText(str.c_str(), str.length(), + SkTextEncoding::kUTF8); + std::vector glyphIDs; + glyphIDs.resize(numGlyphIDs); + getObject()->textToGlyphs(str.c_str(), str.length(), SkTextEncoding::kUTF8, + static_cast(glyphIDs.data()), + numGlyphIDs); + auto jsiGlyphIDs = jsi::Array(runtime, numGlyphIDs); + for (int i = 0; i < numGlyphIDs; i++) { + jsiGlyphIDs.setValueAtIndex(runtime, i, + jsi::Value(static_cast(glyphIDs[i]))); + } + return jsiGlyphIDs; + } + + JSI_HOST_FUNCTION(getGlyphIntercepts) { + auto jsiGlyphs = arguments[0].asObject(runtime).asArray(runtime); + auto jsiPositions = arguments[1].asObject(runtime).asArray(runtime); + auto top = arguments[2].asNumber(); + auto bottom = arguments[3].asNumber(); + std::vector positions; + int pointsSize = static_cast(jsiPositions.size(runtime)); + positions.reserve(pointsSize); + for (int i = 0; i < pointsSize; i++) { + std::shared_ptr point = JsiSkPoint::fromValue( + runtime, jsiPositions.getValueAtIndex(runtime, i).asObject(runtime)); + positions.push_back(*point.get()); + } + + std::vector glyphs; + int glyphsSize = static_cast(jsiGlyphs.size(runtime)); + glyphs.reserve(glyphsSize); + for (int i = 0; i < glyphsSize; i++) { + glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber()); + } + + if (glyphs.size() > positions.size()) { + throw jsi::JSError(runtime, "Not enough x,y position pairs for glyphs"); + return jsi::Value::null(); + } + auto sects = getObject()->getIntercepts( + glyphs.data(), SkToInt(glyphs.size()), positions.data(), top, bottom); + auto jsiSects = jsi::Array(runtime, sects.size()); + for (int i = 0; i < sects.size(); i++) { + jsiSects.setValueAtIndex(runtime, i, + jsi::Value(static_cast(sects.at(i)))); + } + return jsiSects; + } + + JSI_HOST_FUNCTION(getScaleX) { + return jsi::Value(SkScalarToDouble(getObject()->getScaleX())); + } + + JSI_HOST_FUNCTION(getSize) { + return jsi::Value(SkScalarToDouble(getObject()->getSize())); + } + + JSI_HOST_FUNCTION(getSkewX) { + return jsi::Value(SkScalarToDouble(getObject()->getSkewX())); + } + + JSI_HOST_FUNCTION(isEmbolden) { + return jsi::Value(getObject()->isEmbolden()); + } + + JSI_HOST_FUNCTION(getTypeface) { + return JsiSkTypeface::toValue( + runtime, getContext(), sk_sp(getObject()->getTypeface())); + } + + JSI_HOST_FUNCTION(setEdging) { + auto edging = arguments[0].asNumber(); + getObject()->setEdging(static_cast(edging)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(embeddedBitmaps) { + auto embeddedBitmaps = arguments[0].getBool(); + getObject()->setEmbeddedBitmaps(embeddedBitmaps); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setHinting) { + auto hinting = arguments[0].asNumber(); + getObject()->setHinting(static_cast(hinting)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setLinearMetrics) { + auto linearMetrics = arguments[0].getBool(); + getObject()->setLinearMetrics(linearMetrics); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setScaleX) { + auto scaleX = arguments[0].asNumber(); + getObject()->setScaleX(scaleX); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setSkewX) { + auto skewX = arguments[0].asNumber(); + getObject()->setSkewX(skewX); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setSize) { + auto size = arguments[0].asNumber(); + getObject()->setSize(size); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setEmbolden) { + auto embolden = arguments[0].asNumber(); + getObject()->setEmbolden(embolden); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setSubpixel) { + auto subpixel = arguments[0].asNumber(); + getObject()->setSubpixel(subpixel); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setTypeface) { + auto typeface = arguments[0].isNull() + ? nullptr + : JsiSkTypeface::fromValue(runtime, arguments[0]); + getObject()->setTypeface(typeface); + return jsi::Value::undefined(); + } + + EXPORT_JSI_API_TYPENAME(JsiSkFont, "Font") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkFont, getSize), + JSI_EXPORT_FUNC(JsiSkFont, getMetrics), + JSI_EXPORT_FUNC(JsiSkFont, getGlyphIDs), + JSI_EXPORT_FUNC(JsiSkFont, getGlyphIntercepts), + JSI_EXPORT_FUNC(JsiSkFont, getScaleX), + JSI_EXPORT_FUNC(JsiSkFont, getSkewX), + JSI_EXPORT_FUNC(JsiSkFont, getTypeface), + JSI_EXPORT_FUNC(JsiSkFont, setEdging), + JSI_EXPORT_FUNC(JsiSkFont, embeddedBitmaps), + JSI_EXPORT_FUNC(JsiSkFont, setHinting), + JSI_EXPORT_FUNC(JsiSkFont, setLinearMetrics), + JSI_EXPORT_FUNC(JsiSkFont, setScaleX), + JSI_EXPORT_FUNC(JsiSkFont, setSkewX), + JSI_EXPORT_FUNC(JsiSkFont, setSize), + JSI_EXPORT_FUNC(JsiSkFont, setEmbolden), + JSI_EXPORT_FUNC(JsiSkFont, setSubpixel), + JSI_EXPORT_FUNC(JsiSkFont, setTypeface), + JSI_EXPORT_FUNC(JsiSkFont, getGlyphWidths), + JSI_EXPORT_FUNC(JsiSkFont, getTextWidth), + JSI_EXPORT_FUNC(JsiSkFont, dispose)) + + JsiSkFont(std::shared_ptr context, const SkFont &font) + : JsiSkWrappingSharedPtrHostObject(std::move(context), + std::make_shared(font)) {} + + /** + * Creates the function for construction a new instance of the SkFont + * wrapper + * @param context Platform context + * @return A function for creating a new host object wrapper for the SkFont + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + // Handle arguments + if (count == 2) { + auto typeface = JsiSkTypeface::fromValue(runtime, arguments[0]); + auto size = arguments[1].asNumber(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), + SkFont(typeface, size))); + } else if (count == 1) { + auto typeface = JsiSkTypeface::fromValue(runtime, arguments[0]); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), SkFont(typeface))); + } else { + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), SkFont())); + } + }; + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkHostObjects.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkHostObjects.h new file mode 100644 index 00000000000000..68410f9c45bbc9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkHostObjects.h @@ -0,0 +1,163 @@ +#pragma once + +#include +#include + +#include "JsiHostObject.h" +#include "RNSkPlatformContext.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +/** + * Base class for jsi host objects - these are all implemented as JsiHostObjects + * and has a pointer to the platform context. + */ +class JsiSkHostObject : public RNJsi::JsiHostObject { +public: + /** + * Default constructor + * @param context Platform context + */ + explicit JsiSkHostObject(std::shared_ptr context) + : _context(context) {} + +protected: + /** + * @return A pointer to the platform context + */ + std::shared_ptr getContext() { return _context; } + +private: + std::shared_ptr _context; +}; + +#define JSI_API_TYPENAME(A) \ + JSI_PROPERTY_GET(__typename__) { \ + return jsi::String::createFromUtf8(runtime, #A); \ + } + +#define EXPORT_JSI_API_TYPENAME(CLASS, TYPENAME) \ + JSI_API_TYPENAME(TYPENAME) \ + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(CLASS, __typename__)) + +template class JsiSkWrappingHostObject : public JsiSkHostObject { +public: + /** + * Default constructor + * @param context Platform context + */ + JsiSkWrappingHostObject(std::shared_ptr context, + T object) + : JsiSkHostObject(std::move(context)), _object(std::move(object)) {} + + /** + * Returns the underlying object exposed by this host object. This object + * should be wrapped in a shared pointer of some kind + * @return Underlying object + */ + T getObject() { return _object; } + const T getObject() const { return _object; } + + /** + Updates the inner object with a new version of the object. + */ + void setObject(T object) { _object = object; } + + /** + Dispose function that can be exposed to JS by using the JSI_API_TYPENAME + macro + */ + JSI_HOST_FUNCTION(dispose) { + safeDispose(); + return jsi::Value::undefined(); + } + +protected: + /** + Override to implement disposale of allocated resources like smart pointers + etc. This method will only be called once for each instance of this class. + */ + virtual void releaseResources() = 0; + + /** + Throws a runtime error if this method is called after the object has been + disposed. + */ + void ensureNotDisposed() { + if (_isDisposed) { + throw std::runtime_error("API Object accessed after it was disposed"); + } + } + +private: + void safeDispose() { + if (!_isDisposed) { + _isDisposed = true; + releaseResources(); + } + } + + /** + * Wrapped object + */ + T _object; + + /** + Resource disposed flag + */ + std::atomic _isDisposed = {false}; +}; + +template +class JsiSkWrappingSharedPtrHostObject + : public JsiSkWrappingHostObject> { +public: + JsiSkWrappingSharedPtrHostObject(std::shared_ptr context, + std::shared_ptr object) + : JsiSkWrappingHostObject>(std::move(context), + std::move(object)) {} + + /** + Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + return std::static_pointer_cast( + obj.asObject(runtime).asHostObject(runtime)) + ->getObject(); + } + +protected: + void releaseResources() override { + // Clear internally allocated objects + this->setObject(nullptr); + } +}; + +template +class JsiSkWrappingSkPtrHostObject : public JsiSkWrappingHostObject> { +public: + JsiSkWrappingSkPtrHostObject(std::shared_ptr context, + sk_sp object) + : JsiSkWrappingHostObject>(std::move(context), + std::move(object)) {} + + /** + Returns the underlying object from a host object of this type + */ + static sk_sp fromValue(jsi::Runtime &runtime, const jsi::Value &obj) { + return std::static_pointer_cast( + obj.asObject(runtime).asHostObject(runtime)) + ->getObject(); + } + +protected: + void releaseResources() override { + // Clear internally allocated objects + this->setObject(nullptr); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImage.h new file mode 100644 index 00000000000000..9591906ef160b9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImage.h @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkMatrix.h" +#include "JsiSkShader.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBase64.h" +#include "SkImage.h" +#include "SkStream.h" +#include "codec/SkEncodedImageFormat.h" +#include "include/encode/SkJpegEncoder.h" +#include "include/encode/SkPngEncoder.h" + +#pragma clang diagnostic pop + +#include + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkImage : public JsiSkWrappingSkPtrHostObject { +public: + // TODO-API: Properties? + JSI_HOST_FUNCTION(width) { return static_cast(getObject()->width()); } + JSI_HOST_FUNCTION(height) { + return static_cast(getObject()->height()); + } + + JSI_HOST_FUNCTION(makeShaderOptions) { + auto tmx = (SkTileMode)arguments[0].asNumber(); + auto tmy = (SkTileMode)arguments[1].asNumber(); + auto fm = (SkFilterMode)arguments[2].asNumber(); + auto mm = (SkMipmapMode)arguments[3].asNumber(); + auto m = count > 4 && !arguments[4].isUndefined() + ? JsiSkMatrix::fromValue(runtime, arguments[4]).get() + : nullptr; + auto shader = + getObject()->makeShader(tmx, tmy, SkSamplingOptions(fm, mm), m); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(shader))); + } + + JSI_HOST_FUNCTION(makeShaderCubic) { + auto tmx = (SkTileMode)arguments[0].asNumber(); + auto tmy = (SkTileMode)arguments[1].asNumber(); + auto B = SkDoubleToScalar(arguments[2].asNumber()); + auto C = SkDoubleToScalar(arguments[3].asNumber()); + auto m = count > 4 && !arguments[4].isUndefined() + ? JsiSkMatrix::fromValue(runtime, arguments[4]).get() + : nullptr; + auto shader = + getObject()->makeShader(tmx, tmy, SkSamplingOptions({B, C}), m); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(shader))); + } + + JSI_HOST_FUNCTION(encodeToBytes) { + // Get optional parameters + auto format = + count >= 1 ? static_cast(arguments[0].asNumber()) + : SkEncodedImageFormat::kPNG; + auto quality = count == 2 ? arguments[1].asNumber() : 100.0; + + // Get data + sk_sp data; + if (format == SkEncodedImageFormat::kJPEG) { + SkJpegEncoder::Options options; + options.fQuality = quality; + data = SkJpegEncoder::Encode(nullptr, getObject().get(), options); + } else { + SkPngEncoder::Options options; + data = SkPngEncoder::Encode(nullptr, getObject().get(), options); + } + auto arrayCtor = + runtime.global().getPropertyAsFunction(runtime, "Uint8Array"); + size_t size = data->size(); + + jsi::Object array = + arrayCtor.callAsConstructor(runtime, static_cast(size)) + .getObject(runtime); + jsi::ArrayBuffer buffer = + array.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer")) + .asObject(runtime) + .getArrayBuffer(runtime); + + auto bfrPtr = reinterpret_cast(buffer.data(runtime)); + memcpy(bfrPtr, data->bytes(), size); + return array; + } + + JSI_HOST_FUNCTION(encodeToBase64) { + // Get optional parameters + auto format = + count >= 1 ? static_cast(arguments[0].asNumber()) + : SkEncodedImageFormat::kPNG; + + auto quality = count == 2 ? arguments[1].asNumber() : 100.0; + auto image = getObject(); + if (image->isTextureBacked()) { + image = image->makeNonTextureImage(); + } + sk_sp data; + if (format == SkEncodedImageFormat::kJPEG) { + SkJpegEncoder::Options options; + options.fQuality = quality; + data = SkJpegEncoder::Encode(nullptr, image.get(), options); + } else { + SkPngEncoder::Options options; + data = SkPngEncoder::Encode(nullptr, image.get(), options); + } + auto len = SkBase64::Encode(data->bytes(), data->size(), nullptr); + auto buffer = std::string(len, 0); + SkBase64::Encode(data->bytes(), data->size(), + reinterpret_cast(&buffer[0])); + return jsi::String::createFromAscii(runtime, buffer); + } + + JSI_HOST_FUNCTION(makeNonTextureImage) { + auto image = getObject()->makeNonTextureImage(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(image))); + } + + EXPORT_JSI_API_TYPENAME(JsiSkImage, "Image") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImage, width), + JSI_EXPORT_FUNC(JsiSkImage, height), + JSI_EXPORT_FUNC(JsiSkImage, makeShaderOptions), + JSI_EXPORT_FUNC(JsiSkImage, makeShaderCubic), + JSI_EXPORT_FUNC(JsiSkImage, encodeToBytes), + JSI_EXPORT_FUNC(JsiSkImage, encodeToBase64), + JSI_EXPORT_FUNC(JsiSkImage, makeNonTextureImage), + JSI_EXPORT_FUNC(JsiSkImage, dispose)) + + JsiSkImage(std::shared_ptr context, + const sk_sp image) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(image)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFactory.h new file mode 100644 index 00000000000000..2ccb32af0d626d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFactory.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkData.h" +#include "JsiSkHostObjects.h" +#include "JsiSkImage.h" +#include "JsiSkImageInfo.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkImageFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeImageFromEncoded) { + auto data = JsiSkData::fromValue(runtime, arguments[0]); + auto image = SkImages::DeferredFromEncodedData(data); + if (image == nullptr) { + return jsi::Value::null(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(image))); + } + + JSI_HOST_FUNCTION(MakeImage) { + auto imageInfo = JsiSkImageInfo::fromValue(runtime, arguments[0]); + auto pixelData = JsiSkData::fromValue(runtime, arguments[1]); + auto bytesPerRow = arguments[2].asNumber(); + auto image = SkImages::RasterFromData(*imageInfo, pixelData, bytesPerRow); + if (image == nullptr) { + return jsi::Value::null(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(image))); + } + + JSI_HOST_FUNCTION(MakeImageFromViewTag) { + auto viewTag = arguments[0].asNumber(); + auto context = getContext(); + return react::createPromiseAsJSIValue( + runtime, + [context = std::move(context), + viewTag](jsi::Runtime &runtime, + std::shared_ptr promise) -> void { + // Create a stream operation - this will be run on the main thread + context->makeViewScreenshot( + viewTag, [&runtime, context = std::move(context), + promise = std::move(promise)](sk_sp image) { + context->runOnJavascriptThread([&runtime, + context = std::move(context), + promise = std::move(promise), + result = std::move(image)]() { + if (result == nullptr) { + promise->reject("Failed to create image from view tag"); + return; + } + promise->resolve(jsi::Object::createFromHostObject( + runtime, std::make_shared( + std::move(context), std::move(result)))); + }); + }); + }); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromEncoded), + JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromViewTag), + JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage), ) + + explicit JsiSkImageFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFilter.h new file mode 100644 index 00000000000000..1969add100b754 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFilter.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkImageFilters.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkImageFilter : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkImageFilter(std::shared_ptr context, + sk_sp imageFilter) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(imageFilter)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkImageFilter, "ImageFilter") +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFilterFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFilterFactory.h new file mode 100644 index 00000000000000..d9f313fccac6b3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageFilterFactory.h @@ -0,0 +1,240 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkImageFilter.h" +#include "JsiSkRuntimeShaderBuilder.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkImageFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkImageFilterFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeBlur) { + float sigmaX = arguments[0].asNumber(); + float sigmaY = arguments[1].asNumber(); + int tileMode = arguments[2].asNumber(); + sk_sp imageFilter; + if (!arguments[3].isNull()) { + imageFilter = JsiSkImageFilter::fromValue(runtime, arguments[3]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::Blur(sigmaX, sigmaY, (SkTileMode)tileMode, + imageFilter))); + } + + JSI_HOST_FUNCTION(MakeColorFilter) { + auto cf = JsiSkColorFilter::fromValue(runtime, arguments[0]); + sk_sp input; + if (!arguments[1].isNull()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[1]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::ColorFilter( + std::move(cf), std::move(input)))); + } + + JSI_HOST_FUNCTION(MakeOffset) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + sk_sp input; + if (!arguments[2].isNull()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), SkImageFilters::Offset(x, y, std::move(input)))); + } + + JSI_HOST_FUNCTION(MakeDisplacementMap) { + auto fXChannelSelector = + static_cast(arguments[0].asNumber()); + auto fYChannelSelector = + static_cast(arguments[1].asNumber()); + auto scale = arguments[2].asNumber(); + auto in2 = JsiSkImageFilter::fromValue(runtime, arguments[3]); + sk_sp input; + if (!arguments[4].isNull()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[4]); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), SkImageFilters::DisplacementMap( + fXChannelSelector, fYChannelSelector, scale, + std::move(in2), std::move(input)))); + } + + JSI_HOST_FUNCTION(MakeShader) { + auto shader = JsiSkShader::fromValue(runtime, arguments[0]); + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Shader(std::move(shader)))); + } + + JSI_HOST_FUNCTION(MakeCompose) { + sk_sp outer; + if (!arguments[0].isNull() && !arguments[0].isUndefined()) { + outer = JsiSkImageFilter::fromValue(runtime, arguments[0]); + } + sk_sp inner; + if (!arguments[1].isNull() && !arguments[1].isUndefined()) { + inner = JsiSkImageFilter::fromValue(runtime, arguments[1]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Compose(std::move(outer), + std::move(inner)))); + } + + JSI_HOST_FUNCTION(MakeBlend) { + auto mode = static_cast(arguments[0].asNumber()); + sk_sp background = + JsiSkImageFilter::fromValue(runtime, arguments[1]); + sk_sp foreground = nullptr; + + if (count > 2 && !arguments[2].isNull()) { + foreground = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + + SkImageFilters::CropRect cropRect = {}; + if (count > 3 && !arguments[3].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } + + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Blend( + std::move(mode), std::move(background), + std::move(foreground), cropRect))); + } + + JSI_HOST_FUNCTION(MakeDropShadow) { + auto dx = arguments[0].asNumber(); + auto dy = arguments[1].asNumber(); + auto sigmaX = arguments[2].asNumber(); + auto sigmaY = arguments[3].asNumber(); + auto color = JsiSkColor::fromValue(runtime, arguments[4]); + sk_sp input; + if (!arguments[5].isNull() && !arguments[5].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[5]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 6 && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkImageFilters::DropShadow(dx, dy, sigmaX, sigmaY, color, + std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeDropShadowOnly) { + auto dx = arguments[0].asNumber(); + auto dy = arguments[1].asNumber(); + auto sigmaX = arguments[2].asNumber(); + auto sigmaY = arguments[3].asNumber(); + auto color = JsiSkColor::fromValue(runtime, arguments[4]); + sk_sp input; + if (!arguments[5].isNull() && !arguments[5].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[5]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 6 && !arguments[6].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[6]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::DropShadowOnly( + dx, dy, sigmaX, sigmaY, color, + std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeErode) { + auto rx = arguments[0].asNumber(); + auto ry = arguments[1].asNumber(); + sk_sp input; + if (!arguments[2].isNull() && !arguments[2].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 3 && !arguments[3].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Erode( + rx, ry, std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeDilate) { + auto rx = arguments[0].asNumber(); + auto ry = arguments[1].asNumber(); + sk_sp input; + if (!arguments[2].isNull() && !arguments[2].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + SkImageFilters::CropRect cropRect = {}; + if (count > 3 && !arguments[3].isUndefined()) { + cropRect = *JsiSkRect::fromValue(runtime, arguments[3]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::Dilate( + rx, ry, std::move(input), cropRect))); + } + + JSI_HOST_FUNCTION(MakeRuntimeShader) { + auto rtb = JsiSkRuntimeShaderBuilder::fromValue(runtime, arguments[0]); + + const char *childName = ""; + if (!arguments[1].isNull() && !arguments[1].isUndefined()) { + childName = arguments[1].asString(runtime).utf8(runtime).c_str(); + } + + sk_sp input; + if (!arguments[2].isNull() && !arguments[2].isUndefined()) { + input = JsiSkImageFilter::fromValue(runtime, arguments[2]); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkImageFilters::RuntimeShader( + *rtb, childName, std::move(input)))); + } + + JSI_EXPORT_FUNCTIONS( + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlur), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeOffset), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeColorFilter), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeShader), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDisplacementMap), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeCompose), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeErode), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDilate), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlend), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDropShadow), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDropShadowOnly), + JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeRuntimeShader)) + + explicit JsiSkImageFilterFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageInfo.h new file mode 100644 index 00000000000000..150700da3e070d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkImageInfo.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkImageInfo.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkImageInfo : public JsiSkWrappingSharedPtrHostObject { +public: + JsiSkImageInfo(std::shared_ptr context, + const SkImageInfo &imageInfo) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(imageInfo)) {} + + /** + Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + if (object.isHostObject(runtime)) { + return object.asHostObject(runtime)->getObject(); + } else { + auto width = object.getProperty(runtime, "width").asNumber(); + auto height = object.getProperty(runtime, "height").asNumber(); + auto colorType = static_cast( + object.getProperty(runtime, "colorType").asNumber()); + auto alphaType = static_cast( + object.getProperty(runtime, "alphaType").asNumber()); + // TODO: color space not supported yet + return std::make_shared( + SkImageInfo::Make(width, height, colorType, alphaType)); + } + } + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkImageInfo &imageInfo) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), imageInfo)); + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMaskFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMaskFilter.h new file mode 100644 index 00000000000000..664193d3ee83db --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMaskFilter.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkMaskFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkMaskFilter : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkMaskFilter(std::shared_ptr context, + sk_sp maskFilter) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(maskFilter)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkMaskFilter, "MaskFilter") +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMaskFilterFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMaskFilterFactory.h new file mode 100644 index 00000000000000..526d159bcdbc92 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMaskFilterFactory.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkColorFilter.h" +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkMaskFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkMaskFilterFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeBlur) { + int blurStyle = arguments[0].asNumber(); + float sigma = arguments[1].asNumber(); + bool respectCTM = arguments[2].getBool(); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared( + getContext(), + SkMaskFilter::MakeBlur((SkBlurStyle)blurStyle, sigma, respectCTM))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkMaskFilterFactory, MakeBlur)) + + explicit JsiSkMaskFilterFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMatrix.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMatrix.h new file mode 100644 index 00000000000000..262ab87da54aa9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkMatrix.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkMatrix.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkMatrix : public JsiSkWrappingSharedPtrHostObject { +public: + JsiSkMatrix(std::shared_ptr context, SkMatrix m) + : JsiSkWrappingSharedPtrHostObject( + context, std::make_shared(std::move(m))) {} + + static SkMatrix getMatrix(jsi::Runtime &runtime, const jsi::Value &value) { + const auto &object = value.asObject(runtime); + const auto &array = object.asArray(runtime); + auto scaleX = array.getValueAtIndex(runtime, 0).asNumber(); + auto skewX = array.getValueAtIndex(runtime, 1).asNumber(); + auto transX = array.getValueAtIndex(runtime, 2).asNumber(); + auto skewY = array.getValueAtIndex(runtime, 3).asNumber(); + auto scaleY = array.getValueAtIndex(runtime, 4).asNumber(); + auto transY = array.getValueAtIndex(runtime, 5).asNumber(); + auto pers0 = array.getValueAtIndex(runtime, 6).asNumber(); + auto pers1 = array.getValueAtIndex(runtime, 7).asNumber(); + auto pers2 = array.getValueAtIndex(runtime, 8).asNumber(); + return SkMatrix::MakeAll(scaleX, skewX, transX, skewY, scaleY, transY, + pers0, pers1, pers2); + } + + JSI_HOST_FUNCTION(concat) { + auto m3 = JsiSkMatrix::fromValue(runtime, arguments[0]); + getObject()->preConcat(*m3); + return thisValue.asObject(runtime); + } + + JSI_HOST_FUNCTION(translate) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + getObject()->preTranslate(x, y); + return thisValue.asObject(runtime); + } + + JSI_HOST_FUNCTION(scale) { + auto x = arguments[0].asNumber(); + auto y = count > 1 ? arguments[1].asNumber() : 1; + getObject()->preScale(x, y); + return thisValue.asObject(runtime); + } + + JSI_HOST_FUNCTION(skew) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + getObject()->preSkew(x, y); + return thisValue.asObject(runtime); + } + + JSI_HOST_FUNCTION(rotate) { + auto a = arguments[0].asNumber(); + getObject()->preRotate(SkRadiansToDegrees(a)); + return thisValue.asObject(runtime); + } + + JSI_HOST_FUNCTION(identity) { + getObject()->setIdentity(); + return thisValue.asObject(runtime); + } + + JSI_HOST_FUNCTION(get) { + auto values = jsi::Array(runtime, 9); + for (auto i = 0; i < 9; i++) { + values.setValueAtIndex(runtime, i, getObject()->get(i)); + } + return values; + } + + EXPORT_JSI_API_TYPENAME(JsiSkMatrix, "Matrix") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkMatrix, concat), + JSI_EXPORT_FUNC(JsiSkMatrix, translate), + JSI_EXPORT_FUNC(JsiSkMatrix, scale), + JSI_EXPORT_FUNC(JsiSkMatrix, skew), + JSI_EXPORT_FUNC(JsiSkMatrix, rotate), + JSI_EXPORT_FUNC(JsiSkMatrix, identity), + JSI_EXPORT_FUNC(JsiSkMatrix, get), + JSI_EXPORT_FUNC(JsiSkMatrix, dispose)) + + /** + * Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + if (object.isHostObject(runtime)) { + return object.asHostObject(runtime)->getObject(); + } else { + return std::make_shared(JsiSkMatrix::getMatrix(runtime, obj)); + } + } + + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + SkMatrix matrix; + if (count == 1) { + matrix = JsiSkMatrix::getMatrix(runtime, arguments[0]); + } else { + matrix = SkMatrix::I(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), matrix)); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPaint.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPaint.h new file mode 100644 index 00000000000000..fdf54033f5f441 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPaint.h @@ -0,0 +1,213 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkColor.h" +#include "JsiSkColorFilter.h" +#include "JsiSkHostObjects.h" +#include "JsiSkImageFilter.h" +#include "JsiSkMaskFilter.h" +#include "JsiSkPathEffect.h" +#include "JsiSkShader.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPaint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { +namespace jsi = facebook::jsi; + +class JsiSkPaint : public JsiSkWrappingSharedPtrHostObject { +public: + EXPORT_JSI_API_TYPENAME(JsiSkPaint, "Paint") + + JSI_HOST_FUNCTION(copy) { + const auto *paint = getObject().get(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), SkPaint(*paint))); + } + + JSI_HOST_FUNCTION(reset) { + getObject()->reset(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(getColor) { + return JsiSkColor::toValue(runtime, getObject()->getColor()); + } + + JSI_HOST_FUNCTION(getStrokeCap) { + return static_cast(getObject()->getStrokeCap()); + } + + JSI_HOST_FUNCTION(getStrokeJoin) { + return static_cast(getObject()->getStrokeJoin()); + } + + JSI_HOST_FUNCTION(getStrokeMiter) { + return static_cast(getObject()->getStrokeMiter()); + } + + JSI_HOST_FUNCTION(getStrokeWidth) { + return static_cast(getObject()->getStrokeWidth()); + } + + JSI_HOST_FUNCTION(getAlphaf) { + float alphaf = getObject()->getAlphaf(); + return jsi::Value(SkScalarToDouble(alphaf)); + } + + JSI_HOST_FUNCTION(setColor) { + SkColor color = JsiSkColor::fromValue(runtime, arguments[0]); + getObject()->setColor(color); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setAlphaf) { + SkScalar alpha = arguments[0].asNumber(); + getObject()->setAlphaf(alpha); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setAntiAlias) { + bool antiAliased = arguments[0].getBool(); + getObject()->setAntiAlias(antiAliased); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setStrokeWidth) { + SkScalar width = arguments[0].asNumber(); + getObject()->setStrokeWidth(width); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setStyle) { + auto style = arguments[0].asNumber(); + getObject()->setStyle(static_cast(style)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setStrokeCap) { + auto cap = arguments[0].asNumber(); + getObject()->setStrokeCap(static_cast(cap)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setStrokeJoin) { + int join = arguments[0].asNumber(); + getObject()->setStrokeJoin(static_cast(join)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setStrokeMiter) { + int limit = arguments[0].asNumber(); + getObject()->setStrokeMiter(limit); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setBlendMode) { + auto blendMode = (SkBlendMode)arguments[0].asNumber(); + getObject()->setBlendMode(blendMode); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setMaskFilter) { + auto maskFilter = arguments[0].isNull() || arguments[0].isUndefined() + ? nullptr + : JsiSkMaskFilter::fromValue(runtime, arguments[0]); + getObject()->setMaskFilter(std::move(maskFilter)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setImageFilter) { + auto imageFilter = arguments[0].isNull() || arguments[0].isUndefined() + ? nullptr + : JsiSkImageFilter::fromValue(runtime, arguments[0]); + getObject()->setImageFilter(std::move(imageFilter)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setColorFilter) { + auto colorFilter = arguments[0].isNull() || arguments[0].isUndefined() + ? nullptr + : JsiSkColorFilter::fromValue(runtime, arguments[0]); + getObject()->setColorFilter(std::move(colorFilter)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setShader) { + auto shader = arguments[0].isNull() || arguments[0].isUndefined() + ? nullptr + : JsiSkShader::fromValue(runtime, arguments[0]); + getObject()->setShader(std::move(shader)); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setPathEffect) { + auto pathEffect = arguments[0].isNull() || arguments[0].isUndefined() + ? nullptr + : JsiSkPathEffect::fromValue(runtime, arguments[0]); + getObject()->setPathEffect(std::move(pathEffect)); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPaint, copy), + JSI_EXPORT_FUNC(JsiSkPaint, reset), + JSI_EXPORT_FUNC(JsiSkPaint, getAlphaf), + JSI_EXPORT_FUNC(JsiSkPaint, getColor), + JSI_EXPORT_FUNC(JsiSkPaint, getStrokeCap), + JSI_EXPORT_FUNC(JsiSkPaint, getStrokeJoin), + JSI_EXPORT_FUNC(JsiSkPaint, getStrokeMiter), + JSI_EXPORT_FUNC(JsiSkPaint, getStrokeWidth), + JSI_EXPORT_FUNC(JsiSkPaint, setPathEffect), + JSI_EXPORT_FUNC(JsiSkPaint, setShader), + JSI_EXPORT_FUNC(JsiSkPaint, setColorFilter), + JSI_EXPORT_FUNC(JsiSkPaint, setImageFilter), + JSI_EXPORT_FUNC(JsiSkPaint, setMaskFilter), + JSI_EXPORT_FUNC(JsiSkPaint, setBlendMode), + JSI_EXPORT_FUNC(JsiSkPaint, setStrokeMiter), + JSI_EXPORT_FUNC(JsiSkPaint, setStrokeJoin), + JSI_EXPORT_FUNC(JsiSkPaint, setStrokeCap), + JSI_EXPORT_FUNC(JsiSkPaint, setAntiAlias), + JSI_EXPORT_FUNC(JsiSkPaint, setStrokeWidth), + JSI_EXPORT_FUNC(JsiSkPaint, setStyle), + JSI_EXPORT_FUNC(JsiSkPaint, setColor), + JSI_EXPORT_FUNC(JsiSkPaint, setAlphaf), + JSI_EXPORT_FUNC(JsiSkPaint, dispose)) + + JsiSkPaint(std::shared_ptr context, SkPaint paint) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(std::move(paint))) {} + + /** + Copy from another paint + */ + void fromPaint(const SkPaint &paint) { + setObject(std::make_shared(std::move(paint))); + } + + /** + * Creates the function for construction a new instance of the SkPaint + * wrapper + * @param context Platform context + * @return A function for creating a new host object wrapper for the SkPaint + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto paint = SkPaint(); + paint.setAntiAlias(true); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), paint)); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPath.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPath.h new file mode 100644 index 00000000000000..7938ca885f3834 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPath.h @@ -0,0 +1,584 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkMatrix.h" +#include "JsiSkPoint.h" +#include "JsiSkRRect.h" +#include "JsiSkRect.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkDashPathEffect.h" +#include "SkParsePath.h" +#include "SkPath.h" +#include "SkPathEffect.h" +#include "SkPathOps.h" +#include "SkPathTypes.h" +#include "SkPathUtils.h" +#include "SkString.h" +#include "SkStrokeRec.h" +#include "SkTextUtils.h" +#include "SkTrimPathEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPath : public JsiSkWrappingSharedPtrHostObject { + +public: + JSI_HOST_FUNCTION(addPath) { + auto src = JsiSkPath::fromValue(runtime, arguments[0]); + auto matrix = + count > 1 && !arguments[1].isUndefined() && !arguments[1].isNull() + ? JsiSkMatrix::fromValue(runtime, arguments[1]) + : nullptr; + auto mode = count > 2 && arguments[2].isBool() && arguments[2].getBool() + ? SkPath::kExtend_AddPathMode + : SkPath::kAppend_AddPathMode; + if (matrix == nullptr) { + getObject()->addPath(*src, mode); + } else { + getObject()->addPath(*src, *matrix, mode); + } + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(addArc) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto start = arguments[1].asNumber(); + auto sweep = arguments[2].asNumber(); + getObject()->addArc(*rect, start, sweep); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(addOval) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto direction = SkPathDirection::kCW; + if (count >= 2 && arguments[1].getBool()) { + direction = SkPathDirection::kCCW; + } + unsigned startIndex = count < 3 ? 0 : arguments[2].asNumber(); + auto result = getObject()->addOval(*rect, direction, startIndex); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(addPoly) { + std::vector points; + auto jsiPoints = arguments[0].asObject(runtime).asArray(runtime); + auto close = arguments[1].getBool(); + auto pointsSize = jsiPoints.size(runtime); + points.reserve(pointsSize); + for (int i = 0; i < pointsSize; i++) { + std::shared_ptr point = JsiSkPoint::fromValue( + runtime, jsiPoints.getValueAtIndex(runtime, i).asObject(runtime)); + points.push_back(*point.get()); + } + getObject()->addPoly(points.data(), static_cast(points.size()), close); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(addRect) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto direction = SkPathDirection::kCW; + if (count >= 2 && arguments[1].getBool()) { + direction = SkPathDirection::kCCW; + } + getObject()->addRect(*rect, direction); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(addRRect) { + auto rrect = JsiSkRRect::fromValue(runtime, arguments[0]); + auto direction = SkPathDirection::kCW; + if (count >= 2 && arguments[1].getBool()) { + direction = SkPathDirection::kCCW; + } + getObject()->addRRect(*rrect, direction); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(arcToOval) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + auto start = arguments[1].asNumber(); + auto sweep = arguments[2].asNumber(); + auto forceMoveTo = arguments[3].getBool(); + getObject()->arcTo(*rect, start, sweep, forceMoveTo); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(arcToRotated) { + auto rx = arguments[0].asNumber(); + auto ry = arguments[1].asNumber(); + auto xAxisRotate = arguments[2].asNumber(); + auto useSmallArc = arguments[3].getBool(); + auto arcSize = useSmallArc ? SkPath::ArcSize::kSmall_ArcSize + : SkPath::ArcSize::kLarge_ArcSize; + auto sweep = + arguments[4].getBool() ? SkPathDirection::kCCW : SkPathDirection::kCW; + auto x = arguments[5].asNumber(); + auto y = arguments[6].asNumber(); + getObject()->arcTo(rx, ry, xAxisRotate, arcSize, sweep, x, y); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(rArcTo) { + auto rx = arguments[0].asNumber(); + auto ry = arguments[1].asNumber(); + auto xAxisRotate = arguments[2].asNumber(); + auto useSmallArc = arguments[3].getBool(); + auto arcSize = useSmallArc ? SkPath::ArcSize::kSmall_ArcSize + : SkPath::ArcSize::kLarge_ArcSize; + auto sweep = + arguments[4].getBool() ? SkPathDirection::kCCW : SkPathDirection::kCW; + auto x = arguments[5].asNumber(); + auto y = arguments[6].asNumber(); + getObject()->rArcTo(rx, ry, xAxisRotate, arcSize, sweep, x, y); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(arcToTangent) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + auto r = arguments[4].asNumber(); + getObject()->arcTo(x1, y1, x2, y2, r); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(computeTightBounds) { + auto result = getObject()->computeTightBounds(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(result))); + } + + // TODO-API: Should this be a property? + JSI_HOST_FUNCTION(getBounds) { + auto result = getObject()->getBounds(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(result))); + } + + JSI_HOST_FUNCTION(conicTo) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + auto w = arguments[4].asNumber(); + getObject()->conicTo(x1, y1, x2, y2, w); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(rConicTo) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + auto w = arguments[4].asNumber(); + getObject()->rConicTo(x1, y1, x2, y2, w); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(contains) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + return jsi::Value(getObject()->contains(x, y)); + } + + JSI_HOST_FUNCTION(dash) { + SkScalar on = arguments[0].asNumber(); + SkScalar off = arguments[1].asNumber(); + auto phase = arguments[2].asNumber(); + SkScalar intervals[] = {on, off}; + auto pe = SkDashPathEffect::Make(intervals, 2, phase); + if (!pe) { + // TODO: SkDebugf("Invalid args to dash()\n"); + return jsi::Value(false); + } + SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle); + SkPath &path = *getObject(); + // TODO: why we don't need to swap here? In trim() which is the same + // API, we need to swap + if (pe->filterPath(&path, path, &rec, nullptr)) { + return jsi::Value(true); + } + SkDebugf("Could not make dashed path\n"); + return jsi::Value(false); + } + + JSI_HOST_FUNCTION(equals) { + auto p1 = JsiSkPath::fromValue(runtime, arguments[0]).get(); + auto p2 = JsiSkPath::fromValue(runtime, arguments[1]).get(); + return jsi::Value(p1 == p2); + } + + // TODO-API: Property? + JSI_HOST_FUNCTION(getFillType) { + auto fillType = getObject()->getFillType(); + return jsi::Value(static_cast(fillType)); + } + + // TODO-API: Property? + JSI_HOST_FUNCTION(setFillType) { + auto ft = (SkPathFillType)arguments[0].asNumber(); + getObject()->setFillType(ft); + return jsi::Value::undefined(); + } + + // TODO-API: Property? + JSI_HOST_FUNCTION(setIsVolatile) { + auto v = arguments[0].getBool(); + getObject()->setIsVolatile(v); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(isVolatile) { + return jsi::Value(getObject()->isVolatile()); + } + + JSI_HOST_FUNCTION(transform) { + auto m3 = *JsiSkMatrix::fromValue(runtime, arguments[0]); + getObject()->transform(m3); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(stroke) { + auto path = *getObject(); + auto opts = arguments[0].asObject(runtime); + SkPaint p; + p.setStyle(SkPaint::kStroke_Style); + + auto jsiCap = opts.getProperty(runtime, "cap"); + if (!jsiCap.isUndefined()) { + auto cap = (SkPaint::Cap)jsiCap.asNumber(); + p.setStrokeCap(cap); + } + + auto jsiJoin = opts.getProperty(runtime, "join"); + if (!jsiJoin.isUndefined()) { + auto join = (SkPaint::Join)jsiJoin.asNumber(); + p.setStrokeJoin(join); + } + + auto jsiWidth = opts.getProperty(runtime, "width"); + if (!jsiWidth.isUndefined()) { + auto width = jsiWidth.asNumber(); + p.setStrokeWidth(width); + } + + auto jsiMiterLimit = opts.getProperty(runtime, "miter_limit"); + if (!jsiMiterLimit.isUndefined()) { + auto miter_limit = opts.getProperty(runtime, "miter_limit").asNumber(); + p.setStrokeMiter(miter_limit); + } + + auto jsiPrecision = opts.getProperty(runtime, "precision"); + auto precision = jsiPrecision.isUndefined() ? 1 : jsiPrecision.asNumber(); + auto result = + skpathutils::FillPathWithPaint(path, p, &path, nullptr, precision); + if (result) { + getObject()->swap(path); + } + return result ? thisValue.getObject(runtime) : jsi::Value::null(); + } + + JSI_HOST_FUNCTION(trim) { + auto start = arguments[0].asNumber(); + auto end = arguments[1].asNumber(); + auto isComplement = arguments[2].getBool(); + auto path = *getObject(); + auto mode = isComplement ? SkTrimPathEffect::Mode::kInverted + : SkTrimPathEffect::Mode::kNormal; + auto pe = SkTrimPathEffect::Make(start, end, mode); + if (!pe) { + // SkDebugf("Invalid args to trim(): startT and stopT must be in + // [0,1]\n"); + return jsi::Value::null(); + } + SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle); + if (pe->filterPath(&path, path, &rec, nullptr)) { + getObject()->swap(path); + return thisValue.getObject(runtime); + } + SkDebugf("Could not trim path\n"); + return jsi::Value::null(); + } + + JSI_HOST_FUNCTION(getPoint) { + auto index = arguments[0].asNumber(); + auto point = getObject()->getPoint(index); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), point)); + } + + JSI_HOST_FUNCTION(toSVGString) { + SkPath path = *getObject(); + auto s = SkParsePath::ToSVGString(path); + return jsi::String::createFromUtf8(runtime, s.c_str()); + } + + JSI_HOST_FUNCTION(makeAsWinding) { + SkPath out; + if (AsWinding(*getObject(), &out)) { + getObject()->swap(out); + return thisValue.getObject(runtime); + } + return jsi::Value::null(); + } + + JSI_HOST_FUNCTION(isEmpty) { return jsi::Value(getObject()->isEmpty()); } + + JSI_HOST_FUNCTION(offset) { + SkScalar dx = arguments[0].asNumber(); + SkScalar dy = arguments[1].asNumber(); + getObject()->offset(dx, dy); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(moveTo) { + SkScalar x = arguments[0].asNumber(); + SkScalar y = arguments[1].asNumber(); + getObject()->moveTo(x, y); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(rMoveTo) { + SkScalar x = arguments[0].asNumber(); + SkScalar y = arguments[1].asNumber(); + getObject()->rMoveTo(x, y); + return thisValue.getObject(runtime); + } + JSI_HOST_FUNCTION(lineTo) { + SkScalar x = arguments[0].asNumber(); + SkScalar y = arguments[1].asNumber(); + getObject()->lineTo(x, y); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(rLineTo) { + SkScalar x = arguments[0].asNumber(); + SkScalar y = arguments[1].asNumber(); + getObject()->rLineTo(x, y); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(cubicTo) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + auto x3 = arguments[4].asNumber(); + auto y3 = arguments[5].asNumber(); + getObject()->cubicTo(x1, y1, x2, y2, x3, y3); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(rCubicTo) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + auto x3 = arguments[4].asNumber(); + auto y3 = arguments[5].asNumber(); + getObject()->rCubicTo(x1, y1, x2, y2, x3, y3); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(reset) { + getObject()->reset(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(rewind) { + getObject()->rewind(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(quadTo) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + getObject()->quadTo(x1, y1, x2, y2); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(rQuadTo) { + auto x1 = arguments[0].asNumber(); + auto y1 = arguments[1].asNumber(); + auto x2 = arguments[2].asNumber(); + auto y2 = arguments[3].asNumber(); + getObject()->rQuadTo(x1, y1, x2, y2); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(addCircle) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + auto r = arguments[2].asNumber(); + getObject()->addCircle(x, y, r); + return thisValue.getObject(runtime); + } + + JSI_HOST_FUNCTION(getLastPt) { + SkPoint last; + getObject()->getLastPt(&last); + auto point = jsi::Object(runtime); + point.setProperty(runtime, "x", static_cast(last.fX)); + point.setProperty(runtime, "y", static_cast(last.fY)); + return point; + } + + JSI_HOST_FUNCTION(close) { + getObject()->close(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(simplify) { + SkPath result; + if (Simplify(*getObject(), &result)) { + getObject()->swap(result); + return jsi::Value(true); + } + return jsi::Value(false); + } + + JSI_HOST_FUNCTION(countPoints) { + auto points = getObject()->countPoints(); + return jsi::Value(points); + } + + JSI_HOST_FUNCTION(copy) { + const auto *path = getObject().get(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), SkPath(*path))); + } + + JSI_HOST_FUNCTION(op) { + auto path2 = JsiSkPath::fromValue(runtime, arguments[0]); + int pathOp = arguments[1].asNumber(); + SkPath result; + if (Op(*getObject(), *path2, SkPathOp(pathOp), &result)) { + getObject()->swap(result); + return jsi::Value(true); + } + return jsi::Value(false); + } + + JSI_HOST_FUNCTION(isInterpolatable) { + auto path2 = JsiSkPath::fromValue(runtime, arguments[0]); + return getObject()->isInterpolatable(*path2); + } + + JSI_HOST_FUNCTION(interpolate) { + auto path2 = JsiSkPath::fromValue(runtime, arguments[0]); + auto weight = arguments[1].asNumber(); + SkPath result; + auto succeed = getObject()->interpolate(*path2, weight, &result); + if (!succeed) { + return nullptr; + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(result))); + } + + JSI_HOST_FUNCTION(toCmds) { + auto path = *getObject(); + auto cmds = jsi::Array(runtime, path.countVerbs()); + auto it = SkPath::Iter(path, false); + // { "Move", "Line", "Quad", "Conic", "Cubic", + // "Close", "Done" }; + const int pointCount[] = {1, 1, 2, 2, 3, 0, 0}; + const int cmdCount[] = {3, 3, 5, 6, 7, 1, 0}; + SkPoint points[4]; + SkPath::Verb verb; + auto k = 0; + while (SkPath::kDone_Verb != (verb = it.next(points))) { + auto verbVal = static_cast(verb); + auto cmd = jsi::Array(runtime, cmdCount[verbVal]); + auto j = 0; + cmd.setValueAtIndex(runtime, j++, jsi::Value(verbVal)); + for (int i = 0; i < pointCount[verbVal]; ++i) { + cmd.setValueAtIndex(runtime, j++, + jsi::Value(static_cast(points[1 + i].fX))); + cmd.setValueAtIndex(runtime, j++, + jsi::Value(static_cast(points[1 + i].fY))); + } + if (SkPath::kConic_Verb == verb) { + cmd.setValueAtIndex(runtime, j, + jsi::Value(static_cast(it.conicWeight()))); + } + cmds.setValueAtIndex(runtime, k++, cmd); + } + return cmds; + } + + EXPORT_JSI_API_TYPENAME(JsiSkPath, "Path") + + JSI_EXPORT_FUNCTIONS( + JSI_EXPORT_FUNC(JsiSkPath, addPath), JSI_EXPORT_FUNC(JsiSkPath, addArc), + JSI_EXPORT_FUNC(JsiSkPath, addOval), JSI_EXPORT_FUNC(JsiSkPath, addPoly), + JSI_EXPORT_FUNC(JsiSkPath, addRect), JSI_EXPORT_FUNC(JsiSkPath, addRRect), + JSI_EXPORT_FUNC(JsiSkPath, arcToOval), + JSI_EXPORT_FUNC(JsiSkPath, arcToRotated), + JSI_EXPORT_FUNC(JsiSkPath, rArcTo), + JSI_EXPORT_FUNC(JsiSkPath, arcToTangent), + JSI_EXPORT_FUNC(JsiSkPath, computeTightBounds), + JSI_EXPORT_FUNC(JsiSkPath, getBounds), + JSI_EXPORT_FUNC(JsiSkPath, conicTo), JSI_EXPORT_FUNC(JsiSkPath, rConicTo), + JSI_EXPORT_FUNC(JsiSkPath, contains), JSI_EXPORT_FUNC(JsiSkPath, dash), + JSI_EXPORT_FUNC(JsiSkPath, equals), + JSI_EXPORT_FUNC(JsiSkPath, getFillType), + JSI_EXPORT_FUNC(JsiSkPath, setFillType), + JSI_EXPORT_FUNC(JsiSkPath, setIsVolatile), + JSI_EXPORT_FUNC(JsiSkPath, isVolatile), + JSI_EXPORT_FUNC(JsiSkPath, transform), JSI_EXPORT_FUNC(JsiSkPath, stroke), + JSI_EXPORT_FUNC(JsiSkPath, trim), JSI_EXPORT_FUNC(JsiSkPath, getPoint), + JSI_EXPORT_FUNC(JsiSkPath, toSVGString), + JSI_EXPORT_FUNC(JsiSkPath, makeAsWinding), + JSI_EXPORT_FUNC(JsiSkPath, isEmpty), JSI_EXPORT_FUNC(JsiSkPath, offset), + JSI_EXPORT_FUNC(JsiSkPath, moveTo), JSI_EXPORT_FUNC(JsiSkPath, rMoveTo), + JSI_EXPORT_FUNC(JsiSkPath, lineTo), JSI_EXPORT_FUNC(JsiSkPath, rLineTo), + JSI_EXPORT_FUNC(JsiSkPath, cubicTo), JSI_EXPORT_FUNC(JsiSkPath, rCubicTo), + JSI_EXPORT_FUNC(JsiSkPath, reset), JSI_EXPORT_FUNC(JsiSkPath, rewind), + JSI_EXPORT_FUNC(JsiSkPath, quadTo), JSI_EXPORT_FUNC(JsiSkPath, rQuadTo), + JSI_EXPORT_FUNC(JsiSkPath, addCircle), + JSI_EXPORT_FUNC(JsiSkPath, getLastPt), JSI_EXPORT_FUNC(JsiSkPath, close), + JSI_EXPORT_FUNC(JsiSkPath, simplify), + JSI_EXPORT_FUNC(JsiSkPath, countPoints), JSI_EXPORT_FUNC(JsiSkPath, copy), + JSI_EXPORT_FUNC(JsiSkPath, op), + JSI_EXPORT_FUNC(JsiSkPath, isInterpolatable), + JSI_EXPORT_FUNC(JsiSkPath, interpolate), + JSI_EXPORT_FUNC(JsiSkPath, toCmds), JSI_EXPORT_FUNC(JsiSkPath, dispose)) + + JsiSkPath(std::shared_ptr context, SkPath path) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(std::move(path))) {} + + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkPath &path) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), path)); + } + + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + SkPath &&path) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), std::move(path))); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathEffect.h new file mode 100644 index 00000000000000..925dd464419460 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathEffect.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPathEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPathEffect : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkPathEffect(std::shared_ptr context, + sk_sp pathEffect) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(pathEffect)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkPathEffect, "PathEffect") + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkColorFilter, dispose)) +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathEffectFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathEffectFactory.h new file mode 100644 index 00000000000000..8ed945462ae389 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathEffectFactory.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkPathEffect.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCornerPathEffect.h" +#include "SkDashPathEffect.h" +#include "SkDiscretePathEffect.h" +#include "SkPathEffect.h" +#include "include/effects/Sk1DPathEffect.h" +#include "include/effects/Sk2DPathEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPathEffectFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeCorner) { + int radius = arguments[0].asNumber(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkCornerPathEffect::Make(radius))); + } + + JSI_HOST_FUNCTION(MakeDash) { + auto jsiIntervals = arguments[0].asObject(runtime).asArray(runtime); + auto size = static_cast(jsiIntervals.size(runtime)); + std::vector intervals; + intervals.reserve(size); + for (int i = 0; i < size; i++) { + SkScalar interval = jsiIntervals.getValueAtIndex(runtime, i).asNumber(); + intervals.push_back(interval); + } + int phase = + count >= 2 && !arguments[1].isUndefined() && !arguments[1].isNull() + ? arguments[1].asNumber() + : 0; + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkDashPathEffect::Make(intervals.data(), size, phase))); + } + + JSI_HOST_FUNCTION(MakeDiscrete) { + int segLength = arguments[0].asNumber(); + int dec = arguments[1].asNumber(); + int seedAssist = arguments[2].asNumber(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkDiscretePathEffect::Make(segLength, dec, seedAssist))); + } + + JSI_HOST_FUNCTION(MakeCompose) { + auto outer = JsiSkPathEffect::fromValue(runtime, arguments[0]); + auto inner = JsiSkPathEffect::fromValue(runtime, arguments[1]); + + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkPathEffect::MakeCompose( + std::move(outer), std::move(inner)))); + } + + JSI_HOST_FUNCTION(MakeSum) { + auto outer = JsiSkPathEffect::fromValue(runtime, arguments[0]); + auto inner = JsiSkPathEffect::fromValue(runtime, arguments[1]); + + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkPathEffect::MakeSum(std::move(outer), + std::move(inner)))); + } + + JSI_HOST_FUNCTION(MakePath1D) { + auto path = JsiSkPath::fromValue(runtime, arguments[0]); + auto advance = arguments[1].asNumber(); + auto phase = arguments[2].asNumber(); + auto style = + static_cast(arguments[3].asNumber()); + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), + SkPath1DPathEffect::Make(*path, advance, phase, style))); + } + + JSI_HOST_FUNCTION(MakePath2D) { + auto matrix = JsiSkMatrix::fromValue(runtime, arguments[0]); + auto path = JsiSkPath::fromValue(runtime, arguments[1]); + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkPath2DPathEffect::Make(*matrix, *path))); + } + + JSI_HOST_FUNCTION(MakeLine2D) { + auto width = arguments[0].asNumber(); + auto matrix = JsiSkMatrix::fromValue(runtime, arguments[1]); + + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + getContext(), SkLine2DPathEffect::Make(width, *matrix))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakeCorner), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakeDash), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakeDiscrete), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakeCompose), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakeSum), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakeLine2D), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakePath1D), + JSI_EXPORT_FUNC(JsiSkPathEffectFactory, MakePath2D), ) + + explicit JsiSkPathEffectFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathFactory.h new file mode 100644 index 00000000000000..143ef95bffaa41 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPathFactory.h @@ -0,0 +1,173 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkPathEffect.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "RNSkLog.h" +#include "SkPath.h" +#include "SkPathOps.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPathFactory : public JsiSkHostObject { + + static const int MOVE = 0; + static const int LINE = 1; + static const int QUAD = 2; + static const int CONIC = 3; + static const int CUBIC = 4; + static const int CLOSE = 5; + +public: + JSI_HOST_FUNCTION(Make) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), SkPath())); + } + + JSI_HOST_FUNCTION(MakeFromSVGString) { + auto svgString = arguments[0].asString(runtime).utf8(runtime); + SkPath result; + + if (!SkParsePath::FromSVGString(svgString.c_str(), &result)) { + throw jsi::JSError(runtime, "Could not parse Svg path"); + return jsi::Value(nullptr); + } + + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(result))); + } + + JSI_HOST_FUNCTION(MakeFromOp) { + SkPath one = *JsiSkPath::fromValue(runtime, arguments[0]).get(); + SkPath two = *JsiSkPath::fromValue(runtime, arguments[1]).get(); + SkPathOp op = (SkPathOp)arguments[2].asNumber(); + SkPath result; + bool success = Op(one, two, op, &result); + if (!success) { + return jsi::Value(nullptr); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(result))); + } + + JSI_HOST_FUNCTION(MakeFromCmds) { + SkPath path; + auto cmds = arguments[0].asObject(runtime).asArray(runtime); + auto cmdCount = cmds.size(runtime); + for (int i = 0; i < cmdCount; i++) { + auto cmd = + cmds.getValueAtIndex(runtime, i).asObject(runtime).asArray(runtime); + if (cmd.size(runtime) < 1) { + RNSkLogger::logToConsole("Invalid command found (got an empty array)"); + return jsi::Value::null(); + } + auto verb = static_cast(cmd.getValueAtIndex(runtime, 0).asNumber()); + switch (verb) { + case MOVE: { + if (cmd.size(runtime) < 3) { + RNSkLogger::logToConsole("Invalid move command found"); + return jsi::Value::null(); + } + auto x = cmd.getValueAtIndex(runtime, 1).asNumber(); + auto y = cmd.getValueAtIndex(runtime, 2).asNumber(); + path.moveTo(x, y); + break; + } + case LINE: { + if (cmd.size(runtime) < 3) { + RNSkLogger::logToConsole("Invalid line command found"); + return jsi::Value::null(); + } + auto x = cmd.getValueAtIndex(runtime, 1).asNumber(); + auto y = cmd.getValueAtIndex(runtime, 2).asNumber(); + path.lineTo(x, y); + break; + } + case QUAD: { + if (cmd.size(runtime) < 5) { + RNSkLogger::logToConsole("Invalid line command found"); + return jsi::Value::null(); + } + auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber(); + auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber(); + auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber(); + auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber(); + path.quadTo(x1, y1, x2, y2); + break; + } + case CONIC: { + if (cmd.size(runtime) < 6) { + RNSkLogger::logToConsole("Invalid line command found"); + return jsi::Value::null(); + } + auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber(); + auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber(); + auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber(); + auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber(); + auto w = cmd.getValueAtIndex(runtime, 5).asNumber(); + path.conicTo(x1, y1, x2, y2, w); + break; + } + case CUBIC: { + if (cmd.size(runtime) < 7) { + RNSkLogger::logToConsole("Invalid line command found"); + return jsi::Value::null(); + } + auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber(); + auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber(); + auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber(); + auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber(); + auto x3 = cmd.getValueAtIndex(runtime, 5).asNumber(); + auto y3 = cmd.getValueAtIndex(runtime, 6).asNumber(); + path.cubicTo(x1, y1, x2, y2, x3, y3); + break; + } + case CLOSE: { + path.close(); + break; + } + default: { + RNSkLogger::logToConsole("Found an unknown command"); + return jsi::Value::null(); + } + } + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(path))); + } + + JSI_HOST_FUNCTION(MakeFromText) { + auto text = arguments[0].asString(runtime).utf8(runtime); + auto x = arguments[1].asNumber(); + auto y = arguments[2].asNumber(); + auto font = JsiSkFont::fromValue(runtime, arguments[3]); + SkPath path; + SkTextUtils::GetPath(text.c_str(), strlen(text.c_str()), + SkTextEncoding::kUTF8, x, y, *font, &path); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(path))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPathFactory, Make), + JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromSVGString), + JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromOp), + JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromCmds), + JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromText)) + + explicit JsiSkPathFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPicture.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPicture.h new file mode 100644 index 00000000000000..1c375e0fe53c98 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPicture.h @@ -0,0 +1,69 @@ +#pragma once + +#include + +#include "JsiSkData.h" +#include "JsiSkHostObjects.h" +#include "JsiSkShader.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPicture.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPicture : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkPicture(std::shared_ptr context, + const sk_sp picture) + : JsiSkWrappingSkPtrHostObject(context, picture) {} + + JSI_HOST_FUNCTION(makeShader) { + auto tmx = (SkTileMode)arguments[0].asNumber(); + auto tmy = (SkTileMode)arguments[1].asNumber(); + auto fm = (SkFilterMode)arguments[2].asNumber(); + auto m = count > 3 && !arguments[3].isUndefined() + ? JsiSkMatrix::fromValue(runtime, arguments[3]).get() + : nullptr; + + auto tr = count > 4 && !arguments[4].isUndefined() + ? JsiSkRect::fromValue(runtime, arguments[4]).get() + : nullptr; + + // Create shader + auto shader = getObject()->makeShader(tmx, tmy, fm, m, tr); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), shader)); + } + + JSI_HOST_FUNCTION(serialize) { + auto data = getObject()->serialize(); + auto arrayCtor = + runtime.global().getPropertyAsFunction(runtime, "Uint8Array"); + size_t size = data->size(); + + jsi::Object array = + arrayCtor.callAsConstructor(runtime, static_cast(size)) + .getObject(runtime); + jsi::ArrayBuffer buffer = + array.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer")) + .asObject(runtime) + .getArrayBuffer(runtime); + + auto bfrPtr = reinterpret_cast(buffer.data(runtime)); + memcpy(bfrPtr, data->bytes(), size); + return array; + } + + EXPORT_JSI_API_TYPENAME(JsiSkPicture, "Picture") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPicture, makeShader), + JSI_EXPORT_FUNC(JsiSkPicture, serialize), + JSI_EXPORT_FUNC(JsiSkPicture, dispose)) +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPictureFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPictureFactory.h new file mode 100644 index 00000000000000..ae8ad96475ec83 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPictureFactory.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "JsiSkColorFilter.h" +#include "JsiSkData.h" +#include "JsiSkHostObjects.h" +#include "JsiSkPicture.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkData.h" +#include "SkPicture.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPictureFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakePicture) { + if (!arguments[0].isObject()) { + throw jsi::JSError(runtime, "Expected arraybuffer as first parameter"); + } + auto array = arguments[0].asObject(runtime); + jsi::ArrayBuffer buffer = + array.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer")) + .asObject(runtime) + .getArrayBuffer(runtime); + + sk_sp data = + SkData::MakeWithCopy(buffer.data(runtime), buffer.size(runtime)); + auto picture = SkPicture::MakeFromData(data.get()); + if (picture != nullptr) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), picture)); + } else { + return jsi::Value::undefined(); + } + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPictureFactory, MakePicture)) + + explicit JsiSkPictureFactory(std::shared_ptr context) + : JsiSkHostObject(context) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPictureRecorder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPictureRecorder.h new file mode 100644 index 00000000000000..fc8601020595f7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPictureRecorder.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include "JsiSkCanvas.h" +#include "JsiSkHostObjects.h" +#include "JsiSkPicture.h" +#include "JsiSkRect.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBBHFactory.h" +#include "SkPictureRecorder.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPictureRecorder + : public JsiSkWrappingSharedPtrHostObject { +public: + explicit JsiSkPictureRecorder(std::shared_ptr context) + : JsiSkWrappingSharedPtrHostObject( + context, std::make_shared()) {} + + JSI_HOST_FUNCTION(beginRecording) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + SkRTreeFactory factory; + auto canvas = getObject()->beginRecording(*rect, &factory); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), canvas)); + } + + JSI_HOST_FUNCTION(finishRecordingAsPicture) { + auto picture = getObject()->finishRecordingAsPicture(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), picture)); + } + + EXPORT_JSI_API_TYPENAME(JsiSkPictureRecorder, "PictureRecorder") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPictureRecorder, beginRecording), + JSI_EXPORT_FUNC(JsiSkPictureRecorder, + finishRecordingAsPicture), + JSI_EXPORT_FUNC(JsiSkPictureRecorder, dispose)) + + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(context)); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPoint.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPoint.h new file mode 100644 index 00000000000000..d14593d93992c2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkPoint.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPoint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkPoint : public JsiSkWrappingSharedPtrHostObject { +public: + JSI_PROPERTY_GET(x) { return static_cast(getObject()->x()); } + + JSI_PROPERTY_GET(y) { return static_cast(getObject()->y()); } + + JSI_API_TYPENAME("Point"); + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkPoint, x), + JSI_EXPORT_PROP_GET(JsiSkPoint, y), + JSI_EXPORT_PROP_GET(JsiSkPoint, __typename__)) + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPoint, dispose)) + + JsiSkPoint(std::shared_ptr context, const SkPoint &point) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(point)) {} + + /** + Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + if (object.isHostObject(runtime)) { + return object.asHostObject(runtime)->getObject(); + } else { + auto x = object.getProperty(runtime, "x").asNumber(); + auto y = object.getProperty(runtime, "y").asNumber(); + return std::make_shared(SkPoint::Make(x, y)); + } + } + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkPoint &point) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), point)); + } + + /** + * Creates the function for construction a new instance of the SkPoint + * wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the SkPoint + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto point = + SkPoint::Make(arguments[0].asNumber(), arguments[1].asNumber()); + + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), std::move(point))); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRRect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRRect.h new file mode 100644 index 00000000000000..b77c48a683592b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRRect.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRRect.h" + +#include "JsiSkRect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkRRect : public JsiSkWrappingSharedPtrHostObject { +public: + JSI_PROPERTY_GET(rx) { + return static_cast(getObject()->getSimpleRadii().x()); + } + JSI_PROPERTY_GET(ry) { + return static_cast(getObject()->getSimpleRadii().y()); + } + JSI_PROPERTY_GET(rect) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), getObject()->getBounds())); + } + + JSI_API_TYPENAME("RRect"); + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkRRect, rx), + JSI_EXPORT_PROP_GET(JsiSkRRect, ry), + JSI_EXPORT_PROP_GET(JsiSkRRect, rect), + JSI_EXPORT_PROP_GET(JsiSkRRect, __typename__)) + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkRRect, dispose)) + + JsiSkRRect(std::shared_ptr context, const SkRRect &rect) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(rect)) {} + + /** + Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + + const auto &object = obj.asObject(runtime); + if (object.isHostObject(runtime)) { + return obj.asObject(runtime) + .asHostObject(runtime) + ->getObject(); + } else { + auto rect = + JsiSkRect::fromValue(runtime, object.getProperty(runtime, "rect")); + auto rx = object.getProperty(runtime, "rx").asNumber(); + auto ry = object.getProperty(runtime, "ry").asNumber(); + return std::make_shared(SkRRect::MakeRectXY(*rect, rx, ry)); + } + } + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkRRect &rect) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), rect)); + } + + /** + * Creates the function for construction a new instance of the SkRect + * wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the SkRect + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + // Set up the rect + auto rect = JsiSkRect::fromValue(runtime, arguments[0]).get(); + auto rx = arguments[1].asNumber(); + auto ry = arguments[2].asNumber(); + auto rrect = SkRRect::MakeRectXY(*rect, rx, ry); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), std::move(rrect))); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRSXform.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRSXform.h new file mode 100644 index 00000000000000..2d4e69092fcc3a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRSXform.h @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRSXform.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkRSXform : public JsiSkWrappingSharedPtrHostObject { +public: + JsiSkRSXform(std::shared_ptr context, + const SkRSXform &rsxform) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(rsxform)) {} + + JSI_API_TYPENAME("RSXform"); + + JSI_PROPERTY_GET(scos) { + return jsi::Value(SkScalarToDouble(getObject()->fSCos)); + } + JSI_PROPERTY_GET(ssin) { + return jsi::Value(SkScalarToDouble(getObject()->fSSin)); + } + JSI_PROPERTY_GET(tx) { + return jsi::Value(SkScalarToDouble(getObject()->fTx)); + } + JSI_PROPERTY_GET(ty) { + return jsi::Value(SkScalarToDouble(getObject()->fTy)); + } + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkRSXform, __typename__), + JSI_EXPORT_PROP_GET(JsiSkRSXform, scos), + JSI_EXPORT_PROP_GET(JsiSkRSXform, ssin), + JSI_EXPORT_PROP_GET(JsiSkRSXform, tx), + JSI_EXPORT_PROP_GET(JsiSkRSXform, ty)) + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkRSXform, dispose)) + + /** + Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + if (object.isHostObject(runtime)) { + return object.asHostObject(runtime)->getObject(); + } else { + auto scos = + object.getArray(runtime).getValueAtIndex(runtime, 0).asNumber(); + auto ssin = + object.getArray(runtime).getValueAtIndex(runtime, 1).asNumber(); + auto tx = object.getArray(runtime).getValueAtIndex(runtime, 2).asNumber(); + auto ty = object.getArray(runtime).getValueAtIndex(runtime, 3).asNumber(); + return std::make_shared(SkRSXform::Make(scos, ssin, tx, ty)); + } + } + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkRSXform &rsxform) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), rsxform)); + } + + /** + * Creates the function for construction a new instance of the SkRSXform + * wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the SkRSXform + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto rsxform = + SkRSXform::Make(arguments[0].asNumber(), arguments[1].asNumber(), + arguments[2].asNumber(), arguments[3].asNumber()); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), + std::move(rsxform))); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRect.h new file mode 100644 index 00000000000000..c37a042f8db2ee --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRect.h @@ -0,0 +1,123 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkRect : public JsiSkWrappingSharedPtrHostObject { +public: + JSI_PROPERTY_GET(x) { return static_cast(getObject()->x()); } + JSI_PROPERTY_GET(y) { return static_cast(getObject()->y()); } + JSI_PROPERTY_GET(width) { return static_cast(getObject()->width()); } + JSI_PROPERTY_GET(height) { + return static_cast(getObject()->height()); + } + JSI_PROPERTY_GET(left) { return static_cast(getObject()->left()); } + JSI_PROPERTY_GET(top) { return static_cast(getObject()->top()); } + JSI_PROPERTY_GET(right) { return static_cast(getObject()->right()); } + JSI_PROPERTY_GET(bottom) { + return static_cast(getObject()->bottom()); + } + + JSI_API_TYPENAME("Rect"); + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkRect, x), + JSI_EXPORT_PROP_GET(JsiSkRect, y), + JSI_EXPORT_PROP_GET(JsiSkRect, width), + JSI_EXPORT_PROP_GET(JsiSkRect, height), + JSI_EXPORT_PROP_GET(JsiSkRect, __typename__)) + + JSI_HOST_FUNCTION(setXYWH) { + getObject()->setXYWH(arguments[0].asNumber(), arguments[1].asNumber(), + arguments[2].asNumber(), arguments[3].asNumber()); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(setLTRB) { + getObject()->setLTRB(arguments[0].asNumber(), arguments[1].asNumber(), + arguments[2].asNumber(), arguments[3].asNumber()); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkRect, setXYWH), + JSI_EXPORT_FUNC(JsiSkRect, setLTRB), + JSI_EXPORT_FUNC(JsiSkRect, dispose)) + + /** + Constructor + */ + JsiSkRect(std::shared_ptr context, const SkRect &rect) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(rect)) {} + + /** + Returns the underlying object from a host object of this type + */ + static std::shared_ptr fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + const auto &object = obj.asObject(runtime); + if (object.isHostObject(runtime)) { + return object.asHostObject(runtime)->getObject(); + } else { + auto x = object.getProperty(runtime, "x").asNumber(); + auto y = object.getProperty(runtime, "y").asNumber(); + auto width = object.getProperty(runtime, "width").asNumber(); + auto height = object.getProperty(runtime, "height").asNumber(); + return std::make_shared(SkRect::MakeXYWH(x, y, width, height)); + } + } + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkRect &rect) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(std::move(context), rect)); + } + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + SkRect &&rect) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), std::move(rect))); + } + + /** + * Creates the function for construction a new instance of the SkRect + * wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the SkRect + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + // Set up the rect + SkRect rect = + SkRect::MakeXYWH(arguments[0].asNumber(), arguments[1].asNumber(), + arguments[2].asNumber(), arguments[3].asNumber()); + + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), std::move(rect))); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeEffect.h new file mode 100644 index 00000000000000..698a01a37e3f14 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeEffect.h @@ -0,0 +1,220 @@ +#pragma once + +#include +#include +#include +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkMatrix.h" +#include "JsiSkShader.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRuntimeEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +struct RuntimeEffectUniform { + int columns; + int rows; + int slot; // the index into the uniforms array that this uniform begins. + bool isInteger; +}; + +class JsiSkRuntimeEffect + : public JsiSkWrappingSkPtrHostObject { +public: + JSI_HOST_FUNCTION(makeShader) { + auto uniforms = castUniforms(runtime, arguments[0]); + + auto matrix = + count >= 2 && !arguments[1].isUndefined() && !arguments[1].isNull() + ? JsiSkMatrix::fromValue(runtime, arguments[1]).get() + : nullptr; + + // Create and return shader as host object + auto shader = + getObject()->makeShader(std::move(uniforms), nullptr, 0, matrix); + + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(shader))); + } + + JSI_HOST_FUNCTION(makeShaderWithChildren) { + auto uniforms = castUniforms(runtime, arguments[0]); + + // Children + std::vector> children; + auto jsiChildren = arguments[1].asObject(runtime).asArray(runtime); + auto jsiChildCount = jsiChildren.size(runtime); + children.reserve(jsiChildCount); + for (int i = 0; i < jsiChildCount; i++) { + auto shader = jsiChildren.getValueAtIndex(runtime, i) + .asObject(runtime) + .asHostObject(runtime) + ->getObject(); + children.push_back(shader); + } + + auto matrix = + count >= 3 && !arguments[2].isUndefined() && !arguments[2].isNull() + ? JsiSkMatrix::fromValue(runtime, arguments[2]).get() + : nullptr; + + // Create and return shader as host object + auto shader = getObject()->makeShader(std::move(uniforms), children.data(), + children.size(), matrix); + + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(shader))); + } + + JSI_HOST_FUNCTION(getUniformCount) { + return static_cast(getObject()->uniforms().size()); + } + + JSI_HOST_FUNCTION(getUniformFloatCount) { + return static_cast(getObject()->uniformSize() / sizeof(float)); + } + + JSI_HOST_FUNCTION(getUniformName) { + auto i = static_cast(arguments[0].asNumber()); + if (i < 0 || i >= getObject()->uniforms().size()) { + throw jsi::JSError(runtime, "invalid uniform index"); + } + auto it = getObject()->uniforms().begin() + i; + return jsi::String::createFromAscii(runtime, std::string(it->name)); + } + + JSI_HOST_FUNCTION(getUniform) { + auto i = static_cast(arguments[0].asNumber()); + if (i < 0 || i >= getObject()->uniforms().size()) { + throw jsi::JSError(runtime, "invalid uniform index"); + } + auto it = getObject()->uniforms().begin() + i; + auto result = jsi::Object(runtime); + RuntimeEffectUniform su = fromUniform(*it); + result.setProperty(runtime, "columns", su.columns); + result.setProperty(runtime, "rows", su.rows); + result.setProperty(runtime, "slot", su.slot); + result.setProperty(runtime, "isInteger", su.isInteger); + return result; + } + + JSI_HOST_FUNCTION(source) { + return jsi::String::createFromAscii(runtime, getObject()->source()); + } + + EXPORT_JSI_API_TYPENAME(JsiSkRuntimeEffect, "RuntimeEffect") + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkRuntimeEffect, makeShader), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, + makeShaderWithChildren), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, getUniformCount), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, + getUniformFloatCount), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, getUniformName), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, getUniform), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, source), + JSI_EXPORT_FUNC(JsiSkRuntimeEffect, dispose)) + + JsiSkRuntimeEffect(std::shared_ptr context, + sk_sp rt) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(rt)) {} + + static RuntimeEffectUniform fromUniform(const SkRuntimeEffect::Uniform &u) { + RuntimeEffectUniform su; + su.rows = u.count; // arrayLength + su.columns = 1; + su.isInteger = false; + using Type = SkRuntimeEffect::Uniform::Type; + switch (u.type) { + case Type::kFloat: + break; + case Type::kFloat2: + su.columns = 2; + break; + case Type::kFloat3: + su.columns = 3; + break; + case Type::kFloat4: + su.columns = 4; + break; + case Type::kFloat2x2: + su.columns = 2; + su.rows *= 2; + break; + case Type::kFloat3x3: + su.columns = 3; + su.rows *= 3; + break; + case Type::kFloat4x4: + su.columns = 4; + su.rows *= 4; + break; + case Type::kInt: + su.isInteger = true; + break; + case Type::kInt2: + su.columns = 2; + su.isInteger = true; + break; + case Type::kInt3: + su.columns = 3; + su.isInteger = true; + break; + case Type::kInt4: + su.columns = 4; + su.isInteger = true; + break; + } + su.slot = static_cast(u.offset / sizeof(float)); + return su; + } + +private: + sk_sp castUniforms(jsi::Runtime &runtime, const jsi::Value &value) { + auto jsiUniforms = value.asObject(runtime).asArray(runtime); + auto jsiUniformsSize = jsiUniforms.size(runtime); + + // verify size of input uniforms + if (jsiUniformsSize * sizeof(float) != getObject()->uniformSize()) { + std::string msg = + "Uniforms size differs from effect's uniform size. Received " + + std::to_string(jsiUniformsSize) + " expected " + + std::to_string(getObject()->uniformSize() / sizeof(float)); + throw jsi::JSError(runtime, msg.c_str()); + } + + auto uniforms = SkData::MakeUninitialized(getObject()->uniformSize()); + + // Convert to skia uniforms + const auto &u = getObject()->uniforms(); + for (std::size_t i = 0; i < u.size(); i++) { + auto it = getObject()->uniforms().begin() + i; + RuntimeEffectUniform reu = fromUniform(*it); + for (std::size_t j = 0; j < reu.columns * reu.rows; ++j) { + const std::size_t offset = reu.slot + j; + float fValue = jsiUniforms.getValueAtIndex(runtime, offset).asNumber(); + int iValue = static_cast(fValue); + auto value = reu.isInteger ? SkBits2Float(iValue) : fValue; + memcpy(SkTAddOffset(uniforms->writable_data(), + offset * sizeof(value)), + &value, sizeof(value)); + } + } + return uniforms; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeEffectFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeEffectFactory.h new file mode 100644 index 00000000000000..8f6ca59695b14c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeEffectFactory.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "JsiSkRuntimeEffect.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkRuntimeEffectFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(Make) { + auto sksl = arguments[0].asString(runtime).utf8(runtime); + auto result = SkRuntimeEffect::MakeForShader(SkString(sksl)); + auto effect = result.effect; + auto errorText = result.errorText; + if (!effect) { + throw jsi::JSError(runtime, std::string("Error in sksl:\n" + + std::string(errorText.c_str())) + .c_str()); + return jsi::Value::null(); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(effect))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkRuntimeEffectFactory, Make)) + + explicit JsiSkRuntimeEffectFactory( + std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeShaderBuilder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeShaderBuilder.h new file mode 100644 index 00000000000000..99deecdb67f8d3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkRuntimeShaderBuilder.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "JsiSkRuntimeEffect.h" +#include "SkRuntimeEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkRuntimeShaderBuilder + : public JsiSkWrappingSharedPtrHostObject { +public: + /** + Constructor + */ + JsiSkRuntimeShaderBuilder(std::shared_ptr context, + const SkRuntimeShaderBuilder &rt) + : JsiSkWrappingSharedPtrHostObject( + std::move(context), std::make_shared(rt)) {} + + JSI_HOST_FUNCTION(setUniform) { + auto name = arguments[0].asString(runtime).utf8(runtime); + auto jsiValue = arguments[1].asObject(runtime).asArray(runtime); + auto size = jsiValue.size(runtime); + std::vector value; + value.reserve(size); + for (int i = 0; i < size; i++) { + auto e = jsiValue.getValueAtIndex(runtime, i).asNumber(); + value.push_back(e); + } + getObject() + ->uniform(name.c_str()) + .set(value.data(), static_cast(size)); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkRuntimeShaderBuilder, setUniform), + JSI_EXPORT_FUNC(JsiSkRuntimeShaderBuilder, dispose)) + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + const SkRuntimeShaderBuilder &rt) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), rt)); + } + + /** + * Creates the function for construction a new instance of the SkRect + * wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the SkRect + * class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto rt = JsiSkRuntimeEffect::fromValue(runtime, arguments[0]); + auto rtb = SkRuntimeShaderBuilder(rt); + // Return the newly constructed object + return jsi::Object::createFromHostObject( + runtime, std::make_shared( + std::move(context), std::move(rtb))); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSVG.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSVG.h new file mode 100644 index 00000000000000..e715481181b2c1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSVG.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkSVG : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkSVG(std::shared_ptr context, sk_sp svgdom) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(svgdom)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkSVG, "SVG") + + JSI_HOST_FUNCTION(width) { + return static_cast(getObject()->containerSize().width()); + } + + JSI_HOST_FUNCTION(height) { + return static_cast(getObject()->containerSize().height()); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSVG, width), + JSI_EXPORT_FUNC(JsiSkSVG, height), + JSI_EXPORT_FUNC(JsiSkSVG, dispose)) + + /** + Returns the underlying object from a host object of this type + */ + static sk_sp fromValue(jsi::Runtime &runtime, + const jsi::Value &obj) { + return obj.asObject(runtime).asHostObject(runtime)->getObject(); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSVGFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSVGFactory.h new file mode 100644 index 00000000000000..2e6a61cd5ea1b0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSVGFactory.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkData.h" +#include "JsiSkHostObjects.h" +#include "JsiSkSVG.h" +#include "JsiSkTypeface.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkStream.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkSVGFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeFromData) { + auto data = JsiSkData::fromValue(runtime, arguments[0]); + auto stream = SkMemoryStream::Make(data); + auto svg_dom = SkSVGDOM::Builder().make(*stream); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(svg_dom))); + } + + JSI_HOST_FUNCTION(MakeFromString) { + auto svgText = arguments[0].asString(runtime).utf8(runtime); + auto stream = SkMemoryStream::MakeDirect(svgText.c_str(), svgText.size()); + auto svg_dom = SkSVGDOM::Builder().make(*stream); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(svg_dom))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSVGFactory, MakeFromData), + JSI_EXPORT_FUNC(JsiSkSVGFactory, MakeFromString)) + + explicit JsiSkSVGFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkShader.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkShader.h new file mode 100644 index 00000000000000..eee6753e9f7bfa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkShader.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkGradientShader.h" +#include "SkShader.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkShader : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkShader(std::shared_ptr context, + sk_sp shader) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(shader)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkShader, "Shader") + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkShader, dispose)) +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkShaderFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkShaderFactory.h new file mode 100644 index 00000000000000..408fe6cbe72255 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkShaderFactory.h @@ -0,0 +1,226 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkColorFilter.h" +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColorFilter.h" +#include "SkImageFilters.h" +#include "SkPerlinNoiseShader.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +int getFlag(const jsi::Value *values, int i, size_t size) { + if (i >= size || values[i].isUndefined()) { + return 0; + } + return values[i].asNumber(); +} + +SkMatrix *getLocalMatrix(jsi::Runtime &runtime, const jsi::Value *values, int i, + size_t size) { + if (i >= size || values[i].isUndefined()) { + return nullptr; + } + return JsiSkMatrix::fromValue(runtime, values[i]).get(); +} + +SkTileMode getTileMode(const jsi::Value *values, int i, size_t size) { + if (i >= size || values[i].isUndefined()) { + return SkTileMode::kClamp; + } + return static_cast(values[i].asNumber()); +} + +std::vector getColors(jsi::Runtime &runtime, const jsi::Value &value) { + std::vector colors; + if (!value.isNull()) { + auto jsiColors = value.asObject(runtime).asArray(runtime); + auto size = jsiColors.size(runtime); + colors.reserve(size); + for (int i = 0; i < size; i++) { + SkColor color = + JsiSkColor::fromValue(runtime, jsiColors.getValueAtIndex(runtime, i)); + colors.push_back(color); + } + } + return colors; +} + +std::vector getPositions(jsi::Runtime &runtime, + const jsi::Value &value) { + std::vector positions; + if (!value.isNull()) { + auto jsiPositions = value.asObject(runtime).asArray(runtime); + auto size = jsiPositions.size(runtime); + positions.reserve(size); + for (int i = 0; i < size; i++) { + SkScalar position = jsiPositions.getValueAtIndex(runtime, i).asNumber(); + positions.push_back(position); + } + } + return positions; +} + +class JsiSkShaderFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeLinearGradient) { + auto p1 = + *JsiSkPoint::fromValue(runtime, arguments[0].asObject(runtime)).get(); + auto p2 = + *JsiSkPoint::fromValue(runtime, arguments[1].asObject(runtime)).get(); + SkPoint pts[] = {p1, p2}; + + std::vector colors = getColors(runtime, arguments[2]); + std::vector positions = getPositions(runtime, arguments[3]); + auto tileMode = getTileMode(arguments, 4, count); + auto flag = getFlag(arguments, 6, count); + auto localMatrix = getLocalMatrix(runtime, arguments, 5, count); + + sk_sp gradient = SkGradientShader::MakeLinear( + pts, colors.data(), positions.data(), static_cast(colors.size()), + tileMode, flag, localMatrix); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeRadialGradient) { + auto center = + *JsiSkPoint::fromValue(runtime, arguments[0].asObject(runtime)).get(); + auto r = arguments[1].asNumber(); + + std::vector colors = getColors(runtime, arguments[2]); + std::vector positions = getPositions(runtime, arguments[3]); + auto tileMode = getTileMode(arguments, 4, count); + auto flag = getFlag(arguments, 6, count); + auto localMatrix = getLocalMatrix(runtime, arguments, 5, count); + + sk_sp gradient = SkGradientShader::MakeRadial( + center, r, colors.data(), positions.data(), + static_cast(colors.size()), tileMode, flag, localMatrix); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeSweepGradient) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + std::vector colors = getColors(runtime, arguments[2]); + std::vector positions = getPositions(runtime, arguments[3]); + auto tileMode = getTileMode(arguments, 4, count); + auto localMatrix = getLocalMatrix(runtime, arguments, 5, count); + auto flag = getFlag(arguments, 6, count); + auto startAngle = + (count < 8 || arguments[7].isUndefined()) ? 0 : arguments[7].asNumber(); + auto endAngle = (count < 9 || arguments[8].isUndefined()) + ? 360 + : arguments[8].asNumber(); + sk_sp gradient = SkGradientShader::MakeSweep( + x, y, colors.data(), positions.data(), static_cast(colors.size()), + tileMode, startAngle, endAngle, flag, localMatrix); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeTwoPointConicalGradient) { + auto start = + *JsiSkPoint::fromValue(runtime, arguments[0].asObject(runtime)).get(); + auto startRadius = arguments[1].asNumber(); + + auto end = + *JsiSkPoint::fromValue(runtime, arguments[2].asObject(runtime)).get(); + auto endRadius = arguments[3].asNumber(); + + std::vector colors = getColors(runtime, arguments[4]); + std::vector positions = getPositions(runtime, arguments[5]); + auto tileMode = getTileMode(arguments, 6, count); + auto localMatrix = getLocalMatrix(runtime, arguments, 7, count); + auto flag = getFlag(arguments, 8, count); + + sk_sp gradient = SkGradientShader::MakeTwoPointConical( + start, startRadius, end, endRadius, colors.data(), positions.data(), + static_cast(colors.size()), tileMode, flag, localMatrix); + + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeTurbulence) { + auto baseFreqX = arguments[0].asNumber(); + auto baseFreqY = arguments[1].asNumber(); + auto octaves = arguments[2].asNumber(); + auto seed = arguments[3].asNumber(); + auto tileW = arguments[4].asNumber(); + auto tileH = arguments[5].asNumber(); + SkISize size = SkISize::Make(tileW, tileH); + sk_sp gradient = SkPerlinNoiseShader::MakeTurbulence( + baseFreqX, baseFreqY, octaves, seed, &size); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeFractalNoise) { + auto baseFreqX = arguments[0].asNumber(); + auto baseFreqY = arguments[1].asNumber(); + auto octaves = arguments[2].asNumber(); + auto seed = arguments[3].asNumber(); + auto tileW = arguments[4].asNumber(); + auto tileH = arguments[5].asNumber(); + SkISize size = SkISize::Make(tileW, tileH); + sk_sp gradient = SkPerlinNoiseShader::MakeFractalNoise( + baseFreqX, baseFreqY, octaves, seed, &size); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeBlend) { + auto blendMode = (SkBlendMode)arguments[0].asNumber(); + auto one = JsiSkShader::fromValue(runtime, arguments[1]); + auto two = JsiSkShader::fromValue(runtime, arguments[2]); + sk_sp gradient = SkShaders::Blend(blendMode, one, two); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_HOST_FUNCTION(MakeColor) { + auto color = JsiSkColor::fromValue(runtime, arguments[0]); + sk_sp gradient = SkShaders::Color(color); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(gradient))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeLinearGradient), + JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeRadialGradient), + JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeSweepGradient), + JSI_EXPORT_FUNC(JsiSkShaderFactory, + MakeTwoPointConicalGradient), + JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeTurbulence), + JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeFractalNoise), + JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeBlend), + JSI_EXPORT_FUNC(JsiSkShaderFactory, MakeColor)) + + explicit JsiSkShaderFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSurface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSurface.h new file mode 100644 index 00000000000000..0ea0d1820450b2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSurface.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#include "JsiSkCanvas.h" +#include "JsiSkImage.h" +#include "JsiSkSurfaceFactory.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkSurface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkSurface : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkSurface(std::shared_ptr context, + sk_sp surface) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(surface)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkSurface, "Surface") + + JSI_HOST_FUNCTION(getCanvas) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), getObject()->getCanvas())); + } + + JSI_HOST_FUNCTION(flush) { + getObject()->flush(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(makeImageSnapshot) { + sk_sp image; + if (count == 1) { + auto rect = JsiSkRect::fromValue(runtime, arguments[0]); + image = getObject()->makeImageSnapshot(SkIRect::MakeXYWH( + rect->x(), rect->y(), rect->width(), rect->height())); + } else { + image = getObject()->makeImageSnapshot(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), std::move(image))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSurface, getCanvas), + JSI_EXPORT_FUNC(JsiSkSurface, makeImageSnapshot), + JSI_EXPORT_FUNC(JsiSkSurface, flush), + JSI_EXPORT_FUNC(JsiSkSurface, dispose)) +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSurfaceFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSurfaceFactory.h new file mode 100644 index 00000000000000..1f83f8b8f03024 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkSurfaceFactory.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#include "JsiSkSurface.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkSurface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkSurfaceFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(Make) { + auto width = static_cast(arguments[0].asNumber()); + auto height = static_cast(arguments[1].asNumber()); + auto surface = SkSurface::MakeRasterN32Premul(width, height); + if (surface == nullptr) { + return jsi::Value::null(); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(surface))); + } + + JSI_HOST_FUNCTION(MakeOffscreen) { + auto width = static_cast(arguments[0].asNumber()); + auto height = static_cast(arguments[1].asNumber()); + auto context = getContext(); + auto surface = context->makeOffscreenSurface(width, height); + if (surface == nullptr) { + return jsi::Value::null(); + } + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(surface))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSurfaceFactory, Make), + JSI_EXPORT_FUNC(JsiSkSurfaceFactory, MakeOffscreen)) + + explicit JsiSkSurfaceFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTextBlob.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTextBlob.h new file mode 100644 index 00000000000000..9874f888e9a03c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTextBlob.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkTextBlob.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkTextBlob : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkTextBlob(std::shared_ptr context, + sk_sp shader) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(shader)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkTextBlob, "TextBlob") + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkTextBlob, dispose)) +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTextBlobFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTextBlobFactory.h new file mode 100644 index 00000000000000..e66014714d469e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTextBlobFactory.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include + +#include + +#include "JsiSkFont.h" +#include "JsiSkHostObjects.h" +#include "JsiSkRSXform.h" +#include "JsiSkTextBlob.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkTextBlob.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkTextBlobFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeFromText) { + auto str = arguments[0].asString(runtime).utf8(runtime); + auto font = JsiSkFont::fromValue(runtime, arguments[1]); + auto textBlob = SkTextBlob::MakeFromString(str.c_str(), *font); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(textBlob))); + } + + JSI_HOST_FUNCTION(MakeFromGlyphs) { + auto jsiGlyphs = arguments[0].asObject(runtime).asArray(runtime); + auto font = JsiSkFont::fromValue(runtime, arguments[1]); + int bytesPerGlyph = 2; + std::vector glyphs; + int glyphsSize = static_cast(jsiGlyphs.size(runtime)); + glyphs.reserve(glyphsSize); + for (int i = 0; i < glyphsSize; i++) { + glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber()); + } + auto textBlob = + SkTextBlob::MakeFromText(glyphs.data(), glyphs.size() * bytesPerGlyph, + *font, SkTextEncoding::kGlyphID); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(textBlob))); + } + + JSI_HOST_FUNCTION(MakeFromRSXform) { + auto str = arguments[0].asString(runtime).utf8(runtime); + auto jsiRsxforms = arguments[1].asObject(runtime).asArray(runtime); + auto font = JsiSkFont::fromValue(runtime, arguments[2]); + std::vector rsxforms; + int rsxformsSize = static_cast(jsiRsxforms.size(runtime)); + rsxforms.reserve(rsxformsSize); + for (int i = 0; i < rsxformsSize; i++) { + auto rsxform = JsiSkRSXform::fromValue( + runtime, jsiRsxforms.getValueAtIndex(runtime, i)); + rsxforms.push_back(*rsxform); + } + auto textBlob = SkTextBlob::MakeFromRSXform(str.c_str(), str.length(), + rsxforms.data(), *font); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(textBlob))); + } + + JSI_HOST_FUNCTION(MakeFromRSXformGlyphs) { + auto jsiGlyphs = arguments[0].asObject(runtime).asArray(runtime); + auto jsiRsxforms = arguments[1].asObject(runtime).asArray(runtime); + auto font = JsiSkFont::fromValue(runtime, arguments[2]); + int bytesPerGlyph = 2; + std::vector glyphs; + int glyphsSize = static_cast(jsiGlyphs.size(runtime)); + glyphs.reserve(glyphsSize); + for (int i = 0; i < glyphsSize; i++) { + glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber()); + } + std::vector rsxforms; + int rsxformsSize = static_cast(jsiRsxforms.size(runtime)); + rsxforms.reserve(rsxformsSize); + for (int i = 0; i < rsxformsSize; i++) { + auto rsxform = JsiSkRSXform::fromValue( + runtime, jsiRsxforms.getValueAtIndex(runtime, i)); + rsxforms.push_back(*rsxform); + } + auto textBlob = SkTextBlob::MakeFromRSXform( + glyphs.data(), glyphs.size() * bytesPerGlyph, rsxforms.data(), *font, + SkTextEncoding::kGlyphID); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(getContext(), std::move(textBlob))); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkTextBlobFactory, MakeFromText), + JSI_EXPORT_FUNC(JsiSkTextBlobFactory, MakeFromGlyphs), + JSI_EXPORT_FUNC(JsiSkTextBlobFactory, MakeFromRSXform), + JSI_EXPORT_FUNC(JsiSkTextBlobFactory, + MakeFromRSXformGlyphs), ) + + explicit JsiSkTextBlobFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTypeface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTypeface.h new file mode 100644 index 00000000000000..e043543212edd9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTypeface.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "RNSkLog.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkFont.h" +#include "SkTypeface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkTypeface : public JsiSkWrappingSkPtrHostObject { +public: + EXPORT_JSI_API_TYPENAME(JsiSkTypeface, "Typeface") + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkTypeface, dispose)) + + JsiSkTypeface(std::shared_ptr context, + sk_sp typeface) + : JsiSkWrappingSkPtrHostObject(std::move(context), std::move(typeface)) {} + + /** + Returns the jsi object from a host object of this type + */ + static jsi::Value toValue(jsi::Runtime &runtime, + std::shared_ptr context, + sk_sp tf) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(std::move(context), std::move(tf))); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTypefaceFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTypefaceFactory.h new file mode 100644 index 00000000000000..184a57513c0e08 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkTypefaceFactory.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include + +#include "JsiSkData.h" +#include "JsiSkHostObjects.h" +#include "JsiSkTypeface.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkTypefaceFactory : public JsiSkHostObject { +public: + JSI_HOST_FUNCTION(MakeFreeTypeFaceFromData) { + auto data = JsiSkData::fromValue(runtime, arguments[0]); + auto typeface = SkFontMgr::RefDefault()->makeFromData(std::move(data)); + if (typeface == nullptr) { + return jsi::Value::null(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), typeface)); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkTypefaceFactory, + MakeFreeTypeFaceFromData)) + + explicit JsiSkTypefaceFactory(std::shared_ptr context) + : JsiSkHostObject(std::move(context)) {} +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkVertices.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkVertices.h new file mode 100644 index 00000000000000..8c84a0abcf9b24 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/JsiSkVertices.h @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include + +#include "JsiSkHostObjects.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkVertices.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiSkVertices : public JsiSkWrappingSkPtrHostObject { +public: + JsiSkVertices(std::shared_ptr context, + sk_sp vertices) + : JsiSkWrappingSkPtrHostObject(std::move(context), + std::move(vertices)) {} + + EXPORT_JSI_API_TYPENAME(JsiSkVertices, "Vertices") + + JSI_HOST_FUNCTION(bounds) { + const auto &result = getObject()->bounds(); + return jsi::Object::createFromHostObject( + runtime, std::make_shared(getContext(), result)); + } + + JSI_HOST_FUNCTION(uniqueID) { + return static_cast(getObject()->uniqueID()); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkVertices, bounds), + JSI_EXPORT_FUNC(JsiSkVertices, uniqueID), + JSI_EXPORT_FUNC(JsiSkVertices, dispose)) + + /** + * Creates the function for construction a new instance of the SkVertices + * wrapper + * @param context platform context + * @return A function for creating a new host object wrapper for the + * SkVertices class + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto mode = static_cast(arguments[0].getNumber()); + std::vector positions; + std::vector texs; + std::vector colors; + std::vector indices; + + auto jsiPositions = arguments[1].asObject(runtime).asArray(runtime); + auto positionsSize = static_cast(jsiPositions.size(runtime)); + positions.reserve(positionsSize); + for (int i = 0; i < positionsSize; i++) { + std::shared_ptr point = JsiSkPoint::fromValue( + runtime, + jsiPositions.getValueAtIndex(runtime, i).asObject(runtime)); + positions.push_back(*point.get()); + } + + if (count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined()) { + auto jsiTexs = arguments[2].asObject(runtime).asArray(runtime); + auto texsSize = jsiTexs.size(runtime); + texs.reserve(texsSize); + for (int i = 0; i < texsSize; i++) { + auto point = JsiSkPoint::fromValue( + runtime, jsiTexs.getValueAtIndex(runtime, i).asObject(runtime)); + texs.push_back(*point.get()); + } + } + + if (count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()) { + auto jsiColors = arguments[3].asObject(runtime).asArray(runtime); + auto colorsSize = jsiColors.size(runtime); + colors.reserve(colorsSize); + for (int i = 0; i < colorsSize; i++) { + SkColor color = JsiSkColor::fromValue( + runtime, jsiColors.getValueAtIndex(runtime, i)); + colors.push_back(color); + } + } + + int indicesSize = 0; + if (count >= 5 && !arguments[4].isNull() && !arguments[4].isUndefined()) { + auto jsiIndices = arguments[4].asObject(runtime).asArray(runtime); + indicesSize = static_cast(jsiIndices.size(runtime)); + indices.reserve(indicesSize); + for (int i = 0; i < indicesSize; i++) { + uint16_t index = jsiIndices.getValueAtIndex(runtime, i).asNumber(); + indices.push_back(index); + } + } + // TODO: this is the technic used in CanvasKit: + // https://github.com/google/skia/blob/main/modules/canvaskit/interface.js#L1216 + // Note that the isVolatile parameter is unused when using MakeCopy() + // auto isVolatile = count >= 6 && !arguments[5].isNull() + // && !arguments[5].isUndefined() ? arguments[5].getBool() + // : false; auto flags = 0; + // // These flags are from SkVertices.h and should be kept + // in sync with those. if (texs.size() > 0) { + // flags |= (1 << 0); + // } + // if (colors.size() > 0) { + // flags |= (1 << 1); + // } + // if (!isVolatile) { + // flags |= (1 << 2); + // } + // auto builder = SkVertices::Builder(mode, + // positionsSize/2, indicesSize, flags); + // std::copy(positions.data(), positions.data() + + // positionsSize, builder.positions()); if + // (builder.texCoords()) { + // std::copy(std::begin(texs), std::end(texs), + // builder.texCoords()); + // } + // if (builder.colors()) { + // std::copy(std::begin(colors), std::end(colors), + // builder.colors()); + // } + // if (builder.indices()) { + // std::copy(std::begin(indices), std::end(indices), + // builder.indices()); + // } + // auto vertices = builder.detach(); + auto vertices = SkVertices::MakeCopy( + mode, positionsSize, positions.data(), texs.data(), colors.data(), + indicesSize, indices.data()); + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(context, std::move(vertices))); + }; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/third_party/CSSColorParser.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/third_party/CSSColorParser.cpp new file mode 100644 index 00000000000000..a33e4033c7cbcd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/third_party/CSSColorParser.cpp @@ -0,0 +1,181 @@ +#include "CSSColorParser.h" + +namespace CSSColorParser { + +template +uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. + i = ::round(i); // Seems to be what Chrome does (vs truncation). + return i < 0 ? 0 : i > 255 ? 255 : uint8_t(i); +} + +template float clamp_css_float(T f) { // Clamp to float 0.0 .. 1.0. + return f < 0 ? 0 : f > 1 ? 1 : static_cast(f); +} + +float parseFloat(const std::string &str) { + return strtof(str.c_str(), nullptr); +} + +int64_t parseInt(const std::string &str, uint8_t base = 10) { + return strtoll(str.c_str(), nullptr, base); +} + +uint8_t parse_css_int(const std::string &str) { // int or percentage. + if (str.length() && str.back() == '%') { + return clamp_css_byte(parseFloat(str) / 100.0f * 255.0f); + } else { + return clamp_css_byte(parseInt(str)); + } +} + +float parse_css_float(const std::string &str) { // float or percentage. + if (str.length() && str.back() == '%') { + return clamp_css_float(parseFloat(str) / 100.0f); + } else { + return clamp_css_float(parseFloat(str)); + } +} + +float css_hue_to_rgb(float m1, float m2, float h) { + if (h < 0.0f) { + h += 1.0f; + } else if (h > 1.0f) { + h -= 1.0f; + } + + if (h * 6.0f < 1.0f) { + return m1 + (m2 - m1) * h * 6.0f; + } + if (h * 2.0f < 1.0f) { + return m2; + } + if (h * 3.0f < 2.0f) { + return m1 + (m2 - m1) * (2.0f / 3.0f - h) * 6.0f; + } + return m1; +} + +std::vector split(const std::string &s, char delim) { + std::vector elems; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } + return elems; +} + +Color parse(const std::string &css_str) { + std::string str = css_str; + + // Remove all whitespace, not compliant, but should just be more accepting. + str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); + + // Convert to lowercase. + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + + for (const auto &namedColor : namedColors) { + if (str == namedColor.name) { + return {namedColor.color}; + } + } + + // #abc and #abc123 syntax. + if (str.length() && str.front() == '#') { + auto iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (str.length() == 4) { + if (!(iv >= 0 && iv <= 0xfff)) { + return {}; + } else { + return {static_cast(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)), + static_cast((iv & 0xf0) | ((iv & 0xf0) >> 4)), + static_cast((iv & 0xf) | ((iv & 0xf) << 4)), 1}; + } + } else if (str.length() == 7) { + if (!(iv >= 0 && iv <= 0xffffff)) { + return {}; // Covers NaN. + } else { + return {static_cast((iv & 0xff0000) >> 16), + static_cast((iv & 0xff00) >> 8), + static_cast(iv & 0xff), 1}; + } + } else if (str.length() == 5) { + // #rgba + if (!(iv >= 0 && iv <= 0xffff)) + return {}; // Covers NaN. + return { + static_cast(((iv & 0xf000) >> 8) | ((iv & 0xf000) >> 12)), + static_cast(((iv & 0x0f00) >> 4) | ((iv & 0x0f00) >> 8)), + static_cast((iv & 0x00f0) | ((iv & 0x00f0) >> 4)), + static_cast(((iv & 0x000f) << 4 | (iv & 0x000f))) / 255.0f}; + } else if (str.length() == 9) { + // #rrggbbaa + if (!(iv >= 0 && iv <= 0xffffffff)) + return {}; // Covers NaN. + return {static_cast(((iv & 0xff000000) >> 24) & 0xff), + static_cast((iv & 0x00ff0000) >> 16), + static_cast((iv & 0x0000ff00) >> 8), + static_cast((iv & 0x000000ff)) / 255.0f}; + } + + return {}; + } + + size_t op = str.find_first_of('('), ep = str.find_first_of(')'); + if (op != std::string::npos && ep + 1 == str.length()) { + const std::string fname = str.substr(0, op); + const std::vector params = + split(str.substr(op + 1, ep - (op + 1)), ','); + + float alpha = 1.0f; + + if (fname == "rgba" || fname == "rgb") { + if (fname == "rgba") { + if (params.size() != 4) { + return {}; + } + alpha = parse_css_float(params.back()); + } else { + if (params.size() != 3) { + return {}; + } + } + + return {parse_css_int(params[0]), parse_css_int(params[1]), + parse_css_int(params[2]), alpha}; + + } else if (fname == "hsla" || fname == "hsl") { + if (fname == "hsla") { + if (params.size() != 4) { + return {}; + } + alpha = parse_css_float(params.back()); + } else { + if (params.size() != 3) { + return {}; + } + } + + float h = parseFloat(params[0]) / 360.0f; + float i; + // Normalize the hue to [0..1[ + h = std::modf(h, &i); + + // NOTE(deanm): According to the CSS spec s/l should only be + // percentages, but we don't bother and let float or percentage. + float s = parse_css_float(params[1]); + float l = parse_css_float(params[2]); + + float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s; + float m1 = l * 2.0f - m2; + + return {clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1.0f / 3.0f) * 255.0f), + clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255.0f), + clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1.0f / 3.0f) * 255.0f), + alpha}; + } + } + + return {}; +} +} // namespace CSSColorParser \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/third_party/CSSColorParser.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/third_party/CSSColorParser.h new file mode 100644 index 00000000000000..03b2186b42bfb6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/api/third_party/CSSColorParser.h @@ -0,0 +1,210 @@ +// (c) Dean McNamee , 2012. +// C++ port by Mapbox, Konstantin Käfer , 2014-2017. +// +// https://github.com/deanm/css-color-parser-js +// https://github.com/kkaefer/css-color-parser-cpp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace CSSColorParser { + +struct Color { + inline Color() {} + inline Color(unsigned char r_, unsigned char g_, unsigned char b_, float a_) + : r(r_), g(g_), b(b_), a(a_ > 1 ? 1 + : a_ < 0 ? 0 + : a_) {} + unsigned char r = 0, g = 0, b = 0; + float a = -1.0f; +}; + +struct NamedColor { + const char *const name; + const Color color; +}; + +const NamedColor namedColors[] = {{"transparent", {0, 0, 0, 0}}, + {"aliceblue", {240, 248, 255, 1}}, + {"antiquewhite", {250, 235, 215, 1}}, + {"aqua", {0, 255, 255, 1}}, + {"aquamarine", {127, 255, 212, 1}}, + {"azure", {240, 255, 255, 1}}, + {"beige", {245, 245, 220, 1}}, + {"bisque", {255, 228, 196, 1}}, + {"black", {0, 0, 0, 1}}, + {"blanchedalmond", {255, 235, 205, 1}}, + {"blue", {0, 0, 255, 1}}, + {"blueviolet", {138, 43, 226, 1}}, + {"brown", {165, 42, 42, 1}}, + {"burlywood", {222, 184, 135, 1}}, + {"cadetblue", {95, 158, 160, 1}}, + {"chartreuse", {127, 255, 0, 1}}, + {"chocolate", {210, 105, 30, 1}}, + {"coral", {255, 127, 80, 1}}, + {"cornflowerblue", {100, 149, 237, 1}}, + {"cornsilk", {255, 248, 220, 1}}, + {"crimson", {220, 20, 60, 1}}, + {"cyan", {0, 255, 255, 1}}, + {"darkblue", {0, 0, 139, 1}}, + {"darkcyan", {0, 139, 139, 1}}, + {"darkgoldenrod", {184, 134, 11, 1}}, + {"darkgray", {169, 169, 169, 1}}, + {"darkgreen", {0, 100, 0, 1}}, + {"darkgrey", {169, 169, 169, 1}}, + {"darkkhaki", {189, 183, 107, 1}}, + {"darkmagenta", {139, 0, 139, 1}}, + {"darkolivegreen", {85, 107, 47, 1}}, + {"darkorange", {255, 140, 0, 1}}, + {"darkorchid", {153, 50, 204, 1}}, + {"darkred", {139, 0, 0, 1}}, + {"darksalmon", {233, 150, 122, 1}}, + {"darkseagreen", {143, 188, 143, 1}}, + {"darkslateblue", {72, 61, 139, 1}}, + {"darkslategray", {47, 79, 79, 1}}, + {"darkslategrey", {47, 79, 79, 1}}, + {"darkturquoise", {0, 206, 209, 1}}, + {"darkviolet", {148, 0, 211, 1}}, + {"deeppink", {255, 20, 147, 1}}, + {"deepskyblue", {0, 191, 255, 1}}, + {"dimgray", {105, 105, 105, 1}}, + {"dimgrey", {105, 105, 105, 1}}, + {"dodgerblue", {30, 144, 255, 1}}, + {"firebrick", {178, 34, 34, 1}}, + {"floralwhite", {255, 250, 240, 1}}, + {"forestgreen", {34, 139, 34, 1}}, + {"fuchsia", {255, 0, 255, 1}}, + {"gainsboro", {220, 220, 220, 1}}, + {"ghostwhite", {248, 248, 255, 1}}, + {"gold", {255, 215, 0, 1}}, + {"goldenrod", {218, 165, 32, 1}}, + {"gray", {128, 128, 128, 1}}, + {"green", {0, 128, 0, 1}}, + {"greenyellow", {173, 255, 47, 1}}, + {"grey", {128, 128, 128, 1}}, + {"honeydew", {240, 255, 240, 1}}, + {"hotpink", {255, 105, 180, 1}}, + {"indianred", {205, 92, 92, 1}}, + {"indigo", {75, 0, 130, 1}}, + {"ivory", {255, 255, 240, 1}}, + {"khaki", {240, 230, 140, 1}}, + {"lavender", {230, 230, 250, 1}}, + {"lavenderblush", {255, 240, 245, 1}}, + {"lawngreen", {124, 252, 0, 1}}, + {"lemonchiffon", {255, 250, 205, 1}}, + {"lightblue", {173, 216, 230, 1}}, + {"lightcoral", {240, 128, 128, 1}}, + {"lightcyan", {224, 255, 255, 1}}, + {"lightgoldenrodyellow", {250, 250, 210, 1}}, + {"lightgray", {211, 211, 211, 1}}, + {"lightgreen", {144, 238, 144, 1}}, + {"lightgrey", {211, 211, 211, 1}}, + {"lightpink", {255, 182, 193, 1}}, + {"lightsalmon", {255, 160, 122, 1}}, + {"lightseagreen", {32, 178, 170, 1}}, + {"lightskyblue", {135, 206, 250, 1}}, + {"lightslategray", {119, 136, 153, 1}}, + {"lightslategrey", {119, 136, 153, 1}}, + {"lightsteelblue", {176, 196, 222, 1}}, + {"lightyellow", {255, 255, 224, 1}}, + {"lime", {0, 255, 0, 1}}, + {"limegreen", {50, 205, 50, 1}}, + {"linen", {250, 240, 230, 1}}, + {"magenta", {255, 0, 255, 1}}, + {"maroon", {128, 0, 0, 1}}, + {"mediumaquamarine", {102, 205, 170, 1}}, + {"mediumblue", {0, 0, 205, 1}}, + {"mediumorchid", {186, 85, 211, 1}}, + {"mediumpurple", {147, 112, 219, 1}}, + {"mediumseagreen", {60, 179, 113, 1}}, + {"mediumslateblue", {123, 104, 238, 1}}, + {"mediumspringgreen", {0, 250, 154, 1}}, + {"mediumturquoise", {72, 209, 204, 1}}, + {"mediumvioletred", {199, 21, 133, 1}}, + {"midnightblue", {25, 25, 112, 1}}, + {"mintcream", {245, 255, 250, 1}}, + {"mistyrose", {255, 228, 225, 1}}, + {"moccasin", {255, 228, 181, 1}}, + {"navajowhite", {255, 222, 173, 1}}, + {"navy", {0, 0, 128, 1}}, + {"oldlace", {253, 245, 230, 1}}, + {"olive", {128, 128, 0, 1}}, + {"olivedrab", {107, 142, 35, 1}}, + {"orange", {255, 165, 0, 1}}, + {"orangered", {255, 69, 0, 1}}, + {"orchid", {218, 112, 214, 1}}, + {"palegoldenrod", {238, 232, 170, 1}}, + {"palegreen", {152, 251, 152, 1}}, + {"paleturquoise", {175, 238, 238, 1}}, + {"palevioletred", {219, 112, 147, 1}}, + {"papayawhip", {255, 239, 213, 1}}, + {"peachpuff", {255, 218, 185, 1}}, + {"peru", {205, 133, 63, 1}}, + {"pink", {255, 192, 203, 1}}, + {"plum", {221, 160, 221, 1}}, + {"powderblue", {176, 224, 230, 1}}, + {"purple", {128, 0, 128, 1}}, + {"red", {255, 0, 0, 1}}, + {"rosybrown", {188, 143, 143, 1}}, + {"royalblue", {65, 105, 225, 1}}, + {"saddlebrown", {139, 69, 19, 1}}, + {"salmon", {250, 128, 114, 1}}, + {"sandybrown", {244, 164, 96, 1}}, + {"seagreen", {46, 139, 87, 1}}, + {"seashell", {255, 245, 238, 1}}, + {"sienna", {160, 82, 45, 1}}, + {"silver", {192, 192, 192, 1}}, + {"skyblue", {135, 206, 235, 1}}, + {"slateblue", {106, 90, 205, 1}}, + {"slategray", {112, 128, 144, 1}}, + {"slategrey", {112, 128, 144, 1}}, + {"snow", {255, 250, 250, 1}}, + {"springgreen", {0, 255, 127, 1}}, + {"steelblue", {70, 130, 180, 1}}, + {"tan", {210, 180, 140, 1}}, + {"teal", {0, 128, 128, 1}}, + {"thistle", {216, 191, 216, 1}}, + {"tomato", {255, 99, 71, 1}}, + {"turquoise", {64, 224, 208, 1}}, + {"violet", {238, 130, 238, 1}}, + {"wheat", {245, 222, 179, 1}}, + {"white", {255, 255, 255, 1}}, + {"whitesmoke", {245, 245, 245, 1}}, + {"yellow", {255, 255, 0, 1}}, + {"yellowgreen", {154, 205, 50, 1}}}; + +inline bool operator==(const Color &lhs, const Color &rhs) { + return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && + ::fabs(lhs.a - rhs.a) < 0.0001f; +} + +inline bool operator!=(const Color &lhs, const Color &rhs) { + return !(lhs == rhs); +} + +Color parse(const std::string &css_str); +} // namespace CSSColorParser \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiHostObject.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiHostObject.cpp new file mode 100644 index 00000000000000..684168de1d6f85 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiHostObject.cpp @@ -0,0 +1,150 @@ +#include +#include +#include + +// To be able to find objects that aren't cleaned up correctly, +// we can set this value to 1 and debug the constructor/destructor +#define JSI_DEBUG_ALLOCATIONS 0 + +namespace RNJsi { + +#if JSI_DEBUG_ALLOCATIONS +int objCounter = 0; +std::vector objects; +#endif + +JsiHostObject::JsiHostObject() { +#if JSI_DEBUG_ALLOCATIONS + objects.push_back(this); + objCounter++; +#endif +} +JsiHostObject::~JsiHostObject() { +#if JSI_DEBUG_ALLOCATIONS + for (size_t i = 0; i < objects.size(); ++i) { + if (objects.at(i) == this) { + objects.erase(objects.begin() + i); + break; + } + } + objCounter--; +#endif +} + +void JsiHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name, + const jsi::Value &value) { + + auto nameStr = name.utf8(rt); + + /** Check the static setters map */ + const JsiPropertySettersMap &setters = getExportedPropertySettersMap(); + auto setter = setters.find(nameStr); + if (setter != setters.end()) { + auto dispatcher = std::bind(setter->second, this, std::placeholders::_1, + std::placeholders::_2); + return dispatcher(rt, value); + } + + if (_propMap.count(nameStr) > 0) { + auto prop = _propMap.at(nameStr); + (prop.set)(rt, value); + } +} + +jsi::Value JsiHostObject::get(jsi::Runtime &runtime, + const jsi::PropNameID &name) { + auto nameStr = name.utf8(runtime); + + // Happy path - cached host functions are cheapest to look up + const JsiFunctionMap &funcs = getExportedFunctionMap(); + auto func = funcs.find(nameStr); + + // Check function cache + if (func != funcs.end()) { + std::map &runtimeCache = + _hostFunctionCache.get(runtime); + auto cachedFunc = runtimeCache.find(nameStr); + if (cachedFunc != runtimeCache.end()) { + return cachedFunc->second.asFunction(runtime); + } + } + + // Check the static getters map + const JsiPropertyGettersMap &getters = getExportedPropertyGettersMap(); + auto getter = getters.find(nameStr); + if (getter != getters.end()) { + auto dispatcher = std::bind(getter->second, this, std::placeholders::_1); + return dispatcher(runtime); + } + + // Check the static function map + if (func != funcs.end()) { + + // Create dispatcher + auto dispatcher = + std::bind(func->second, reinterpret_cast(this), + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4); + + // Add to cache - it is important to cache the results from the + // createFromHostFunction function which takes some time. + return _hostFunctionCache.get(runtime) + .emplace(nameStr, jsi::Function::createFromHostFunction(runtime, name, + 0, dispatcher)) + .first->second.asFunction(runtime); + } + + if (_funcMap.count(nameStr) > 0) { + return jsi::Function::createFromHostFunction(runtime, name, 0, + _funcMap.at(nameStr)); + } + + if (_propMap.count(nameStr) > 0) { + auto prop = _propMap.at(nameStr); + return (prop.get)(runtime); + } + + return jsi::Value::undefined(); +} + +std::vector +JsiHostObject::getPropertyNames(jsi::Runtime &runtime) { + // statically exported functions + const auto &funcs = getExportedFunctionMap(); + + // Statically exported property getters + const auto &getters = getExportedPropertyGettersMap(); + + // Statically exported property setters + const auto &setters = getExportedPropertySettersMap(); + + std::vector propNames; + propNames.reserve(funcs.size() + getters.size() + setters.size() + + _funcMap.size() + _propMap.size()); + + for (auto it = funcs.cbegin(); it != funcs.cend(); ++it) { + propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first)); + } + + for (auto it = getters.cbegin(); it != getters.cend(); ++it) { + propNames.push_back(jsi::PropNameID::forUtf8(runtime, it->first)); + } + + for (auto it = getters.cbegin(); it != getters.cend(); ++it) { + if (getters.count(it->first) == 0) { + propNames.push_back(jsi::PropNameID::forUtf8(runtime, it->first)); + } + } + + // functions + for (auto it = _funcMap.cbegin(); it != _funcMap.cend(); ++it) { + propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first)); + } + // props + for (auto it = _propMap.cbegin(); it != _propMap.cend(); ++it) { + propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first)); + } + return propNames; +} + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiHostObject.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiHostObject.h new file mode 100644 index 00000000000000..79c1fe42441f43 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiHostObject.h @@ -0,0 +1,370 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include "RuntimeAwareCache.h" + +#define STR_CAT_NX(A, B) A##B +#define STR_CAT(A, B) STR_CAT_NX(A, B) +#define STR_GET get_ +#define STR_SET set_ + +/** + * Creates a new Host function declaration as a lambda with all deps passed + * with implicit lambda capture clause + */ +#define JSI_HOST_FUNCTION_LAMBDA \ + [=](jsi::Runtime & runtime, const jsi::Value &thisValue, \ + const jsi::Value *arguments, size_t count) -> jsi::Value + +/** + * Creates a new Host function declaration + */ +#define JSI_HOST_FUNCTION(NAME) \ + jsi::Value NAME(jsi::Runtime &runtime, const jsi::Value &thisValue, \ + const jsi::Value *arguments, size_t count) + +/** + * Creates a new property setter function declaration + */ +#define JSI_PROPERTY_SET(NAME) \ + void STR_CAT(STR_SET, NAME)(jsi::Runtime & runtime, const jsi::Value &value) + +/** + * Creates a new property getter function declaration + */ +#define JSI_PROPERTY_GET(NAME) \ + jsi::Value STR_CAT(STR_GET, NAME)(jsi::Runtime & runtime) + +/** + * Creates a JSI export function declaration + */ +#define JSI_EXPORT_FUNC(CLASS, FUNCTION) \ + { \ +#FUNCTION, (jsi::Value(JsiHostObject::*)( \ + jsi::Runtime & runtime, const jsi::Value &thisValue, \ + const jsi::Value *arguments, size_t)) & \ + CLASS::FUNCTION \ + } + +/** + * Creates a JSI export functions statement + */ +#define JSI_EXPORT_FUNCTIONS(...) \ + const RNJsi::JsiFunctionMap &getExportedFunctionMap() override { \ + static RNJsi::JsiFunctionMap map = {__VA_ARGS__}; \ + return map; \ + } + +/** + * Creates a JSI export getter declaration + */ +#define JSI_EXPORT_PROP_GET(CLASS, FUNCTION) \ + { \ +#FUNCTION, (jsi::Value(JsiHostObject::*)(jsi::Runtime & runtime)) & \ + CLASS::STR_CAT(STR_GET, FUNCTION) \ + } + +/** + * Creates a JSI export getters statement + */ +#define JSI_EXPORT_PROPERTY_GETTERS(...) \ + const RNJsi::JsiPropertyGettersMap &getExportedPropertyGettersMap() \ + override { \ + static RNJsi::JsiPropertyGettersMap map = {__VA_ARGS__}; \ + return map; \ + } + +/** + * Creates a JSI export setter declaration + */ +#define JSI_EXPORT_PROP_SET(CLASS, FUNCTION) \ + { \ +#FUNCTION, \ + (void(JsiHostObject::*)(jsi::Runtime & runtime, const jsi::Value &)) & \ + CLASS::STR_CAT(STR_SET, FUNCTION) \ + } + +/** + * Creates a JSI export setters statement + */ +#define JSI_EXPORT_PROPERTY_SETTERS(...) \ + const RNJsi::JsiPropertySettersMap &getExportedPropertySettersMap() \ + override { \ + static RNJsi::JsiPropertySettersMap map = {__VA_ARGS__}; \ + return map; \ + } + +namespace RNJsi { + +namespace jsi = facebook::jsi; + +using JsPropertyType = struct { + std::function get; + std::function set; +}; + +class JsiHostObject; + +using JsiFunctionMap = + std::unordered_map; + +using JsiPropertyGettersMap = + std::unordered_map; + +using JsiPropertySettersMap = + std::unordered_map; + +/** + * Base class for jsi host objects + */ +class JsiHostObject : public jsi::HostObject { +public: + JsiHostObject(); + ~JsiHostObject(); + + /** + * Overridden jsi::HostObject set property method + * @param rt Runtime + * @param name Name of value to set + * @param value Value to set + */ + void set(jsi::Runtime &rt, const jsi::PropNameID &name, + const jsi::Value &value) override; + + /** + * Overridden jsi::HostObject get property method. Returns functions from + * the map of functions. + * @param runtime Runtime + * @param name Name of value to get + * @return Value + */ + jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override; + + /** + * Overridden getPropertyNames from jsi::HostObject. Returns all keys in the + * function and property maps + * @param runtime Runtime + * @return List of property names + */ + std::vector getPropertyNames(jsi::Runtime &runtime) override; + +protected: + /** + Override to return map of name/functions + */ + virtual const RNJsi::JsiFunctionMap &getExportedFunctionMap() { + static const RNJsi::JsiFunctionMap empty; + return empty; + } + + /** + Override to get property getters map of name/functions + */ + virtual const JsiPropertyGettersMap &getExportedPropertyGettersMap() { + static const JsiPropertyGettersMap empty; + return empty; + } + + /** + Override to get property setters map of name/functions + */ + virtual const JsiPropertySettersMap &getExportedPropertySettersMap() { + static const JsiPropertySettersMap empty; + return empty; + } + + /** + * Installs a function into the function map + */ + void installFunction(const std::string &name, + const jsi::HostFunctionType &function) { + _funcMap.emplace(name, function); + } + + /** + * Installs a property with get/set + * @param name Name of property to install + * @param get Getter function + * @param set Setter function + */ + void installProperty( + const std::string &name, + const std::function &get, + const std::function &set) { + _propMap.emplace(name, JsPropertyType{.get = get, .set = set}); + } + + /** + * Installs a property with only getter + * @param name Name of property to install + * @param get Getter function + */ + void installReadonlyProperty( + const std::string &name, + const std::function &get) { + _propMap.emplace(name, JsPropertyType{ + .get = get, + .set = [](jsi::Runtime &, const jsi::Value &) {}, + }); + } + + /** + * Installs a property which points to a given host object + * @param name Name of property to install + * @param hostObject Object to return + */ + void installReadonlyProperty(const std::string &name, + std::shared_ptr hostObject) { + _propMap.emplace(name, JsPropertyType{ + .get = + [hostObject](jsi::Runtime &runtime) { + return jsi::Object::createFromHostObject( + runtime, hostObject); + }, + .set = [](jsi::Runtime &, const jsi::Value &) {}, + }); + } + + /** + @Returns a reference to the argument at the given position in the arguments + array. Raises an error if the index is above the number of arguments. + @param runtime jsi::Runtime + @param arguments Arguments list + @param count Number of arguments in arguments list + @param index Index of parameter to return + */ + static const jsi::Value &getArgument(jsi::Runtime &runtime, + const jsi::Value *arguments, + size_t count, size_t index) { + if (index >= count) { + throw jsi::JSError(runtime, "Argument index out of bounds."); + } + + return arguments[index]; + } + + /** + Returns argument as number or throws + */ + static double getArgumentAsNumber(jsi::Runtime &runtime, + const jsi::Value *arguments, size_t count, + size_t index) { + const jsi::Value &value = getArgument(runtime, arguments, count, index); + if (!value.isNumber()) { + throw jsi::JSError(runtime, + "Expected type number for parameter at index " + + std::to_string(index)); + } + return value.asNumber(); + } + + /** + Returns argument as bool or throws + */ + static bool getArgumentAsBool(jsi::Runtime &runtime, + const jsi::Value *arguments, size_t count, + size_t index) { + const jsi::Value &value = getArgument(runtime, arguments, count, index); + if (!value.isBool()) { + throw jsi::JSError(runtime, + "Expected type boolean for parameter at index " + + std::to_string(index)); + } + return value.getBool(); + } + + /** + Returns argument as string or throws + */ + static jsi::String getArgumentAsString(jsi::Runtime &runtime, + const jsi::Value *arguments, + size_t count, size_t index) { + const jsi::Value &value = getArgument(runtime, arguments, count, index); + if (!value.isString()) { + throw jsi::JSError(runtime, + "Expected type string for parameter at index " + + std::to_string(index)); + } + return value.asString(runtime); + } + + /** + Returns argument as object or throws + */ + static jsi::Object getArgumentAsObject(jsi::Runtime &runtime, + const jsi::Value *arguments, + size_t count, size_t index) { + const jsi::Value &value = getArgument(runtime, arguments, count, index); + if (!value.isObject()) { + throw jsi::JSError(runtime, + "Expected type object for parameter at index " + + std::to_string(index)); + } + return value.asObject(runtime); + } + + /** + Returns argument as host object or throws + */ + template + static std::shared_ptr + getArgumentAsHostObject(jsi::Runtime &runtime, const jsi::Value *arguments, + size_t count, size_t index) { + auto value = getArgumentAsObject(runtime, arguments, count, index); + if (!value.isHostObject(runtime)) { + throw jsi::JSError(runtime, + "Expected type host object for parameter at index " + + std::to_string(index)); + } + return value.asHostObject(runtime); + } + + /** + Returns argument as array or throws + */ + static jsi::Array getArgumentAsArray(jsi::Runtime &runtime, + const jsi::Value *arguments, + size_t count, size_t index) { + auto value = getArgumentAsObject(runtime, arguments, count, index); + if (!value.isArray(runtime)) { + throw jsi::JSError(runtime, + "Expected type array for parameter at index " + + std::to_string(index)); + } + return value.asArray(runtime); + } + + /** + Returns argument as function or throws + */ + static jsi::Object getArgumentAsFunction(jsi::Runtime &runtime, + const jsi::Value *arguments, + size_t count, size_t index) { + auto value = getArgumentAsObject(runtime, arguments, count, index); + if (!value.isFunction(runtime)) { + throw jsi::JSError(runtime, + "Expected type function for parameter at index " + + std::to_string(index)); + } + return value.asFunction(runtime); + } + +private: + std::unordered_map _funcMap; + std::unordered_map _propMap; + + RuntimeAwareCache> _hostFunctionCache; +}; +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValue.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValue.cpp new file mode 100644 index 00000000000000..d67d8a679ddd17 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValue.cpp @@ -0,0 +1,346 @@ +#include "JsiValue.h" + +namespace RNJsi { + +JsiValue::JsiValue() : _type(PropType::Undefined) {} + +JsiValue::JsiValue(jsi::Runtime &runtime, const jsi::Value &value) + : JsiValue() { + setCurrent(runtime, value); +} + +void JsiValue::setCurrent(jsi::Runtime &runtime, const jsi::Value &value) { + _stringValue = ""; + _hostObject = nullptr; + _hostFunction = nullptr; + _props.clear(); + _array.clear(); + _keysCache.clear(); + + if (value.isNumber()) { + _type = PropType::Number; + _numberValue = value.asNumber(); + } else if (value.isBool()) { + _type = PropType::Bool; + _boolValue = value.getBool(); + } else if (value.isString()) { + _type = PropType::String; + _stringValue = value.asString(runtime).utf8(runtime); + } else if (value.isUndefined()) { + _type = PropType::Undefined; + } else if (value.isNull()) { + _type = PropType::Null; + } else if (value.isObject()) { + setObject(runtime, value); + } else { + throw std::runtime_error("Could not store jsi::Value of provided type"); + } +} + +bool JsiValue::getAsBool() const { + if (_type != PropType::Bool) { + throw std::runtime_error("Expected type bool, got " + + getTypeAsString(_type)); + } + return _boolValue; +} + +double JsiValue::getAsNumber() const { + if (_type != PropType::Number) { + throw std::runtime_error("Expected type number, got " + + getTypeAsString(_type)); + } + return _numberValue; +} + +const std::string &JsiValue::getAsString() const { + if (_type == PropType::Number) { + return std::move(std::to_string(_numberValue)); + } + + if (_type != PropType::String) { + throw std::runtime_error("Expected type string, got " + + getTypeAsString(_type)); + } + return _stringValue; +} + +const std::vector &JsiValue::getAsArray() const { + if (_type != PropType::Array) { + throw std::runtime_error("Expected type array, got " + + getTypeAsString(_type)); + } + return _array; +} + +const JsiValue &JsiValue::getValue(PropId name) const { + if (_type != PropType::Object) { + throw std::runtime_error("Expected type object, got " + + getTypeAsString(_type)); + } + return _props.at(name); +} + +bool JsiValue::hasValue(PropId name) const { + if (_type != PropType::Object) { + throw std::runtime_error("Expected type object, got " + + getTypeAsString(_type)); + } + return _props.count(name) > 0; +} + +std::vector JsiValue::getKeys() const { + if (_type != PropType::Object) { + throw std::runtime_error("Expected type object, got " + + getTypeAsString(_type)); + } + return _keysCache; +} + +std::shared_ptr JsiValue::getAsHostObject() const { + if (_type != PropType::HostObject) { + throw std::runtime_error("Expected type host object, got " + + getTypeAsString(_type)); + } + return _hostObject; +} + +jsi::HostFunctionType JsiValue::getAsHostFunction() const { + if (_type != PropType::HostFunction) { + throw std::runtime_error("Expected type host function, got " + + getTypeAsString(_type)); + } + return _hostFunction; +} + +const jsi::HostFunctionType JsiValue::getAsFunction() const { + return getAsHostFunction(); +} + +std::string JsiValue::asString() const { + switch (_type) { + case PropType::Null: + return "(null)"; + case PropType::Undefined: + return "(undefined)"; + case PropType::Number: + return std::to_string(_numberValue); + case PropType::Bool: + return std::to_string(_boolValue); + case PropType::String: + return _stringValue; + case PropType::Object: + return "[Object]"; + case PropType::Array: + return "[Array]"; + case PropType::HostObject: + return "[HostObject]"; + case PropType::HostFunction: + return "[HostFunction]"; + } +} + +jsi::Value JsiValue::getAsJsiValue(jsi::Runtime &runtime) const { + switch (_type) { + case PropType::Undefined: + return jsi::Value::undefined(); + case PropType::Null: + return jsi::Value::null(); + case PropType::Number: + return _numberValue; + case PropType::Bool: + return _boolValue; + case PropType::String: + return jsi::String::createFromUtf8(runtime, _stringValue); + case PropType::Object: + return getObject(runtime); + case PropType::Array: + return getArray(runtime); + case PropType::HostObject: + return getHostObject(runtime); + case PropType::HostFunction: + return getHostFunction(runtime); + } +} + +std::string JsiValue::getTypeAsString(PropType type) { + switch (type) { + case PropType::Undefined: + return "undefined"; + case PropType::Null: + return "null"; + case PropType::Number: + return "number"; + case PropType::Bool: + return "boolean"; + case PropType::String: + return "string"; + case PropType::Object: + return "object"; + case PropType::Array: + return "array"; + case PropType::HostObject: + return "hostobject"; + case PropType::HostFunction: + return "hostfunction"; + } +} + +void JsiValue::setObject(jsi::Runtime &runtime, const jsi::Value &value) { + auto obj = value.asObject(runtime); + if (obj.isFunction(runtime)) { + setFunction(runtime, value); + } else if (obj.isArray(runtime)) { + setArray(runtime, obj); + } else if (obj.isHostObject(runtime)) { + setHostObject(runtime, obj); + } else { + _type = PropType::Object; + // Read object keys + auto keys = obj.getPropertyNames(runtime); + size_t size = keys.size(runtime); + _keysCache.clear(); + _keysCache.reserve(size); + _props.clear(); + _props.reserve(size); + + for (size_t i = 0; i < size; ++i) { + auto key = JsiPropId::get( + keys.getValueAtIndex(runtime, i).asString(runtime).utf8(runtime)); + try { + _props.try_emplace(key, runtime, obj.getProperty(runtime, key)); + _keysCache.push_back(key); + } catch (jsi::JSError e) { + throw jsi::JSError(runtime, + "Could not set property for key " + + std::string(key) + ":\n" + e.getMessage(), + e.getStack()); + } + } + } +} + +jsi::Object JsiValue::getObject(jsi::Runtime &runtime) const { + assert(_type == PropType::Object); + auto obj = jsi::Object(runtime); + for (auto &p : _props) { + obj.setProperty(runtime, p.first, p.second.getAsJsiValue(runtime)); + } + return obj; +} + +bool JsiValue::operator!=(const JsiValue &other) const { + return !(this->operator==(other)); +} + +bool JsiValue::operator==(const JsiValue &other) const { + + if (other.getType() != getType()) { + return false; + } + + switch (_type) { + case PropType::Null: + case PropType::Undefined: + return true; + case PropType::Number: + return _numberValue == other.getAsNumber(); + case PropType::Bool: + return _boolValue == other.getAsBool(); + case PropType::String: + return _stringValue == other.getAsString(); + case PropType::Object: { + if (_props.size() != other.getProps().size()) { + return false; + } + for (auto &p : _props) { + auto t = p.second.operator==(other.getValue(p.first)); + if (!t) { + return false; + } + } + return true; + } + case PropType::Array: { + auto otherArr = other.getAsArray(); + if (_array.size() != otherArr.size()) { + return false; + } + for (size_t i = 0; i < _array.size(); ++i) { + if (!_array[i].operator==(otherArr[i])) { + return false; + } + } + return true; + } + case PropType::HostObject: + return getAsHostObject() == other.getAsHostObject(); + case PropType::HostFunction: + // Unable to compare host functions + return false; + } + + throw std::runtime_error( + "Wrong type in equals call. Should not happen. File a bug."); + + return false; +} + +void JsiValue::setFunction(jsi::Runtime &runtime, const jsi::Value &value) { + auto func = value.asObject(runtime).asFunction(runtime); + if (func.isHostFunction(runtime)) { + _type = PropType::HostFunction; + _hostFunction = func.getHostFunction(runtime); + } else { + _type = PropType::HostFunction; + auto obj = std::make_shared(value.asObject(runtime)); + _hostFunction = [obj](jsi::Runtime &runtime, const jsi::Value &thisValue, + const jsi::Value *arguments, + size_t count) -> jsi::Value { + auto func = obj->asFunction(runtime); + if (thisValue.isNull() || thisValue.isUndefined()) { + return func.call(runtime, arguments, count); + } else { + return func.callWithThis(runtime, thisValue.asObject(runtime), + arguments, count); + } + }; + } +} + +jsi::Object JsiValue::getHostFunction(jsi::Runtime &runtime) const { + assert(_type == PropType::HostFunction); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, "fn"), 0, _hostFunction); +} + +void JsiValue::setArray(jsi::Runtime &runtime, const jsi::Object &obj) { + _type = PropType::Array; + auto arr = obj.asArray(runtime); + size_t size = arr.size(runtime); + _array.reserve(size); + for (size_t i = 0; i < size; ++i) { + _array.emplace_back(runtime, arr.getValueAtIndex(runtime, i)); + } +} + +jsi::Array JsiValue::getArray(jsi::Runtime &runtime) const { + assert(_type == PropType::Array); + jsi::Array arr = jsi::Array(runtime, _array.size()); + for (size_t i = 0; i < _array.size(); ++i) { + arr.setValueAtIndex(runtime, i, _array[i].getAsJsiValue(runtime)); + } + return arr; +} + +void JsiValue::setHostObject(jsi::Runtime &runtime, const jsi::Object &obj) { + _type = PropType::HostObject; + _hostObject = obj.asHostObject(runtime); +} + +jsi::Object JsiValue::getHostObject(jsi::Runtime &runtime) const { + assert(_type == PropType::HostObject); + return jsi::Object::createFromHostObject(runtime, _hostObject); +} + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValue.h new file mode 100644 index 00000000000000..88a72203ea6aa4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValue.h @@ -0,0 +1,222 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace RNJsi { + +namespace jsi = facebook::jsi; + +enum struct PropType { + Undefined = 0, + Null = 1, // Keep undefined / null constant so that we can do checks faster + Bool = 2, + Number = 3, + String = 4, + Object = 5, + HostObject = 6, + HostFunction = 7, + Array = 8 +}; + +using PropId = const char *; + +class JsiPropId { +public: + static const char *get(const std::string &name) { return _get(name); } + + static const char *get(const std::string &&name) { + return _get(std::move(name)); + } + +private: + static const char *_get(const std::string &name) { + if (_impls().count(name) == 0) { + // Alloc string + char *impl = new char[name.size() + 1]; + strncpy(impl, name.c_str(), name.size() + 1); + _impls().emplace(name, impl); + } + return _impls().at(name); + } + + static std::unordered_map &_impls() { + static std::unordered_map impls; + return impls; + } +}; + +/** + This is a class that deep copies values from JS to C++. + */ +class JsiValue { +public: + /** + Default constructor for an empty JsiValue + */ + JsiValue(); + + /** + Constructs an instance of the JsiValue object with a current value + */ + JsiValue(jsi::Runtime &runtime, const jsi::Value &value); + + /** + Updates the current value from the Javascript value. This function will + perform a deep copy of the javascript value. + */ + void setCurrent(jsi::Runtime &runtime, const jsi::Value &value); + + /** + Returns the type of value contained in this JsiValue + */ + PropType getType() const { return _type; } + + /** + Returns true if the value is undefined or null. + */ + bool isUndefinedOrNull() const { return _type <= PropType::Null; } + + /** + Returns true if the value is undefined. + */ + bool isUndefined() const { return _type == PropType::Undefined; } + + /** + Returns true if the value is null. + */ + bool isNull() const { return _type == PropType::Null; } + + /** + Returns the bool value. Requires that the underlying type is bool + */ + bool getAsBool() const; + + /** + Returns the numeric value. Requires that the underlying type is number + */ + double getAsNumber() const; + + /** + Returns the string value. Requires that the underlying type is string + */ + const std::string &getAsString() const; + + /** + Returns the array value. Requires that the underlying type is array + */ + const std::vector &getAsArray() const; + + /** + Returns an inner value by name. Requires that the underlying type is Object + */ + const JsiValue &getValue(PropId name) const; + + /** + Returns true if the underlying type is Object and the property name exists. + */ + bool hasValue(PropId name) const; + + /** + Returns the names of the properties stored in this value + */ + std::vector getKeys() const; + + /** + Returns the host object value. Requires that the underlying type is Host + Object + */ + std::shared_ptr getAsHostObject() const; + + /** + Returns a dynamic cast of the host object value. Requires that the underlying + type is Host Object + */ + template std::shared_ptr getAs() const { + if (_type != PropType::HostObject) { + throw std::runtime_error("Expected type host object, got " + + getTypeAsString(_type)); + } + return std::dynamic_pointer_cast(_hostObject); + } + + /** + Returns the host function. Requires that the type is HostFunction + */ + jsi::HostFunctionType getAsHostFunction() const; + + /** + Returns a callable HostFunction representing the undderlying js function. + Requires that the type is Function + */ + const jsi::HostFunctionType getAsFunction() const; + + /** + Returns a string representation of the value + */ + std::string asString() const; + + /** + Converts the underlying value back to a JS value + */ + jsi::Value getAsJsiValue(jsi::Runtime &runtime) const; + + /** + Returns a string representing the type. + */ + static std::string getTypeAsString(PropType type); + + /** + Implements the equals operator + */ + bool operator==(const JsiValue &other) const; + + /** + Implements the inequals operator + */ + bool operator!=(const JsiValue &other) const; + +protected: + const std::unordered_map &getProps() const { + return _props; + } + + bool boolValue() const { return _boolValue; } + double numberValue() const { return _numberValue; } + std::string stringValue() const { return _stringValue; } + std::shared_ptr hostObject() const { return _hostObject; } + jsi::HostFunctionType hostFunction() const { return _hostFunction; } + std::vector array() const { return _array; } + std::unordered_map props() const { return _props; } + const std::vector &keysCache() const { return _keysCache; } + +private: + void setObject(jsi::Runtime &runtime, const jsi::Value &value); + jsi::Object getObject(jsi::Runtime &runtime) const; + + void setFunction(jsi::Runtime &runtime, const jsi::Value &value); + jsi::Object getHostFunction(jsi::Runtime &runtime) const; + + void setArray(jsi::Runtime &runtime, const jsi::Object &obj); + jsi::Array getArray(jsi::Runtime &runtime) const; + + void setHostObject(jsi::Runtime &runtime, const jsi::Object &obj); + jsi::Object getHostObject(jsi::Runtime &runtime) const; + + PropType _type = PropType::Undefined; + bool _boolValue; + double _numberValue; + std::string _stringValue = ""; + std::shared_ptr _hostObject; + jsi::HostFunctionType _hostFunction; + std::vector _array; + std::unordered_map _props; + std::vector _keysCache; +}; + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValueWrapper.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValueWrapper.h new file mode 100644 index 00000000000000..62762ff658c254 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/JsiValueWrapper.h @@ -0,0 +1,164 @@ +#pragma once + +#include +#include +#include + +namespace RNJsi { +namespace jsi = facebook::jsi; + +enum JsiWrapperValueType { + NonInitialized, + Undefined, + Null, + Bool, + Number, + String, + Object, + Function, + Array, + HostObject, + Unknown +}; + +/** + Implements a simple wrapper class for JSI values where the value can be read + without asking the runtime for any assistance Meaning that we can access + members without being on the JS thread. + */ +class JsiValueWrapper { +public: + explicit JsiValueWrapper(jsi::Runtime &runtime) + : _type(JsiWrapperValueType::Undefined) {} + + JsiValueWrapper(jsi::Runtime &runtime, const jsi::Value &value) + : JsiValueWrapper(runtime) { + setCurrent(runtime, value); + } + + void setCurrent(jsi::Runtime &runtime, const jsi::Value &value) { + if (value.isNumber()) { + _type = JsiWrapperValueType::Number; + _numberValue = value.asNumber(); + } else if (value.isBool()) { + _type = JsiWrapperValueType::Bool; + _boolValue = value.getBool(); + } else if (value.isString()) { + _type = JsiWrapperValueType::String; + _stringValue = value.asString(runtime).utf8(runtime); + } else if (value.isUndefined()) { + _type = JsiWrapperValueType::Undefined; + } else if (value.isNull()) { + _type = JsiWrapperValueType::Null; + } else if (value.isObject()) { + _type = JsiWrapperValueType::Object; + _objectValue = std::make_shared(value.asObject(runtime)); + if (_objectValue->isFunction(runtime)) { + _type = JsiWrapperValueType::Function; + _functionValue = + std::make_shared(_objectValue->asFunction(runtime)); + _objectValue = nullptr; + } else if (_objectValue->isArray(runtime)) { + _type = JsiWrapperValueType::Array; + _arrayValue = + std::make_shared(_objectValue->asArray(runtime)); + _objectValue = nullptr; + } else if (_objectValue->isHostObject(runtime)) { + _type = JsiWrapperValueType::HostObject; + _hostObjectValue = _objectValue->asHostObject(runtime); + _objectValue = nullptr; + } + } else { + throw std::runtime_error("Could not store jsi::Value of provided type"); + } + // Save in value holder as well so that we can return current + if (_valueHolder == nullptr) { + _valueHolder = std::make_shared(runtime); + } + _valueHolder->setProperty(runtime, "current", value); + } + + jsi::Value getCurrent(jsi::Runtime &runtime) { + if (_valueHolder == nullptr) { + return jsi::Value::undefined(); + } + return _valueHolder->getProperty(runtime, "current"); + } + + bool isUndefinedOrNull() { return isUndefined() || isNull(); } + + bool isUndefined() { return _type == JsiWrapperValueType::Undefined; } + + bool isNull() { return _type == JsiWrapperValueType::Null; } + + bool getAsBool() { + assert(_type == JsiWrapperValueType::Bool); + return _boolValue; + } + + double getAsNumber() { + assert(_type == JsiWrapperValueType::Number); + return _numberValue; + } + + const std::string &getAsString() { + assert(_type == JsiWrapperValueType::String); + return _stringValue; + } + + std::shared_ptr getAsFunction() { + assert(_type == JsiWrapperValueType::Function); + return _functionValue; + } + + std::shared_ptr getAsArray() { + assert(_type == JsiWrapperValueType::Array); + return _arrayValue; + } + + std::shared_ptr getAsObject() { + assert(_type == JsiWrapperValueType::Object); + return _objectValue; + } + + std::shared_ptr getAsHostObject() { + assert(_type == JsiWrapperValueType::HostObject); + return _hostObjectValue; + } + + JsiWrapperValueType getType() { return _type; } + + bool equals(jsi::Runtime &runtime, const jsi::Value &value) { + if (value.isNumber() && _type == JsiWrapperValueType::Number) { + return _numberValue == value.asNumber(); + } else if (value.isBool() && _type == JsiWrapperValueType::Bool) { + return _boolValue == value.getBool(); + } else if (value.isUndefined()) { + return _type == JsiWrapperValueType::Undefined; + } else if (value.isNull()) { + return _type == JsiWrapperValueType::Null; + } else if (value.isString()) { + auto current = getCurrent(runtime); + if (current.isString()) { + return jsi::String::strictEquals(runtime, value.asString(runtime), + current.asString(runtime)); + } + return false; + } + return false; + } + +private: + std::shared_ptr _valueHolder; + + bool _boolValue; + double _numberValue; + std::string _stringValue; + std::shared_ptr _objectValue; + std::shared_ptr _functionValue; + std::shared_ptr _arrayValue; + std::shared_ptr _hostObjectValue; + + JsiWrapperValueType _type; +}; +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeAwareCache.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeAwareCache.cpp new file mode 100644 index 00000000000000..ec9d5bad74242e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeAwareCache.cpp @@ -0,0 +1,7 @@ +#include "RuntimeAwareCache.h" + +namespace RNJsi { + +jsi::Runtime *BaseRuntimeAwareCache::_mainRuntime = nullptr; + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeAwareCache.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeAwareCache.h new file mode 100644 index 00000000000000..2b5f16b53af7e5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeAwareCache.h @@ -0,0 +1,101 @@ +#pragma once + +#include + +#include +#include +#include + +#include "RuntimeLifecycleMonitor.h" + +namespace RNJsi { + +namespace jsi = facebook::jsi; + +class BaseRuntimeAwareCache { +public: + static void setMainJsRuntime(jsi::Runtime *rt) { _mainRuntime = rt; } + +protected: + static jsi::Runtime *getMainJsRuntime() { + assert(_mainRuntime != nullptr && + "Expected main Javascript runtime to be set in the " + "BaseRuntimeAwareCache class."); + + return _mainRuntime; + } + +private: + static jsi::Runtime *_mainRuntime; +}; + +/** + * Provides a way to keep data specific to a jsi::Runtime instance that gets + * cleaned up when that runtime is destroyed. This is necessary because JSI does + * not allow for its associated objects to be retained past the runtime + * lifetime. If an object (e.g. jsi::Values or jsi::Function instances) is kept + * after the runtime is torn down, its destructor (once it is destroyed + * eventually) will result in a crash (JSI objects keep a pointer to memory + * managed by the runtime, accessing that portion of the memory after runtime is + * deleted is the root cause of that crash). + * + * In order to provide an efficient implementation that does not add an overhead + * for the cases when only a single runtiome is used, which is the primary + * usecase, the following assumption has been made: Only for secondary runtimes + * we track destruction and clean up the store associated with that runtime. For + * the first runtime we assume that the object holding the store is destroyed + * prior to the destruction of that runtime. + * + * The above assumption makes it work without any overhead when only single + * runtime is in use. Specifically, we don't perform any additional operations + * related to tracking runtime lifecycle when only a single runtime is used. + */ +template +class RuntimeAwareCache : public BaseRuntimeAwareCache, + public RuntimeLifecycleListener { + +public: + void onRuntimeDestroyed(jsi::Runtime *rt) override { + if (getMainJsRuntime() != rt) { + // We are removing a secondary runtime + _secondaryRuntimeCaches.erase(rt); + } + } + + ~RuntimeAwareCache() { + for (auto &cache : _secondaryRuntimeCaches) { + RuntimeLifecycleMonitor::removeListener( + *static_cast(cache.first), this); + } + } + + T &get(jsi::Runtime &rt) { + // We check if we're accessing the main runtime - this is the happy path + // to avoid us having to lookup by runtime for caches that only has a single + // runtime + if (getMainJsRuntime() == &rt) { + return _primaryCache; + } else { + if (_secondaryRuntimeCaches.count(&rt) == 0) { + // we only add listener when the secondary runtime is used, this assumes + // that the secondary runtime is terminated first. This lets us avoid + // additional complexity for the majority of cases when objects are not + // shared between runtimes. Otherwise we'd have to register all objecrts + // with the RuntimeMonitor as opposed to only registering ones that are + // used in secondary runtime. Note that we can't register listener here + // with the primary runtime as it may run on a separate thread. + RuntimeLifecycleMonitor::addListener(rt, this); + + T cache; + _secondaryRuntimeCaches.emplace(&rt, std::move(cache)); + } + } + return _secondaryRuntimeCaches.at(&rt); + } + +private: + std::unordered_map _secondaryRuntimeCaches; + T _primaryCache; +}; + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeLifecycleMonitor.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeLifecycleMonitor.cpp new file mode 100644 index 00000000000000..d94b3717c5eac5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeLifecycleMonitor.cpp @@ -0,0 +1,57 @@ +#include "RuntimeLifecycleMonitor.h" + +#include +#include +#include + +namespace RNJsi { + +static std::unordered_map> + listeners; + +struct RuntimeLifecycleMonitorObject : public jsi::HostObject { + jsi::Runtime *_rt; + explicit RuntimeLifecycleMonitorObject(jsi::Runtime *rt) : _rt(rt) {} + ~RuntimeLifecycleMonitorObject() { + auto listenersSet = listeners.find(_rt); + if (listenersSet != listeners.end()) { + for (auto listener : listenersSet->second) { + listener->onRuntimeDestroyed(_rt); + } + listeners.erase(listenersSet); + } + } +}; + +void RuntimeLifecycleMonitor::addListener(jsi::Runtime &rt, + RuntimeLifecycleListener *listener) { + auto listenersSet = listeners.find(&rt); + if (listenersSet == listeners.end()) { + // We install a global host object in the provided runtime, this way we can + // use that host object destructor to get notified when the runtime is being + // terminated. We use a unique name for the object as it gets saved with the + // runtime's global object. + rt.global().setProperty( + rt, "__rnskia_rt_lifecycle_monitor", + jsi::Object::createFromHostObject( + rt, std::make_shared(&rt))); + std::unordered_set newSet; + newSet.insert(listener); + listeners.emplace(&rt, std::move(newSet)); + } else { + listenersSet->second.insert(listener); + } +} + +void RuntimeLifecycleMonitor::removeListener( + jsi::Runtime &rt, RuntimeLifecycleListener *listener) { + auto listenersSet = listeners.find(&rt); + if (listenersSet == listeners.end()) { + // nothing to do here + } else { + listenersSet->second.erase(listener); + } +} + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeLifecycleMonitor.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeLifecycleMonitor.h new file mode 100644 index 00000000000000..baec54f51a4de0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/jsi/RuntimeLifecycleMonitor.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include + +namespace RNJsi { + +namespace jsi = facebook::jsi; + +/** + * Listener interface that allows for getting notified when a jsi::Runtime + * instance is destroyed. + */ +struct RuntimeLifecycleListener { + virtual ~RuntimeLifecycleListener() {} + virtual void onRuntimeDestroyed(jsi::Runtime *) = 0; +}; + +/** + * This class provides an API via static methods for registering and + * unregistering runtime lifecycle listeners. The listeners can be used to + * cleanup any data that references a given jsi::Runtime instance before it gets + * destroyed. + */ +struct RuntimeLifecycleMonitor { + static void addListener(jsi::Runtime &rt, RuntimeLifecycleListener *listener); + static void removeListener(jsi::Runtime &rt, + RuntimeLifecycleListener *listener); +}; + +} // namespace RNJsi diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkAnimation.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkAnimation.h new file mode 100644 index 00000000000000..9abd4418b57f40 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkAnimation.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#include "JsiHostObject.h" +#include "RNSkClockValue.h" +#include "RNSkPlatformContext.h" +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; + +/** + Implements an animation that can be used to drive other values + */ +class RNSkAnimation : public RNSkClockValue { + +public: + RNSkAnimation(std::shared_ptr platformContext, + size_t identifier, jsi::Runtime &runtime, + const jsi::Value *arguments, size_t count) + : RNSkClockValue(platformContext, identifier, runtime, arguments, count) { + // Save the update function + _updateFunction = std::make_shared( + arguments[0].asObject(runtime).asFunction(runtime)); + + // Set state to undefined initially. + _args[1] = jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(cancel) { + stopClock(); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkAnimation, cancel)) + +protected: + void tick(jsi::Runtime &runtime, const jsi::Value &value) override { + // Set up arguments and call the update function + _args[0] = value.asNumber(); + _args[1] = _updateFunction->call( + runtime, static_cast(_args.data()), _args.size()); + + // Get finished + auto finished = + _args[1].asObject(runtime).getProperty(runtime, "finished").getBool(); + if (finished) { + stopClock(); + } + + // Get the next value + auto nextValue = + _args[1].asObject(runtime).getProperty(runtime, "current").asNumber(); + + // Update self + update(runtime, nextValue); + } + +private: + std::shared_ptr _updateFunction; + std::array _args; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDispatchQueue.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDispatchQueue.cpp new file mode 100644 index 00000000000000..d9e1727ee6b552 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDispatchQueue.cpp @@ -0,0 +1,73 @@ +#include "RNSkDispatchQueue.h" + +#include +#include +#include + +namespace RNSkia { + +RNSkDispatchQueue::~RNSkDispatchQueue() { + // Signal to dispatch threads that it's time to wrap up + std::unique_lock lock(lock_); + quit_ = true; + lock.unlock(); + cv_.notify_all(); + + // Wait for threads to finish before we exit + for (size_t i = 0; i < threads_.size(); i++) { + if (threads_[i].joinable()) { + threads_[i].join(); + } + } +} + +RNSkDispatchQueue::RNSkDispatchQueue(std::string name, size_t thread_cnt) + : name_{std::move(name)}, threads_(thread_cnt) { + for (size_t i = 0; i < threads_.size(); i++) { + threads_[i] = + std::thread(&RNSkDispatchQueue::dispatch_thread_handler, this); + } +} + +void RNSkDispatchQueue::dispatch(const fp_t &op) { + std::unique_lock lock(lock_); + q_.push(op); + + // Manual unlocking is done before notifying, to avoid waking up + // the waiting thread only to block again (see notify_one for details) + lock.unlock(); + cv_.notify_one(); +} + +void RNSkDispatchQueue::dispatch(fp_t &&op) { + std::unique_lock lock(lock_); + q_.push(std::move(op)); + + // Manual unlocking is done before notifying, to avoid waking up + // the waiting thread only to block again (see notify_one for details) + lock.unlock(); + cv_.notify_one(); +} + +void RNSkDispatchQueue::dispatch_thread_handler(void) { + std::unique_lock lock(lock_); + + do { + // Wait until we have data or a quit signal + cv_.wait(lock, [this] { return (q_.size() || quit_); }); + + // after wait, we own the lock + if (!quit_ && q_.size()) { + auto op = std::move(q_.front()); + q_.pop(); + + // unlock now that we're done messing with the queue + lock.unlock(); + + op(); + + lock.lock(); + } + } while (!quit_); +} +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDispatchQueue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDispatchQueue.h new file mode 100644 index 00000000000000..a53ce2822b0655 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDispatchQueue.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp +namespace RNSkia { + +class RNSkDispatchQueue { + typedef std::function fp_t; + +public: + explicit RNSkDispatchQueue(std::string name, size_t thread_cnt = 1); + + ~RNSkDispatchQueue(); + + // dispatch and copy + void dispatch(const fp_t &op); + + // dispatch and move + void dispatch(fp_t &&op); + + // Deleted operations + RNSkDispatchQueue(const RNSkDispatchQueue &rhs) = delete; + + RNSkDispatchQueue &operator=(const RNSkDispatchQueue &rhs) = delete; + + RNSkDispatchQueue(RNSkDispatchQueue &&rhs) = delete; + + RNSkDispatchQueue &operator=(RNSkDispatchQueue &&rhs) = delete; + +private: + std::string name_; + std::mutex lock_; + std::vector threads_; + std::queue q_; + std::condition_variable cv_; + bool quit_ = false; + + void dispatch_thread_handler(void); +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDomView.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDomView.cpp new file mode 100644 index 00000000000000..6ff1df7f6fdf46 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDomView.cpp @@ -0,0 +1,220 @@ +#include "RNSkDomView.h" +#include "DrawingContext.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include + +#pragma clang diagnostic pop + +namespace RNSkia { + +RNSkDomRenderer::RNSkDomRenderer(std::function requestRedraw, + std::shared_ptr context) + : RNSkRenderer(requestRedraw), _platformContext(std::move(context)), + _renderLock(std::make_shared()), + _touchCallbackLock(std::make_shared()), + _renderTimingInfo("SKIA/RENDER") {} + +RNSkDomRenderer::~RNSkDomRenderer() { + if (_root != nullptr) { + _root->dispose(true); + _root = nullptr; + } +} + +bool RNSkDomRenderer::tryRender( + std::shared_ptr canvasProvider) { + // If we have touches we need to call the touch callback as well + if (_currentTouches.size() > 0) { + callOnTouch(); + } + + // We render on the main thread + if (_renderLock->try_lock()) { + bool result = false; + // If we have a Dom Node we can render directly on the main thread + if (_root != nullptr) { + result = canvasProvider->renderToCanvas(std::bind( + &RNSkDomRenderer::renderCanvas, this, std::placeholders::_1, + canvasProvider->getScaledWidth(), canvasProvider->getScaledHeight())); + } + + _renderLock->unlock(); + return result; + } else { + return false; + } +} + +void RNSkDomRenderer::renderImmediate( + std::shared_ptr canvasProvider) { + auto prevDebugOverlay = getShowDebugOverlays(); + setShowDebugOverlays(false); + canvasProvider->renderToCanvas(std::bind( + &RNSkDomRenderer::renderCanvas, this, std::placeholders::_1, + canvasProvider->getScaledWidth(), canvasProvider->getScaledHeight())); + setShowDebugOverlays(prevDebugOverlay); +} + +void RNSkDomRenderer::setRoot(std::shared_ptr node) { + std::lock_guard lock(_rootLock); + if (_root != nullptr) { + _root->dispose(true); + _root = nullptr; + } + _root = node; +} + +void RNSkDomRenderer::setOnTouchCallback( + std::shared_ptr onTouchCallback) { + _touchCallback = onTouchCallback; +} + +void RNSkDomRenderer::renderCanvas(SkCanvas *canvas, float scaledWidth, + float scaledHeight) { + _renderTimingInfo.beginTiming(); + + auto pd = _platformContext->getPixelDensity(); + canvas->clear(SK_ColorTRANSPARENT); + canvas->save(); + canvas->scale(pd, pd); + + if (_drawingContext == nullptr) { + _drawingContext = std::make_shared(); + + _drawingContext->setRequestRedraw([weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + self->_requestRedraw(); + } + }); + } + + _drawingContext->setScaledWidth(scaledWidth); + _drawingContext->setScaledHeight(scaledHeight); + + // Update canvas before drawing + _drawingContext->setCanvas(canvas); + + try { + // Ask the root node to render to the provided canvas + std::lock_guard lock(_rootLock); + if (_root != nullptr) { + _root->commitPendingChanges(); + _root->render(_drawingContext.get()); + _root->resetPendingChanges(); + } + } catch (std::runtime_error err) { + _platformContext->raiseError(err); + } catch (jsi::JSError err) { + _platformContext->raiseError(err); + } catch (...) { + _platformContext->raiseError( + std::runtime_error("Error rendering the Skia view.")); + } + + renderDebugOverlays(canvas); + + canvas->restore(); + + _renderTimingInfo.stopTiming(); +} + +void RNSkDomRenderer::updateTouches(std::vector &touches) { + std::lock_guard lock(_touchMutex); + // Add timestamp + auto ms = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + + for (size_t i = 0; i < touches.size(); i++) { + touches.at(i).timestamp = ms; + } + _currentTouches.push_back(std::move(touches)); +} + +void RNSkDomRenderer::callOnTouch() { + + if (_touchCallback == nullptr) { + return; + } + + if (_touchCallbackLock->try_lock()) { + + { + std::lock_guard lock(_touchMutex); + _touchesCache.clear(); + _touchesCache.reserve(_currentTouches.size()); + for (size_t i = 0; i < _currentTouches.size(); ++i) { + _touchesCache.push_back(_currentTouches.at(i)); + } + _currentTouches.clear(); + } + + // We have an onDraw method - use it to render since we don't have a + // DOM-node yet. + _platformContext->runOnJavascriptThread([weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + jsi::Runtime &runtime = *self->_platformContext->getJsRuntime(); + // Set up touches + auto size = self->_touchesCache.size(); + auto ops = jsi::Array(runtime, size); + for (size_t i = 0; i < size; i++) { + auto cur = self->_touchesCache.at(i); + auto curSize = cur.size(); + auto touches = jsi::Array(runtime, curSize); + for (size_t n = 0; n < curSize; n++) { + auto touchObj = jsi::Object(runtime); + auto t = cur.at(n); + touchObj.setProperty(runtime, "x", t.x); + touchObj.setProperty(runtime, "y", t.y); + touchObj.setProperty(runtime, "force", t.force); + touchObj.setProperty(runtime, "type", static_cast(t.type)); + touchObj.setProperty(runtime, "timestamp", + static_cast(t.timestamp) / 1000.0); + touchObj.setProperty(runtime, "id", static_cast(t.id)); + touches.setValueAtIndex(runtime, n, touchObj); + } + ops.setValueAtIndex(runtime, i, touches); + } + // Call on touch callback + self->_touchCallback->call(runtime, ops, 1); + } + self->_touchCallbackLock->unlock(); + }); + } else { + // We'll try next time - schedule a new redraw + _requestRedraw(); + } +} + +void RNSkDomRenderer::renderDebugOverlays(SkCanvas *canvas) { + if (!getShowDebugOverlays()) { + return; + } + auto renderAvg = _renderTimingInfo.getAverage(); + auto fps = _renderTimingInfo.getFps(); + + // Build string + std::ostringstream stream; + stream << "render: " << renderAvg << "ms" + << " fps: " << fps; + + std::string debugString = stream.str(); + + // Set up debug font/paints + auto font = SkFont(); + font.setSize(14); + auto paint = SkPaint(); + paint.setColor(SkColors::kRed); + canvas->drawSimpleText(debugString.c_str(), debugString.size(), + SkTextEncoding::kUTF8, 8, 18, font, paint); +} + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDomView.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDomView.h new file mode 100644 index 00000000000000..5832d3dbcfbb65 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkDomView.h @@ -0,0 +1,140 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "JsiValueWrapper.h" +#include "RNSkView.h" + +#include "JsiDomRenderNode.h" +#include "RNSkInfoParameter.h" +#include "RNSkLog.h" +#include "RNSkPlatformContext.h" +#include "RNSkTimingInfo.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBBHFactory.h" +#include "SkCanvas.h" +#include "SkPictureRecorder.h" + +#pragma clang diagnostic pop + +class SkPicture; +class SkRect; +class SkImage; + +namespace RNSkia { +class JsiSkCanvas; +namespace jsi = facebook::jsi; + +class RNSkDomRenderer : public RNSkRenderer, + public std::enable_shared_from_this { +public: + RNSkDomRenderer(std::function requestRedraw, + std::shared_ptr context); + + ~RNSkDomRenderer(); + + bool tryRender(std::shared_ptr canvasProvider) override; + + void + renderImmediate(std::shared_ptr canvasProvider) override; + + void setRoot(std::shared_ptr node); + + void setOnTouchCallback(std::shared_ptr onTouchCallback); + + void updateTouches(std::vector &touches); + +private: + void callOnTouch(); + void renderCanvas(SkCanvas *canvas, float scaledWidth, float scaledHeight); + void renderDebugOverlays(SkCanvas *canvas); + + std::shared_ptr _platformContext; + std::shared_ptr _touchCallback; + + std::shared_ptr _renderLock; + std::shared_ptr _touchCallbackLock; + + std::shared_ptr _root; + std::shared_ptr _drawingContext; + + RNSkTimingInfo _renderTimingInfo; + + std::mutex _touchMutex; + std::vector> _currentTouches; + std::vector> _touchesCache; + std::mutex _rootLock; +}; + +class RNSkDomView : public RNSkView { +public: + /** + * Constructor + */ + RNSkDomView(std::shared_ptr context, + std::shared_ptr canvasProvider) + : RNSkView(context, canvasProvider, + std::make_shared( + std::bind(&RNSkView::requestRedraw, this), context)) {} + + void updateTouchState(std::vector &touches) override { + std::static_pointer_cast(getRenderer()) + ->updateTouches(touches); + RNSkView::updateTouchState(touches); + } + + void setJsiProperties( + std::unordered_map &props) override { + + RNSkView::setJsiProperties(props); + + for (auto &prop : props) { + if (prop.first == "onTouch") { + if (prop.second.isUndefinedOrNull()) { + // Clear touchCallback + std::static_pointer_cast(getRenderer()) + ->setOnTouchCallback(nullptr); + requestRedraw(); + continue; + + } else if (prop.second.getType() != JsiWrapperValueType::Function) { + // We expect a function for the draw callback custom property + throw std::runtime_error( + "Expected a function for the onTouch property."); + } + + // Save callback + std::static_pointer_cast(getRenderer()) + ->setOnTouchCallback(prop.second.getAsFunction()); + + // Request redraw + requestRedraw(); + + } else if (prop.first == "root") { + // Save root + if (prop.second.isUndefined() || prop.second.isNull()) { + std::static_pointer_cast(getRenderer()) + ->setRoot(nullptr); + } else { + std::static_pointer_cast(getRenderer()) + ->setRoot(std::dynamic_pointer_cast( + prop.second.getAsHostObject())); + } + + // Request redraw + requestRedraw(); + } + } + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkInfoParameter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkInfoParameter.h new file mode 100644 index 00000000000000..aa981d63a3b8aa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkInfoParameter.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "JsiHostObject.h" +#include "RNSkView.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class RNSkInfoObject : public RNJsi::JsiHostObject { +public: + JSI_PROPERTY_GET(width) { return _width; } + JSI_PROPERTY_GET(height) { return _height; } + JSI_PROPERTY_GET(timestamp) { return _timestamp; } + + JSI_PROPERTY_GET(touches) { + auto ops = jsi::Array(runtime, _touchesCache.size()); + for (size_t i = 0; i < _touchesCache.size(); i++) { + auto cur = _touchesCache.at(i); + auto touches = jsi::Array(runtime, cur.size()); + for (size_t n = 0; n < cur.size(); n++) { + auto touchObj = jsi::Object(runtime); + auto t = cur.at(n); + touchObj.setProperty(runtime, "x", t.x); + touchObj.setProperty(runtime, "y", t.y); + touchObj.setProperty(runtime, "force", t.force); + touchObj.setProperty(runtime, "type", static_cast(t.type)); + touchObj.setProperty(runtime, "timestamp", + static_cast(t.timestamp / 1000.0)); + touchObj.setProperty(runtime, "id", static_cast(t.id)); + touches.setValueAtIndex(runtime, n, touchObj); + } + ops.setValueAtIndex(runtime, i, touches); + } + return ops; + } + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(RNSkInfoObject, width), + JSI_EXPORT_PROP_GET(RNSkInfoObject, height), + JSI_EXPORT_PROP_GET(RNSkInfoObject, timestamp), + JSI_EXPORT_PROP_GET(RNSkInfoObject, touches)) + + void beginDrawOperation(int width, int height, double timestamp) { + _width = width; + _height = height; + _timestamp = timestamp; + + // Copy touches so that we can continue to add/receive touch points while + // in the drawing callback. + std::lock_guard lock(_mutex); + _touchesCache.clear(); + _touchesCache.reserve(_currentTouches.size()); + for (size_t i = 0; i < _currentTouches.size(); ++i) { + _touchesCache.push_back(_currentTouches.at(i)); + } + _currentTouches.clear(); + } + + void endDrawOperation() { _touchesCache.clear(); } + + void updateTouches(std::vector &touches) { + std::lock_guard lock(_mutex); + // Add timestamp + auto ms = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + + for (size_t i = 0; i < touches.size(); i++) { + touches.at(i).timestamp = ms; + } + _currentTouches.push_back(std::move(touches)); + } + + RNSkInfoObject() : JsiHostObject() {} + +private: + int _width; + int _height; + double _timestamp; + std::vector> _currentTouches; + std::vector> _touchesCache; + std::mutex _mutex; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsView.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsView.cpp new file mode 100644 index 00000000000000..3c4abb892f3987 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsView.cpp @@ -0,0 +1,211 @@ +#include + +#include "RNSkJsView.h" + +namespace RNSkia { + +RNSkJsRenderer::RNSkJsRenderer(std::function requestRedraw, + std::shared_ptr context) + : RNSkRenderer(requestRedraw), + _jsiCanvas(std::make_shared(context)), + _platformContext(context), + _infoObject(std::make_shared()), + _jsDrawingLock(std::make_shared()), + _gpuDrawingLock(std::make_shared()), + _jsTimingInfo("SKIA/JS"), _gpuTimingInfo("SKIA/GPU") {} + +bool RNSkJsRenderer::tryRender( + std::shared_ptr canvasProvider) { + // We render on the javascript thread. + if (_jsDrawingLock->try_lock()) { + _platformContext->runOnJavascriptThread( + [weakSelf = weak_from_this(), canvasProvider]() { + auto self = weakSelf.lock(); + if (self) { + self->performDraw(canvasProvider); + } + }); + return true; + } else { +#ifdef DEBUG + _jsTimingInfo.markSkipped(); +#endif + return false; + } +} + +void RNSkJsRenderer::renderImmediate( + std::shared_ptr canvasProvider) { + std::chrono::milliseconds ms = + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + canvasProvider->renderToCanvas([&](SkCanvas *canvas) { + // Create jsi canvas + auto jsiCanvas = std::make_shared(_platformContext); + jsiCanvas->setCanvas(canvas); + + drawInJsiCanvas(std::move(jsiCanvas), canvasProvider->getScaledWidth(), + canvasProvider->getScaledHeight(), ms.count() / 1000); + }); +} + +void RNSkJsRenderer::setDrawCallback( + std::shared_ptr drawCallback) { + _drawCallback = drawCallback; +} + +std::shared_ptr RNSkJsRenderer::getInfoObject() { + return _infoObject; +} + +void RNSkJsRenderer::performDraw( + std::shared_ptr canvasProvider) { + // Start timing + _jsTimingInfo.beginTiming(); + + // Record the drawing operations on the JS thread so that we can + // move the actual drawing onto the render thread later + SkPictureRecorder recorder; + SkRTreeFactory factory; + SkCanvas *canvas = + recorder.beginRecording(canvasProvider->getScaledWidth(), + canvasProvider->getScaledHeight(), &factory); + + _jsiCanvas->setCanvas(canvas); + + // Get current milliseconds + std::chrono::milliseconds ms = + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + + try { + // Perform the javascript drawing + drawInJsiCanvas(_jsiCanvas, canvasProvider->getScaledWidth(), + canvasProvider->getScaledHeight(), ms.count() / 1000.0); + + } catch (...) { + _jsTimingInfo.stopTiming(); + _jsDrawingLock->unlock(); + throw; + } + + // Finish drawing operations + auto p = recorder.finishRecordingAsPicture(); + + _jsiCanvas->setCanvas(nullptr); + + // Calculate duration + _jsTimingInfo.stopTiming(); + + if (_gpuDrawingLock->try_lock()) { + + // Post drawing message to the render thread where the picture recorded + // will be sent to the GPU/backend for rendering to screen. + auto gpuLock = _gpuDrawingLock; + _platformContext->runOnRenderThread([weakSelf = weak_from_this(), + p = std::move(p), gpuLock, + canvasProvider]() { + auto self = weakSelf.lock(); + if (self) { + // Draw the picture recorded on the real GPU canvas + self->_gpuTimingInfo.beginTiming(); + + canvasProvider->renderToCanvas( + [p = std::move(p)](SkCanvas *canvas) { canvas->drawPicture(p); }); + + self->_gpuTimingInfo.stopTiming(); + } + // Unlock GPU drawing + gpuLock->unlock(); + }); + } else { +#ifdef DEBUG + _gpuTimingInfo.markSkipped(); +#endif + // Request a new redraw since the last frame was skipped. + _requestRedraw(); + } + + // Unlock JS drawing + _jsDrawingLock->unlock(); +} + +void RNSkJsRenderer::callJsDrawCallback(std::shared_ptr jsiCanvas, + int width, int height, + double timestamp) { + + if (_drawCallback == nullptr) { + return; + } + + // Reset timing info + _jsTimingInfo.reset(); + _gpuTimingInfo.reset(); + + auto runtime = _platformContext->getJsRuntime(); + + // Update info parameter + _infoObject->beginDrawOperation(width, height, timestamp); + + // Set up arguments array + std::vector args(2); + args[0] = jsi::Object::createFromHostObject(*runtime, jsiCanvas); + args[1] = jsi::Object::createFromHostObject(*runtime, _infoObject); + + // To be able to call the drawing function we'll wrap it once again + _drawCallback->call(*runtime, static_cast(args.data()), + static_cast(2)); + + // Reset touches + _infoObject->endDrawOperation(); + + // Draw debug overlays + if (getShowDebugOverlays()) { + + // Display average rendering timer + auto jsAvg = _jsTimingInfo.getAverage(); + // auto jsFps = _jsTimingInfo.getFps(); + + auto gpuAvg = _gpuTimingInfo.getAverage(); + // auto gpuFps = _gpuTimingInfo.getFps(); + + auto total = jsAvg + gpuAvg; + + // Build string + std::ostringstream stream; + stream << "js: " << jsAvg << "ms gpu: " << gpuAvg << "ms " + << " total: " << total << "ms"; + + std::string debugString = stream.str(); + + // Set up debug font/paints + auto font = SkFont(); + font.setSize(14); + auto paint = SkPaint(); + paint.setColor(SkColors::kRed); + jsiCanvas->getCanvas()->drawSimpleText( + debugString.c_str(), debugString.size(), SkTextEncoding::kUTF8, 8, 18, + font, paint); + } +} + +void RNSkJsRenderer::drawInJsiCanvas(std::shared_ptr jsiCanvas, + int width, int height, double time) { + + // Call the draw drawCallback and perform js based drawing + auto skCanvas = jsiCanvas->getCanvas(); + if (_drawCallback != nullptr && skCanvas != nullptr) { + // Make sure to scale correctly + auto pd = _platformContext->getPixelDensity(); + skCanvas->clear(SK_ColorTRANSPARENT); + skCanvas->save(); + skCanvas->scale(pd, pd); + + // Call draw function. + callJsDrawCallback(jsiCanvas, width / pd, height / pd, time); + + skCanvas->restore(); + } +} + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsView.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsView.h new file mode 100644 index 00000000000000..f286682d13c0af --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsView.h @@ -0,0 +1,121 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "JsiValueWrapper.h" +#include "RNSkView.h" + +#include "JsiSkCanvas.h" +#include "RNSkInfoParameter.h" +#include "RNSkLog.h" +#include "RNSkPlatformContext.h" +#include "RNSkTimingInfo.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBBHFactory.h" +#include "SkCanvas.h" +#include "SkPictureRecorder.h" + +#pragma clang diagnostic pop + +class SkPicture; +class SkRect; +class SkImage; + +namespace RNSkia { +class JsiSkCanvas; +namespace jsi = facebook::jsi; + +class RNSkJsRenderer : public RNSkRenderer, + public std::enable_shared_from_this { +public: + RNSkJsRenderer(std::function requestRedraw, + std::shared_ptr context); + + bool tryRender(std::shared_ptr canvasProvider) override; + + void + renderImmediate(std::shared_ptr canvasProvider) override; + + void setDrawCallback(std::shared_ptr drawCallback); + + std::shared_ptr getInfoObject(); + +private: + void performDraw(std::shared_ptr canvasProvider); + + void callJsDrawCallback(std::shared_ptr jsiCanvas, int width, + int height, double timestamp); + + void drawInJsiCanvas(std::shared_ptr jsiCanvas, int width, + int height, double time); + + std::shared_ptr _platformContext; + std::shared_ptr _drawCallback; + std::shared_ptr _jsiCanvas; + std::shared_ptr _jsDrawingLock; + std::shared_ptr _gpuDrawingLock; + std::shared_ptr _infoObject; + RNSkTimingInfo _jsTimingInfo; + RNSkTimingInfo _gpuTimingInfo; +}; + +class RNSkJsView : public RNSkView { +public: + /** + * Constructor + */ + RNSkJsView(std::shared_ptr context, + std::shared_ptr canvasProvider) + : RNSkView(context, canvasProvider, + std::make_shared( + std::bind(&RNSkJsView::requestRedraw, this), context)) {} + + void updateTouchState(std::vector &touches) override { + std::static_pointer_cast(getRenderer()) + ->getInfoObject() + ->updateTouches(touches); + RNSkView::updateTouchState(touches); + } + + void setJsiProperties( + std::unordered_map &props) override { + + RNSkView::setJsiProperties(props); + + for (auto &prop : props) { + if (prop.first == "drawCallback") { + if (prop.second.isUndefinedOrNull()) { + // Clear drawcallback + std::static_pointer_cast(getRenderer()) + ->setDrawCallback(nullptr); + requestRedraw(); + continue; + + } else if (prop.second.getType() != + RNJsi::JsiWrapperValueType::Function) { + // We expect a function for the draw callback custom property + throw std::runtime_error( + "Expected a function for the drawCallback custom property."); + } + + // Save callback + std::static_pointer_cast(getRenderer()) + ->setDrawCallback(prop.second.getAsFunction()); + + // Request redraw + requestRedraw(); + } + } + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsiViewApi.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsiViewApi.h new file mode 100644 index 00000000000000..5096c6dfc288fc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkJsiViewApi.h @@ -0,0 +1,332 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "JsiHostObject.h" +#include "JsiValueWrapper.h" +#include "RNSkPlatformContext.h" +#include "RNSkValue.h" +#include "RNSkView.h" +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; + +using RNSkViewInfo = struct RNSkViewInfo { + RNSkViewInfo() { view = nullptr; } + std::shared_ptr view; + std::unordered_map props; +}; + +class RNSkJsiViewApi : public RNJsi::JsiHostObject, + public std::enable_shared_from_this { +public: + /** + Sets a custom property on a view given a view id. The property name/value + will be stored in a map alongside the id of the view and propagated to the + view when needed. + */ + JSI_HOST_FUNCTION(setJsiProperty) { + if (count != 3) { + _platformContext->raiseError( + std::string("setJsiProperty: Expected 3 arguments, got " + + std::to_string(count) + ".")); + return jsi::Value::undefined(); + } + + if (!arguments[0].isNumber()) { + _platformContext->raiseError( + "setJsiProperty: First argument must be a number"); + return jsi::Value::undefined(); + } + + if (!arguments[1].isString()) { + _platformContext->raiseError("setJsiProperty: Second argument must be " + "the name of the property to set."); + + return jsi::Value::undefined(); + } + auto nativeId = arguments[0].asNumber(); + auto info = getEnsuredViewInfo(nativeId); + + std::lock_guard lock(_mutex); + info->props.insert_or_assign(arguments[1].asString(runtime).utf8(runtime), + RNJsi::JsiValueWrapper(runtime, arguments[2])); + + // Now let's see if we have a view that we can update + if (info->view != nullptr) { + // Update view! + info->view->setNativeId(nativeId); + info->view->setJsiProperties(info->props); + info->props.clear(); + } + + return jsi::Value::undefined(); + } + + /** + Calls a custom command / method on a view by the view id. + */ + JSI_HOST_FUNCTION(callJsiMethod) { + if (count < 2) { + _platformContext->raiseError( + std::string("callCustomCommand: Expected at least 2 arguments, got " + + std::to_string(count) + ".")); + + return jsi::Value::undefined(); + } + + if (!arguments[0].isNumber()) { + _platformContext->raiseError( + "callCustomCommand: First argument must be a number"); + + return jsi::Value::undefined(); + } + + if (!arguments[1].isString()) { + _platformContext->raiseError("callCustomCommand: Second argument must be " + "the name of the action to call."); + + return jsi::Value::undefined(); + } + + auto nativeId = arguments[0].asNumber(); + auto action = arguments[1].asString(runtime).utf8(runtime); + + auto info = getEnsuredViewInfo(nativeId); + + if (info->view == nullptr) { + throw jsi::JSError( + runtime, std::string("callCustomCommand: Could not call action " + + action + " on view - view not ready.") + .c_str()); + + return jsi::Value::undefined(); + } + + // Get arguments + size_t paramsCount = count - 2; + const jsi::Value *params = paramsCount > 0 ? &arguments[2] : nullptr; + return info->view->callJsiMethod(runtime, action, params, paramsCount); + } + + JSI_HOST_FUNCTION(requestRedraw) { + if (count != 1) { + _platformContext->raiseError( + std::string("requestRedraw: Expected 1 arguments, got " + + std::to_string(count) + ".")); + + return jsi::Value::undefined(); + } + + if (!arguments[0].isNumber()) { + _platformContext->raiseError( + "requestRedraw: First argument must be a number"); + + return jsi::Value::undefined(); + } + + // find Skia View + int nativeId = arguments[0].asNumber(); + + auto info = getEnsuredViewInfo(nativeId); + if (info->view != nullptr) { + info->view->requestRedraw(); + } + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(makeImageSnapshot) { + if (count < 1) { + _platformContext->raiseError( + std::string("makeImageSnapshot: Expected at least 1 argument, got " + + std::to_string(count) + ".")); + return jsi::Value::undefined(); + } + + if (!arguments[0].isNumber()) { + _platformContext->raiseError( + "makeImageSnapshot: First argument must be a number"); + return jsi::Value::undefined(); + } + + // find Skia view + int nativeId = arguments[0].asNumber(); + sk_sp image; + auto info = getEnsuredViewInfo(nativeId); + if (info->view != nullptr) { + if (count > 1 && !arguments[1].isUndefined() && !arguments[1].isNull()) { + auto rect = JsiSkRect::fromValue(runtime, arguments[1]); + image = info->view->makeImageSnapshot(rect); + } else { + image = info->view->makeImageSnapshot(nullptr); + } + if (image == nullptr) { + throw jsi::JSError(runtime, + "Could not create image from current surface."); + return jsi::Value::undefined(); + } + return jsi::Object::createFromHostObject( + runtime, std::make_shared(_platformContext, image)); + } + throw jsi::JSError(runtime, "No Skia View currently available."); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(registerValuesInView) { + // Check params + if (!arguments[1].isObject() || + !arguments[1].asObject(runtime).isArray(runtime)) { + throw jsi::JSError(runtime, + "Expected array of Values as second parameter"); + return jsi::Value::undefined(); + } + + // Get identifier of native SkiaView + int nativeId = arguments[0].asNumber(); + + // Get values that should be added as dependencies + auto values = arguments[1].asObject(runtime).asArray(runtime); + std::vector> unsubscribers; + const std::size_t size = values.size(runtime); + unsubscribers.reserve(size); + for (size_t i = 0; i < size; ++i) { + auto value = values.getValueAtIndex(runtime, i) + .asObject(runtime) + .asHostObject(runtime); + + if (value != nullptr) { + // Add change listener + unsubscribers.push_back(value->addListener( + [weakSelf = weak_from_this(), nativeId](jsi::Runtime &) { + auto self = weakSelf.lock(); + if (self) { + auto info = self->getEnsuredViewInfo(nativeId); + if (info->view != nullptr) { + info->view->requestRedraw(); + } + } + })); + } + } + + // Return unsubscribe method that unsubscribes to all values + // that we subscribed to. + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, "unsubscribe"), 0, + JSI_HOST_FUNCTION_LAMBDA { + // decrease dependency count on the Skia View + for (auto &unsub : unsubscribers) { + unsub(); + } + return jsi::Value::undefined(); + }); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkJsiViewApi, setJsiProperty), + JSI_EXPORT_FUNC(RNSkJsiViewApi, callJsiMethod), + JSI_EXPORT_FUNC(RNSkJsiViewApi, registerValuesInView), + JSI_EXPORT_FUNC(RNSkJsiViewApi, requestRedraw), + JSI_EXPORT_FUNC(RNSkJsiViewApi, makeImageSnapshot)) + + /** + * Constructor + * @param platformContext Platform context + */ + explicit RNSkJsiViewApi(std::shared_ptr platformContext) + : JsiHostObject(), _platformContext(platformContext) {} + + /** + * Invalidates the Skia View Api object + */ + void invalidate() { unregisterAll(); } + + /** + Call to remove all draw view infos + */ + void unregisterAll() { + // Unregister all views + auto tempList = _viewInfos; + for (const auto &info : tempList) { + unregisterSkiaView(info.first); + } + std::lock_guard lock(_mutex); + _viewInfos.clear(); + } + + /** + * Registers a skia view + * @param nativeId Id of view to register + * @param view View to register + */ + void registerSkiaView(size_t nativeId, std::shared_ptr view) { + auto info = getEnsuredViewInfo(nativeId); + std::lock_guard lock(_mutex); + info->view = view; + info->view->setNativeId(nativeId); + info->view->setJsiProperties(info->props); + info->props.clear(); + } + + /** + * Unregisters a Skia draw view + * @param nativeId View id + */ + void unregisterSkiaView(size_t nativeId) { + if (_viewInfos.count(nativeId) == 0) { + return; + } + auto info = getEnsuredViewInfo(nativeId); + + std::lock_guard lock(_mutex); + info->view = nullptr; + _viewInfos.erase(nativeId); + } + + /** + Sets a skia draw view for the given id. This function can be used + to mark that an underlying SkiaView is not available (it could be + removed due to ex. a transition). The view can be set to a nullptr + or a valid view, effectively toggling the view's availability. + */ + void setSkiaView(size_t nativeId, std::shared_ptr view) { + if (_viewInfos.find(nativeId) == _viewInfos.end()) { + return; + } + auto info = getEnsuredViewInfo(nativeId); + std::lock_guard lock(_mutex); + if (view != nullptr) { + info->view = view; + info->view->setNativeId(nativeId); + info->view->setJsiProperties(info->props); + info->props.clear(); + } else if (view == nullptr) { + info->view = view; + } + } + +private: + /** + * Creates or returns the callback info object for the given view + * @param nativeId View id + * @return The callback info object for the requested view + */ + RNSkViewInfo *getEnsuredViewInfo(size_t nativeId) { + if (_viewInfos.count(nativeId) == 0) { + RNSkViewInfo info; + std::lock_guard lock(_mutex); + _viewInfos.emplace(nativeId, info); + } + return &_viewInfos.at(nativeId); + } + + std::unordered_map _viewInfos; + std::shared_ptr _platformContext; + std::mutex _mutex; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkManager.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkManager.cpp new file mode 100644 index 00000000000000..819e491d66ba65 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkManager.cpp @@ -0,0 +1,93 @@ +#include "RNSkManager.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; + +RNSkManager::RNSkManager( + jsi::Runtime *jsRuntime, + std::shared_ptr jsCallInvoker, + std::shared_ptr platformContext) + : _jsRuntime(jsRuntime), _jsCallInvoker(jsCallInvoker), + _platformContext(platformContext), + _viewApi(std::make_shared(platformContext)) { + + // Register main runtime + BaseRuntimeAwareCache::setMainJsRuntime(_jsRuntime); + + // Install bindings + installBindings(); +} + +RNSkManager::~RNSkManager() { + invalidate(); + // Free up any references + _viewApi = nullptr; + _jsRuntime = nullptr; + _platformContext = nullptr; + _jsCallInvoker = nullptr; +} + +void RNSkManager::invalidate() { + if (_isInvalidated) { + return; + } + _isInvalidated = true; + + // Invalidate members + _viewApi->invalidate(); + _platformContext->invalidate(); +} + +void RNSkManager::registerSkiaView(size_t nativeId, + std::shared_ptr view) { + if (!_isInvalidated && _viewApi != nullptr) + _viewApi->registerSkiaView(nativeId, view); +} + +void RNSkManager::unregisterSkiaView(size_t nativeId) { + if (!_isInvalidated && _viewApi != nullptr) + _viewApi->unregisterSkiaView(nativeId); +} + +void RNSkManager::setSkiaView(size_t nativeId, std::shared_ptr view) { + if (!_isInvalidated && _viewApi != nullptr) + _viewApi->setSkiaView(nativeId, view); +} + +void RNSkManager::installBindings() { + // Create the API objects and install it on the global object in the + // provided runtime. + + auto skiaApi = std::make_shared(*_jsRuntime, _platformContext); + _jsRuntime->global().setProperty( + *_jsRuntime, "SkiaApi", + jsi::Object::createFromHostObject(*_jsRuntime, std::move(skiaApi))); + + _jsRuntime->global().setProperty( + *_jsRuntime, "SkiaViewApi", + jsi::Object::createFromHostObject(*_jsRuntime, _viewApi)); + + auto skiaValueApi = std::make_shared(_platformContext); + _jsRuntime->global().setProperty( + *_jsRuntime, "SkiaValueApi", + jsi::Object::createFromHostObject(*_jsRuntime, std::move(skiaValueApi))); + + auto skiaDomApi = std::make_shared(_platformContext); + _jsRuntime->global().setProperty( + *_jsRuntime, "SkiaDomApi", + jsi::Object::createFromHostObject(*_jsRuntime, std::move(skiaDomApi))); +} +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkManager.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkManager.h new file mode 100644 index 00000000000000..67370f8a5c8646 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkManager.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +#include "RNSkPlatformContext.h" + +namespace facebook { +namespace react { +class CallInvoker; +} +} // namespace facebook + +namespace RNSkia { +class RNSkView; +class RNSkJsiViewApi; + +namespace jsi = facebook::jsi; +namespace react = facebook::react; + +class RNSkManager { +public: + /** + Initialializes a new instance of the RNSkManager + @param jsRuntime The main JavaScript runtime + @param jsCallInvoker The callinvoker + @param platformContext Context used by wrappers to get platform + functionality + */ + RNSkManager(jsi::Runtime *jsRuntime, + std::shared_ptr jsCallInvoker, + std::shared_ptr platformContext); + + ~RNSkManager(); + + /** + Invalidates the Skia Manager + */ + void invalidate(); + + /** + * Registers a RNSkView with the given native id + * @param nativeId Native view id + * @param view View to register + */ + void registerSkiaView(size_t nativeId, std::shared_ptr view); + + /** + * Unregisters the RNSkView from the list of registered views + * @param nativeId Native view Id + */ + void unregisterSkiaView(size_t nativeId); + + /** + Sets the view pointed to by nativeId to the provided value. + Used when we want to remove a view without unregistering it + - this happens typically on iOS. + */ + void setSkiaView(size_t nativeId, std::shared_ptr view); + + /** + * @return The platform context + */ + std::shared_ptr getPlatformContext() { + return _platformContext; + } + +private: + /** + * Installs the javascript methods for registering/unregistering draw + * callbacks for RNSkViews. Called on installation of the parent native + * module. + */ + void installBindings(); + + jsi::Runtime *_jsRuntime; + std::shared_ptr _platformContext; + std::shared_ptr _jsCallInvoker; + std::shared_ptr _viewApi; + std::atomic _isInvalidated = {false}; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkPictureView.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkPictureView.h new file mode 100644 index 00000000000000..715c304b6a4806 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkPictureView.h @@ -0,0 +1,129 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "JsiValueWrapper.h" +#include "RNSkView.h" + +#include "JsiSkPicture.h" +#include "RNSkInfoParameter.h" +#include "RNSkLog.h" +#include "RNSkPlatformContext.h" +#include "RNSkTimingInfo.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBBHFactory.h" +#include "SkCanvas.h" +#include "SkPictureRecorder.h" + +#pragma clang diagnostic pop + +class SkPicture; +class SkRect; +class SkImage; + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class RNSkPictureRenderer + : public RNSkRenderer, + public std::enable_shared_from_this { +public: + RNSkPictureRenderer(std::function requestRedraw, + std::shared_ptr context) + : RNSkRenderer(requestRedraw), _platformContext(context) {} + + bool tryRender(std::shared_ptr canvasProvider) override { + return performDraw(canvasProvider); + } + + void + renderImmediate(std::shared_ptr canvasProvider) override { + performDraw(canvasProvider); + } + + void setPicture(std::shared_ptr picture) { + if (picture == nullptr) { + _picture = nullptr; + return; + } + + _picture = std::dynamic_pointer_cast(picture); + _requestRedraw(); + } + +private: + bool performDraw(std::shared_ptr canvasProvider) { + canvasProvider->renderToCanvas([=](SkCanvas *canvas) { + // Make sure to scale correctly + auto pd = _platformContext->getPixelDensity(); + canvas->clear(SK_ColorTRANSPARENT); + canvas->save(); + canvas->scale(pd, pd); + + if (_picture != nullptr) { + canvas->drawPicture(_picture->getObject()); + } + + canvas->restore(); + }); + return true; + } + + std::shared_ptr _platformContext; + std::shared_ptr _picture; +}; + +class RNSkPictureView : public RNSkView { +public: + /** + * Constructor + */ + RNSkPictureView(std::shared_ptr context, + std::shared_ptr canvasProvider) + : RNSkView( + context, canvasProvider, + std::make_shared( + std::bind(&RNSkPictureView::requestRedraw, this), context)) {} + + void setJsiProperties( + std::unordered_map &props) override { + + RNSkView::setJsiProperties(props); + + for (auto &prop : props) { + if (prop.first == "picture") { + if (prop.second.isUndefinedOrNull()) { + // Clear picture + std::static_pointer_cast(getRenderer()) + ->setPicture(nullptr); + requestRedraw(); + continue; + } else if (prop.second.getType() != + RNJsi::JsiWrapperValueType::HostObject) { + // We expect a function for the picture custom property + throw std::runtime_error( + "Expected an object for the picture custom property."); + } + + // Save picture + std::static_pointer_cast(getRenderer()) + ->setPicture(prop.second.getAsHostObject()); + + // Request redraw + requestRedraw(); + } + } + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkPlatformContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkPlatformContext.h new file mode 100644 index 00000000000000..f7f9827d40d853 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkPlatformContext.h @@ -0,0 +1,243 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RNSkDispatchQueue.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkData.h" +#include "SkImage.h" +#include "SkStream.h" +#include "SkSurface.h" + +#pragma clang diagnostic pop + +#include + +#include + +namespace RNSkia { + +namespace jsi = facebook::jsi; +namespace react = facebook::react; + +class RNSkPlatformContext { +public: + /** + * Constructor + */ + RNSkPlatformContext(jsi::Runtime *runtime, + std::shared_ptr callInvoker, + float pixelDensity) + : _pixelDensity(pixelDensity), _jsRuntime(runtime), + _callInvoker(callInvoker), + _dispatchQueue( + std::make_unique("skia-render-thread")) { + _jsThreadId = std::this_thread::get_id(); + } + + /** + * Destructor + */ + virtual ~RNSkPlatformContext() { invalidate(); } + + void invalidate() { + if (!_isValid) { + return; + } + // Stop the refresh loop + stopDrawLoop(); + // Notify draw loop listeners once with the invalidated parameter + // set to true signalling that we are done and can clean up. + notifyDrawLoop(true); + _isValid = false; + } + + /* + Returns true if the current execution context is the javascript thread. + */ + bool isOnJavascriptThread() { + return _jsThreadId == std::this_thread::get_id(); + } + + /** + * Schedules the function to be run on the javascript thread async + * @param func Function to run + */ + void runOnJavascriptThread(std::function func) { + if (!_isValid) { + return; + } + _callInvoker->invokeAsync(std::move(func)); + } + + /** + Runs the function on the render thread + */ + void runOnRenderThread(std::function func) { + if (!_isValid) { + return; + } + _dispatchQueue->dispatch(std::move(func)); + } + + /** + * Runs the passed function on the main thread + * @param func Function to run. + */ + virtual void runOnMainThread(std::function func) = 0; + + /** + * Takes a screenshot of a given view represented by the view tag + * @param tag React view tag + */ + virtual sk_sp takeScreenshotFromViewTag(size_t tag) = 0; + + /** + Returns the javascript runtime + */ + jsi::Runtime *getJsRuntime() { return _jsRuntime; } + + /** + * Returns an SkStream wrapping the require uri provided. + * @param sourceUri Uri for the resource to load as a string + * @op Operation to execute when the stream has successfuly been loaded. + */ + virtual void performStreamOperation( + const std::string &sourceUri, + const std::function)> &op) = 0; + + /** + * Raises an exception on the platform. This function does not necessarily + * throw an exception and stop execution, so it is important to stop execution + * by returning after calling the function + * @param err Error to raise + */ + virtual void raiseError(const std::exception &err) = 0; + + /** + * Creates an offscreen surface + * @param width Width of the offscreen surface + * @param height Height of the offscreen surface + * @return sk_sp + */ + virtual sk_sp makeOffscreenSurface(int width, int height) = 0; + + /** + * Creates an skImage containing the screenshot of a native view and its + * children. + * @param viewTag React viewtag + * @param callback Called when image is ready or with null if something + * failed. + */ + virtual void + makeViewScreenshot(int viewTag, + std::function)> callback) { + runOnMainThread([this, callback, viewTag]() { + callback(takeScreenshotFromViewTag(viewTag)); + }); + } + + /** + * Raises an exception on the platform. This function does not necessarily + * throw an exception and stop execution, so it is important to stop execution + * by returning after calling the function + * @param message Message to show + */ + void raiseError(const std::string &message) { + return raiseError(std::runtime_error(message)); + } + + /** + * @return Current scale factor for pixels + */ + float getPixelDensity() { return _pixelDensity; } + + /** + * Starts (if not started) a loop that will call back on display sync + * @param callback Callback to call on sync + * @returns Identifier of the draw loop entry + */ + size_t beginDrawLoop(size_t nativeId, std::function callback) { + if (!_isValid) { + return 0; + } + auto shouldStart = false; + { + std::lock_guard lock(_drawCallbacksLock); + _drawCallbacks.emplace(nativeId, std::move(callback)); + shouldStart = _drawCallbacks.size() == 1; + } + if (shouldStart) { + // Start + startDrawLoop(); + } + return nativeId; + } + + /** + * Ends (if running) the drawing loop that was started with beginDrawLoop. + * This method must be called symmetrically with the beginDrawLoop method. + * @param nativeId Identifier of view to end + */ + void endDrawLoop(size_t nativeId) { + if (!_isValid) { + return; + } + auto shouldStop = false; + { + std::lock_guard lock(_drawCallbacksLock); + if (_drawCallbacks.count(nativeId) > 0) { + _drawCallbacks.erase(nativeId); + } + shouldStop = _drawCallbacks.size() == 0; + } + if (shouldStop) { + stopDrawLoop(); + } + } + + /** + * Notifies all drawing callbacks + * @param invalidated True if the context was invalidated, otherwise false. + * This can be used to receive a notification that we have stopped the main + * drawloop + */ + void notifyDrawLoop(bool invalidated) { + if (!_isValid) { + return; + } + std::lock_guard lock(_drawCallbacksLock); + for (auto it = _drawCallbacks.begin(); it != _drawCallbacks.end(); it++) { + it->second(invalidated); + } + } + + // default implementation does nothing, so it can be called from virtual + // destructor. + virtual void startDrawLoop() {} + virtual void stopDrawLoop() {} + +private: + float _pixelDensity; + + std::thread::id _jsThreadId; + + jsi::Runtime *_jsRuntime; + std::shared_ptr _callInvoker; + std::unique_ptr _dispatchQueue; + + std::unordered_map> _drawCallbacks; + std::mutex _drawCallbacksLock; + std::atomic _isValid = {true}; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkValueApi.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkValueApi.h new file mode 100644 index 00000000000000..302f9755db2b99 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkValueApi.h @@ -0,0 +1,72 @@ +#pragma once + +#include + +#include "JsiHostObject.h" +#include "RNSkAnimation.h" +#include "RNSkComputedValue.h" +#include "RNSkPlatformContext.h" +#include "RNSkValue.h" +#include + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class RNSkValueApi : public RNJsi::JsiHostObject { +public: + /** + * Constructor + * @param platformContext Platform context + */ + explicit RNSkValueApi(std::shared_ptr platformContext) + : JsiHostObject(), _platformContext(platformContext) { + _valueIdentifier = 50000; + } + + /** + * Destructor + */ + ~RNSkValueApi() {} + + JSI_HOST_FUNCTION(createValue) { + return jsi::Object::createFromHostObject( + runtime, std::make_shared(_platformContext, runtime, + arguments, count)); + } + + JSI_HOST_FUNCTION(createComputedValue) { + // Creation and initialization is done in two steps to be able to use weak + // references when setting up dependencies - since weak_from_this needs our + // instance to be a shared_ptr before calling weak_from_this(). + auto computedValue = std::make_shared( + _platformContext, runtime, arguments, count); + computedValue->initializeDependencies(runtime, arguments, count); + return jsi::Object::createFromHostObject(runtime, computedValue); + } + + JSI_HOST_FUNCTION(createAnimation) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(_platformContext, ++_valueIdentifier, + runtime, arguments, count)); + } + + JSI_HOST_FUNCTION(createClockValue) { + return jsi::Object::createFromHostObject( + runtime, + std::make_shared(_platformContext, ++_valueIdentifier, + runtime, arguments, count)); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkValueApi, createValue), + JSI_EXPORT_FUNC(RNSkValueApi, createComputedValue), + JSI_EXPORT_FUNC(RNSkValueApi, createClockValue), + JSI_EXPORT_FUNC(RNSkValueApi, createAnimation)) + +private: + // Platform context + std::shared_ptr _platformContext; + std::atomic _valueIdentifier; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkView.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkView.h new file mode 100644 index 00000000000000..2cfda8aad8f15b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/RNSkView.h @@ -0,0 +1,425 @@ + +#pragma once + +#include +#include +#include +#include + +#include "JsiValueWrapper.h" +#include "RNSkPlatformContext.h" +#include "RNSkValue.h" + +#include "JsiSkImage.h" +#include "JsiSkPoint.h" +#include "JsiSkRect.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCanvas.h" +#include "SkSurface.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class RNSkCanvasProvider { +public: + explicit RNSkCanvasProvider(std::function requestRedraw) + : _requestRedraw(requestRedraw) {} + + /** + Returns the scaled width of the view + */ + virtual float getScaledWidth() = 0; + + /** + Returns the scaled height of the view + */ + virtual float getScaledHeight() = 0; + + /** + Render to a canvas + */ + virtual bool renderToCanvas(const std::function &) = 0; + +protected: + std::function _requestRedraw; +}; + +class RNSkRenderer { +public: + explicit RNSkRenderer(std::function requestRedraw) + : _requestRedraw(requestRedraw) {} + + /** + Tries to render the current set of drawing operations. If we're busy we'll + return false so that the calling RNSkBaseDrawView can request a new render + next frame. The tryRender method is typically called on each frame if there + are any redraw requests. The method will be called from the main thread, so + the implementor must make sure any thread requirements are met before + rendering. This method will also allow the rendering to be dispatched to + another thread. + */ + virtual bool + tryRender(std::shared_ptr canvasProvider) = 0; + + /** + Renders directly to the canvas in the canvas provider. This method is called + from a Javascript call to render a snapshot of the SkiaView to an image, and + can therefore run outside the tryRender loop and directly in the javascript + thread. + */ + virtual void + renderImmediate(std::shared_ptr canvasProvider) = 0; + + void setShowDebugOverlays(bool showDebugOverlays) { + _showDebugOverlays = showDebugOverlays; + } + bool getShowDebugOverlays() { return _showDebugOverlays; } + +protected: + std::function _requestRedraw; + bool _showDebugOverlays; +}; + +class RNSkImageCanvasProvider : public RNSkCanvasProvider { +public: + RNSkImageCanvasProvider(std::shared_ptr context, + std::function requestRedraw, float width, + float height) + : RNSkCanvasProvider(requestRedraw), _width(width), _height(height) { + _surface = context->makeOffscreenSurface(_width, _height); + } + + /** + Returns a snapshot of the current surface/canvas + */ + sk_sp makeSnapshot(std::shared_ptr bounds) { + sk_sp image; + if (bounds != nullptr) { + SkIRect b = SkIRect::MakeXYWH(bounds->x(), bounds->y(), bounds->width(), + bounds->height()); + image = _surface->makeImageSnapshot(b); + } else { + image = _surface->makeImageSnapshot(); + } + return image->makeNonTextureImage(); + } + + /** + Returns the scaled width of the view + */ + float getScaledWidth() override { return _width; }; + + /** + Returns the scaled height of the view + */ + float getScaledHeight() override { return _height; }; + + /** + Render to a canvas + */ + bool renderToCanvas(const std::function &cb) override { + cb(_surface->getCanvas()); + return true; + }; + +private: + float _width; + float _height; + sk_sp _surface; +}; + +enum RNSkDrawingMode { Default, Continuous }; + +using RNSkTouchInfo = struct { + enum TouchType { Start, Active, End, Cancelled }; + double x; + double y; + double force; + TouchType type; + size_t id; + long timestamp; +}; + +class RNSkView : public std::enable_shared_from_this { +public: + /** + * Constructor + */ + RNSkView(std::shared_ptr context, + std::shared_ptr canvasProvider, + std::shared_ptr renderer) + : _platformContext(context), _canvasProvider(canvasProvider), + _renderer(renderer) {} + + /** + Destructor + */ + virtual ~RNSkView() { + endDrawingLoop(); + if (_onSizeUnsubscribe != nullptr) { + _onSizeUnsubscribe(); + _onSizeUnsubscribe = nullptr; + } + } + + /** + Sets custom properties. Custom properties are properties that are set + directly from Javascript without having to go through the async bridge. + */ + virtual void setJsiProperties( + std::unordered_map &props) { + + for (auto &prop : props) { + if (prop.first == "onSize") { + // Start by removing any subscribers to the current onSize + if (_onSizeUnsubscribe != nullptr) { + _onSizeUnsubscribe(); + _onSizeUnsubscribe = nullptr; + } + if (prop.second.isUndefinedOrNull()) { + // Clear touchCallback + _onSize = nullptr; + } else if (prop.second.getType() != + RNJsi::JsiWrapperValueType::HostObject) { + // We expect a function for the draw callback custom property + throw std::runtime_error( + "Expected a Skia mutable value for the onSize property."); + } + // Save onSize + _onSize = + std::dynamic_pointer_cast(prop.second.getAsHostObject()); + + // Add listener + _onSizeUnsubscribe = + _onSize->addListener([weakSelf = weak_from_this()](jsi::Runtime &) { + auto self = weakSelf.lock(); + if (self) { + self->requestRedraw(); + } + }); + } + } + } + + /** + Calls a custom action. + */ + virtual jsi::Value callJsiMethod(jsi::Runtime &runtime, + const std::string &name, + const jsi::Value *arguments, size_t count) { + throw std::runtime_error( + "The base Skia View does not support any commands. Command " + name + + " not found."); + } + + /** + * Repaints the Skia view using the underlying context and the drawcallback. + * This method schedules a draw request that will be run on the correct + * thread and js runtime. + */ + void requestRedraw() { _redrawRequestCounter++; } + + /** + Renders immediate. Be carefull to not call this method from another thread + than the UI thread + */ + void renderImmediate() { + _renderer->renderImmediate(_canvasProvider); + _redrawRequestCounter = 0; + } + + /** + Sets the native id of the view + */ + virtual void setNativeId(size_t nativeId) { + _nativeId = nativeId; + beginDrawingLoop(); + } + + /** + Returns the native id + */ + size_t getNativeId() { return _nativeId; } + + /** + Sets the drawing mode for the view + */ + void setDrawingMode(RNSkDrawingMode mode) { + _drawingMode = mode; + requestRedraw(); + } + + /** + * Set to true to show the debug overlays on render + */ + void setShowDebugOverlays(bool show) { + _renderer->setShowDebugOverlays(show); + requestRedraw(); + } + + /** + Update touch state with new touch points + */ + virtual void updateTouchState(std::vector &) { + requestRedraw(); + } + + /** + Renders the view into an SkImage instead of the screen. + */ + sk_sp makeImageSnapshot(std::shared_ptr bounds) { + + auto provider = std::make_shared( + getPlatformContext(), std::bind(&RNSkView::requestRedraw, this), + _canvasProvider->getScaledWidth(), _canvasProvider->getScaledHeight()); + + _renderer->renderImmediate(provider); + return provider->makeSnapshot(bounds); + } + +protected: + std::shared_ptr getPlatformContext() { + return _platformContext; + } + std::shared_ptr getCanvasProvider() { + return _canvasProvider; + } + std::shared_ptr getRenderer() { return _renderer; } + + /** + Ends an ongoing beginDrawCallback loop for this view. This method is made + protected if the drawing loop should be stopped before reaching the + destructor (like we do for Android views) + */ + void endDrawingLoop() { + if (_drawingLoopId != 0) { + _drawingLoopId = 0; + _platformContext->endDrawLoop(_nativeId); + } + } + +private: + /** + Starts beginDrawCallback loop if the drawing mode is continuous + */ + void beginDrawingLoop() { + if (_drawingLoopId != 0 || _nativeId == 0) { + return; + } + // Set to zero to avoid calling beginDrawLoop before we return + _drawingLoopId = _platformContext->beginDrawLoop( + _nativeId, [weakSelf = weak_from_this()](bool invalidated) { + auto self = weakSelf.lock(); + if (self) { + self->drawLoopCallback(invalidated); + } + }); + } + + void updateOnSize() { + if (_onSize != nullptr) { + auto width = _canvasProvider->getScaledWidth() / + _platformContext->getPixelDensity(); + auto height = _canvasProvider->getScaledHeight() / + _platformContext->getPixelDensity(); + + _platformContext->runOnJavascriptThread( + [width, height, weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + auto runtime = self->_platformContext->getJsRuntime(); + auto onSize = self->_onSize->getCurrent(*runtime); + if (!onSize.isObject()) { + throw jsi::JSError( + *runtime, + "Expected onSize property to be a mutable Skia value."); + return; + } + auto onSizeObj = onSize.asObject(*runtime); + + // Is this a host SkSize object? + if (onSizeObj.isHostObject(*runtime)) { + auto point = std::dynamic_pointer_cast( + onSizeObj.asHostObject(*runtime)); + if (point == nullptr) { + throw jsi::JSError(*runtime, + "Expected onSize property to be a mutable " + "Skia value of type SkSize."); + return; + } + + auto w = point->getObject()->x(); + auto h = point->getObject()->y(); + if (w != width || h != height) { + auto nextSize = + std::make_shared(SkPoint::Make(width, height)); + point->setObject(nextSize); + self->_onSize->set_current(*runtime, onSize); + } + + } else { + auto wVal = onSizeObj.getProperty(*runtime, "width"); + auto hVal = onSizeObj.getProperty(*runtime, "height"); + + if (!wVal.isNumber() || !hVal.isNumber()) { + throw jsi::JSError(*runtime, + "Expected onSize property to be a mutable " + "Skia value of type SkSize."); + return; + } + + auto w = wVal.asNumber(); + auto h = hVal.asNumber(); + + if (w != width || h != height) { + // Update + onSizeObj.setProperty(*runtime, "width", width); + onSizeObj.setProperty(*runtime, "height", height); + self->_onSize->set_current(*runtime, onSize); + } + } + } + }); + } + } + + /** + Draw loop callback + */ + void drawLoopCallback(bool invalidated) { + if (_redrawRequestCounter > 0 || + _drawingMode == RNSkDrawingMode::Continuous) { + _redrawRequestCounter = 0; + + // Update size if needed + updateOnSize(); + + if (!_renderer->tryRender(_canvasProvider)) { + // The renderer could not render cause it was busy, just schedule + // redrawing on the next frame. + requestRedraw(); + } + } + } + + std::shared_ptr _platformContext; + std::shared_ptr _canvasProvider; + std::shared_ptr _renderer; + + std::shared_ptr _onSize; + std::function _onSizeUnsubscribe; + RNSkDrawingMode _drawingMode; + size_t _nativeId; + + size_t _drawingLoopId = 0; + std::atomic _redrawRequestCounter = {1}; + bool _initialDrawingDone = false; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/JsiDomApi.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/JsiDomApi.h new file mode 100644 index 00000000000000..8a84498b066081 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/JsiDomApi.h @@ -0,0 +1,168 @@ +#pragma once + +/* Enable output of dom trees and paint contexts */ +#define SKIA_DOM_DEBUG 0 +#define SKIA_DOM_DEBUG_VERBOSE 0 + +#include + +#include "JsiHostObject.h" + +#include "base/JsiDependencyManager.h" + +#include "nodes/JsiCircleNode.h" +#include "nodes/JsiDiffRectNode.h" +#include "nodes/JsiFillNode.h" +#include "nodes/JsiGroupNode.h" +#include "nodes/JsiImageNode.h" +#include "nodes/JsiLineNode.h" +#include "nodes/JsiOvalNode.h" +#include "nodes/JsiPatchNode.h" +#include "nodes/JsiPathNode.h" +#include "nodes/JsiPointsNode.h" +#include "nodes/JsiRRectNode.h" +#include "nodes/JsiRectNode.h" + +#include "nodes/JsiBlurMaskNode.h" +#include "nodes/JsiImageSvgNode.h" +#include "nodes/JsiPictureNode.h" +#include "nodes/JsiVerticesNode.h" + +#include "nodes/JsiColorFilterNodes.h" +#include "nodes/JsiImageFilterNodes.h" +#include "nodes/JsiPathEffectNodes.h" +#include "nodes/JsiShaderNodes.h" + +#include "nodes/JsiPaintNode.h" + +#include "nodes/JsiBackdropFilterNode.h" +#include "nodes/JsiBlendNode.h" +#include "nodes/JsiBoxNode.h" +#include "nodes/JsiBoxShadowNode.h" + +#include "nodes/JsiCustomDrawingNode.h" + +#include "nodes/JsiGlyphsNode.h" +#include "nodes/JsiTextBlobNode.h" +#include "nodes/JsiTextNode.h" +#include "nodes/JsiTextPathNode.h" + +#include "nodes/JsiLayerNode.h" + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class JsiDomApi : public JsiHostObject { +public: + explicit JsiDomApi(std::shared_ptr context) + : JsiHostObject() { + installFunction("DependencyManager", + JsiDependencyManager::createCtor(context)); + + // Shapes + installFunction("RectNode", JsiRectNode::createCtor(context)); + installFunction("RRectNode", JsiRRectNode::createCtor(context)); + installFunction("CircleNode", JsiCircleNode::createCtor(context)); + installFunction("PathNode", JsiPathNode::createCtor(context)); + installFunction("LineNode", JsiLineNode::createCtor(context)); + installFunction("ImageNode", JsiImageNode::createCtor(context)); + installFunction("OvalNode", JsiOvalNode::createCtor(context)); + installFunction("PatchNode", JsiPatchNode::createCtor(context)); + installFunction("PointsNode", JsiPointsNode::createCtor(context)); + installFunction("DiffRectNode", JsiDiffRectNode::createCtor(context)); + + installFunction("FillNode", JsiFillNode::createCtor(context)); + + installFunction("GroupNode", JsiGroupNode::createCtor(context)); + + installFunction("PaintNode", JsiPaintNode::createCtor(context)); + + installFunction("BlurMaskFilterNode", JsiBlurMaskNode::createCtor(context)); + + installFunction("PictureNode", JsiPictureNode::createCtor(context)); + installFunction("ImageSVGNode", JsiImageSvgNode::createCtor(context)); + + installFunction("VerticesNode", JsiVerticesNode::createCtor(context)); + + // Path effects + installFunction("DashPathEffectNode", + JsiDashPathEffectNode::createCtor(context)); + installFunction("DiscretePathEffectNode", + JsiDiscretePathEffectNode::createCtor(context)); + installFunction("CornerPathEffectNode", + JsiCornerPathEffectNode::createCtor(context)); + installFunction("Path1DPathEffectNode", + JsiPath1DPathEffectNode::createCtor(context)); + installFunction("Path2DPathEffectNode", + JsiPath2DPathEffectNode::createCtor(context)); + installFunction("Line2DPathEffectNode", + JsiLine2DPathEffectNode::createCtor(context)); + installFunction("SumPathEffectNode", + JsiSumPathEffectNode::createCtor(context)); + + // Image filters + installFunction("DashPathEffectNode", + JsiBlendImageFilterNode::createCtor(context)); + installFunction("DropShadowImageFilterNode", + JsiDropShadowImageFilterNode::createCtor(context)); + installFunction("DisplacementMapImageFilterNode", + JsiDisplacementMapImageFilterNode::createCtor(context)); + installFunction("BlurImageFilterNode", + JsiBlurImageFilterNode::createCtor(context)); + installFunction("OffsetImageFilterNode", + JsiOffsetImageFilterNode::createCtor(context)); + installFunction("MorphologyImageFilterNode", + JsiMorphologyImageFilterNode::createCtor(context)); + installFunction("RuntimeShaderImageFilterNode", + JsiRuntimeShaderImageFilterNode::createCtor(context)); + + // Color Filters + installFunction("MatrixColorFilterNode", + JsiMatrixColorFilterNode::createCtor(context)); + installFunction("BlendColorFilterNode", + JsiBlendColorFilterNode::createCtor(context)); + installFunction("LinearToSRGBGammaColorFilterNode", + JsiLinearToSRGBGammaColorFilterNode::createCtor(context)); + installFunction("SRGBToLinearGammaColorFilterNode", + JsiSRGBToLinearGammaColorFilterNode::createCtor(context)); + installFunction("LumaColorFilterNode", + JsiLumaColorFilterNode::createCtor(context)); + installFunction("LerpColorFilterNode", + JsiLerpColorFilterNode::createCtor(context)); + + // Shaders + installFunction("ShaderNode", JsiShaderNode::createCtor(context)); + installFunction("ImageShaderNode", JsiImageShaderNode::createCtor(context)); + installFunction("ColorShaderNode", JsiColorShaderNode::createCtor(context)); + installFunction("TurbulenceNode", JsiTurbulenceNode::createCtor(context)); + installFunction("FractalNoiseNode", + JsiFractalNoiseNode::createCtor(context)); + installFunction("LinearGradientNode", + JsiLinearGradientNode::createCtor(context)); + installFunction("RadialGradientNode", + JsiRadialGradientNode::createCtor(context)); + installFunction("SweepGradientNode", + JsiSweepGradientNode::createCtor(context)); + installFunction("TwoPointConicalGradientNode", + JsiTwoPointConicalGradientNode::createCtor(context)); + + installFunction("BackdropFilterNode", + JsiBackdropFilterNode::createCtor(context)); + installFunction("BlendNode", JsiBlendNode::createCtor(context)); + installFunction("BoxNode", JsiBoxNode::createCtor(context)); + installFunction("BoxShadowNode", JsiBoxShadowNode::createCtor(context)); + + installFunction("CustomDrawingNode", + JsiCustomDrawingNode::createCtor(context)); + + installFunction("GlyphsNode", JsiGlyphsNode::createCtor(context)); + installFunction("TextNode", JsiTextNode::createCtor(context)); + installFunction("TextPathNode", JsiTextPathNode::createCtor(context)); + installFunction("TextBlobNode", JsiTextBlobNode::createCtor(context)); + + installFunction("LayerNode", JsiLayerNode::createCtor(context)); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/BaseNodeProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/BaseNodeProp.h new file mode 100644 index 00000000000000..75826150a45574 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/BaseNodeProp.h @@ -0,0 +1,72 @@ +#pragma once + +#include "DrawingContext.h" +#include "JsiValue.h" + +#include + +namespace RNSkia { + +class NodeProp; + +using namespace RNJsi; // NOLINT + +using ReadPropFunc = + std::function; + +/** + Base class for Dom Node Properties + */ +class BaseNodeProp { +public: + virtual ~BaseNodeProp() {} + + /** + Use to check if the value represented by this property has a usable + (non-null/undefined) value or not. + */ + virtual bool isSet() = 0; + + /** + True if the property has changed since we last visited it + */ + virtual bool isChanged() = 0; + + /** + Updates any pending values that has happened from other threads, sets flags + for changed. + */ + virtual void updatePendingChanges() = 0; + + /* + Marks property flags for changed as resolved + */ + virtual void markAsResolved() = 0; + + /** + Override to read the value represented by this property from the Javascript + property object + */ + virtual void readValueFromJs(jsi::Runtime &runtime, + const ReadPropFunc &read) = 0; + + /** + Returns the name (or names) in a property + */ + virtual std::string getName() = 0; + + /** + Sets the property as required + */ + void require() { _isRequired = true; } + + /** + Returns true for required props + */ + bool isRequired() { return _isRequired; } + +private: + bool _isRequired = false; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/ConcatablePaint.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/ConcatablePaint.cpp new file mode 100644 index 00000000000000..1f56372a0dd47b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/ConcatablePaint.cpp @@ -0,0 +1,117 @@ +#include "ConcatablePaint.h" + +#include "DeclarationContext.h" +#include "JsiDomNode.h" +#include "PaintProps.h" + +namespace RNSkia { + +ConcatablePaint::ConcatablePaint( + DeclarationContext *declarationContext, PaintProps *paintProps, + const std::vector> &children) + : _declarationContext(declarationContext), _paintProps(paintProps), + _children(children) { + + auto hasPropertyValues = _paintProps->getColor()->isSet() || + _paintProps->getStrokeWidth()->isSet() || + _paintProps->getBlendMode()->isSet() || + _paintProps->getStyle()->isSet() || + _paintProps->getStrokeJoin()->isSet() || + _paintProps->getStrokeCap()->isSet() || + _paintProps->getStrokeMiter()->isSet() || + _paintProps->getOpacity()->isSet() || + _paintProps->getAntiAlias()->isSet(); + + _declarationContext->save(); + + for (auto &child : _children) { + child->decorateContext(_declarationContext); + } + + _imageFilter = declarationContext->getImageFilters()->popAsOne(); + _colorFilter = declarationContext->getColorFilters()->popAsOne(); + _shader = declarationContext->getShaders()->pop(); + _maskFilter = declarationContext->getMaskFilters()->pop(); + _pathEffect = declarationContext->getPathEffects()->popAsOne(); + + _declarationContext->restore(); + + _isEmpty = !hasPropertyValues && _imageFilter == nullptr && + _colorFilter == nullptr && _shader == nullptr && + _maskFilter == nullptr && _pathEffect == nullptr; +} + +bool ConcatablePaint::isEmpty() { return _isEmpty; } + +void ConcatablePaint::concatTo(std::shared_ptr paint) { + + if (_paintProps->getOpacity()->isSet()) { + paint->setAlphaf(paint->getAlphaf() * + _paintProps->getOpacity()->value().getAsNumber()); + } + + if (_paintProps->getColor()->isSet()) { + auto currentOpacity = paint->getAlphaf(); + paint->setShader(nullptr); + paint->setColor(*_paintProps->getColor()->getDerivedValue()); + paint->setAlphaf(paint->getAlphaf() * currentOpacity); + } + + if (_paintProps->getStrokeWidth()->isSet()) { + paint->setStrokeWidth(_paintProps->getStrokeWidth()->value().getAsNumber()); + } + + if (_paintProps->getBlendMode()->isSet()) { + paint->setBlendMode(*_paintProps->getBlendMode()->getDerivedValue()); + } + + if (_paintProps->getStyle()->isSet()) { + auto styleValue = _paintProps->getStyle()->value().getAsString(); + if (styleValue == "stroke") { + paint->setStyle(SkPaint::Style::kStroke_Style); + } else if (styleValue == "fill") { + paint->setStyle(SkPaint::Style::kFill_Style); + } else { + throw std::runtime_error(styleValue + + " is not a valud value for the style property."); + } + } + + if (_paintProps->getStrokeJoin()->isSet()) { + paint->setStrokeJoin(*_paintProps->getStrokeJoin()->getDerivedValue()); + } + + if (_paintProps->getStrokeCap()->isSet()) { + paint->setStrokeCap(*_paintProps->getStrokeCap()->getDerivedValue()); + } + + if (_paintProps->getStrokeMiter()->isSet()) { + paint->setStrokeMiter(_paintProps->getStrokeMiter()->value().getAsNumber()); + } + + if (_paintProps->getAntiAlias()->isSet()) { + paint->setAntiAlias(_paintProps->getAntiAlias()->value().getAsBool()); + } + + if (_imageFilter) { + paint->setImageFilter(_imageFilter); + } + + if (_colorFilter) { + paint->setColorFilter(_colorFilter); + } + + if (_shader) { + paint->setShader(_shader); + } + + if (_maskFilter) { + paint->setMaskFilter(_maskFilter); + } + + if (_pathEffect) { + paint->setPathEffect(_pathEffect); + } +} + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/ConcatablePaint.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/ConcatablePaint.h new file mode 100644 index 00000000000000..dd4c2f0b52bdbe --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/ConcatablePaint.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColorFilter.h" +#include "SkImageFilter.h" +#include "SkMaskFilter.h" +#include "SkPaint.h" +#include "SkPathEffect.h" +#include "SkShader.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class JsiDomNode; +class PaintProps; +class DeclarationContext; + +/** + Class for concatenating SkPaint objects. + */ +class ConcatablePaint { +public: + ConcatablePaint(DeclarationContext *context, PaintProps *paintProps, + const std::vector> &children); + + void concatTo(std::shared_ptr paint); + bool isEmpty(); + +private: + DeclarationContext *_declarationContext; + const std::vector> _children; + PaintProps *_paintProps; + + bool _isEmpty{true}; + + sk_sp _imageFilter; + sk_sp _colorFilter; + sk_sp _pathEffect; + sk_sp _maskFilter; + sk_sp _shader; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/Declaration.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/Declaration.h new file mode 100644 index 00000000000000..f95478c7b341d0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/Declaration.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRefCnt.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +/** + Small container for shaders, filters, masks and effects + */ +template class Declaration { +public: + // Pushes to the stack + void push(T el) { _elements.push(el); } + + // Clears and returns all elements + std::vector popAll() { + auto size = _elements.size(); + std::vector tmp; + tmp.reserve(size); + for (size_t i = 0; i < size; ++i) { + tmp.push_back(_elements.top()); + _elements.pop(); + } + std::reverse(std::begin(tmp), std::end(tmp)); + return tmp; + } + + T pop() { + if (_elements.size() == 0) { + return nullptr; + } + auto tmp = _elements.top(); + _elements.pop(); + return tmp; + } + + // Clears and returns through reducer function in reversed order + T popAsOne(std::function composer) { + auto tmp = popAll(); + std::reverse(std::begin(tmp), std::end(tmp)); + return std::accumulate(std::begin(tmp), std::end(tmp), + static_cast(nullptr), [=](T inner, T outer) { + if (inner == nullptr) { + return outer; + } + return composer(inner, outer); + }); + } + + // Returns the size of the elements + size_t size() { return _elements.size(); } + +private: + std::stack _elements; +}; + +/** + Small container for shaders, filters, masks and effects + */ +template class ComposableDeclaration : public Declaration { +public: + /** + Constructor + */ + explicit ComposableDeclaration(std::function composer) + : Declaration(), _composer(composer) {} + + // Clears and returns through reducer function in reversed order + T popAsOne() { return Declaration::popAsOne(_composer); } + +private: + std::function _composer; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DeclarationContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DeclarationContext.h new file mode 100644 index 00000000000000..dcb33f891b9bcc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DeclarationContext.h @@ -0,0 +1,79 @@ +#pragma once + +#include "Declaration.h" + +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColorFilter.h" +#include "SkImageFilter.h" +#include "SkImageFilters.h" +#include "SkMaskFilter.h" +#include "SkPaint.h" +#include "SkPathEffect.h" +#include "SkShader.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class DeclarationContext { +public: + DeclarationContext() { save(); } + + Declaration> *getShaders() { return &_shaders.top(); } + ComposableDeclaration> *getImageFilters() { + return &_imageFilters.top(); + } + ComposableDeclaration> *getColorFilters() { + return &_colorFilters.top(); + } + ComposableDeclaration> *getPathEffects() { + return &_pathEffects.top(); + } + Declaration> *getMaskFilters() { + return &_maskFilters.top(); + } + Declaration> *getPaints() { return &_paints.top(); } + + void save() { + _paints.emplace(); + _shaders.emplace(); + _imageFilters.emplace( + [](sk_sp inner, sk_sp outer) { + return SkImageFilters::Compose(outer, inner); + }); + _colorFilters.emplace( + [](sk_sp inner, sk_sp outer) { + return SkColorFilters::Compose(outer, inner); + }); + _pathEffects.emplace( + [](sk_sp inner, sk_sp outer) { + return SkPathEffect::MakeCompose(outer, inner); + }); + _maskFilters.emplace(); + } + + void restore() { + _shaders.pop(); + _imageFilters.pop(); + _colorFilters.pop(); + _pathEffects.pop(); + _maskFilters.pop(); + _paints.pop(); + } + +private: + std::stack>> _shaders; + std::stack>> _imageFilters; + std::stack>> _colorFilters; + std::stack>> _pathEffects; + std::stack>> _maskFilters; + std::stack>> _paints; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DerivedNodeProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DerivedNodeProp.h new file mode 100644 index 00000000000000..3a9ecb4476b1b5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DerivedNodeProp.h @@ -0,0 +1,203 @@ +#pragma once + +#include "BaseNodeProp.h" +#include "JsiValue.h" + +#include +#include +#include +#include + +namespace RNSkia { + +/** + Class for composing multiple properties into a derived property value + */ +class BaseDerivedProp : public BaseNodeProp { +public: + explicit BaseDerivedProp(const std::function &onChange) + : _onChange(onChange), BaseNodeProp() {} + + /** + Starts the process of updating and reading props + */ + void updatePendingChanges() override { + auto changed = false; + for (auto &prop : _properties) { + prop->updatePendingChanges(); + if (prop->isChanged()) { + changed = true; + } + } + + // We only need to update the derived value when any of the derived + // properties have changed. + if (changed) { + updateDerivedValue(); + } + } + + /* + Marks properties as no longer changed + */ + void markAsResolved() override { + for (auto &prop : _properties) { + prop->markAsResolved(); + } + + _isChanged = false; + } + + /** + Returns the changed state of the prop + */ + bool isChanged() override { return _isChanged; } + + /** + Delegate read value to child nodes + */ + void readValueFromJs(jsi::Runtime &runtime, + const ReadPropFunc &read) override { + for (auto &prop : _properties) { + prop->readValueFromJs(runtime, read); + } + } + + /** + Override to calculate the derived value from child properties + */ + virtual void updateDerivedValue() = 0; + + /** + Adds a property to the derived property child props. + */ + template ::value>> + _Tp *defineProperty(_Args &&...__args) { + auto prop = + std::make_shared<_Tp>(std::forward<_Args>(__args)..., _onChange); + _properties.push_back(prop); + return prop.get(); + } + + /* + Return name of properties in derived prop as a comma separated list + */ + std::string getName() override { + std::string v = ""; + for (size_t i = 0; i < _properties.size(); ++i) { + v += _properties[i]->getName() + (i < _properties.size() - 1 ? ", " : ""); + } + return v; + } + + /** + Returns true if one or more of the child props has values + */ + bool isSet() override { + for (auto &prop : _properties) { + if (prop->isSet()) { + return true; + } + } + return false; + } + +protected: + void setIsChanged(bool isChanged) { _isChanged = isChanged; } + +private: + std::vector> _properties; + std::atomic _isChanged = {false}; + std::function _onChange; +}; + +/** + Class for composing multiple properties into a derived property value + */ +template class DerivedProp : public BaseDerivedProp { +public: + explicit DerivedProp(const std::function &onChange) + : BaseDerivedProp(onChange) {} + + /** + Returns the derived value + */ + std::shared_ptr getDerivedValue() { + return std::const_pointer_cast(_derivedValue); + } + + /** + Returns a mutable version of the derived value. Used by the paint props to + keep a drawing context + */ + std::shared_ptr getUnsafeDerivedValue() { return _derivedValue; } + + /** + Returns true if is optional and one of the child props has a value, or all + props if optional is false. + */ + bool isSet() override { return _derivedValue != nullptr; }; + +protected: + /** + Set derived value from sub classes + */ + void setDerivedValue(std::shared_ptr value) { + setIsChanged(_derivedValue != value); + _derivedValue = value; + } + + /** + Set derived value from sub classes + */ + void setDerivedValue(T &&value) { + setIsChanged(true); + _derivedValue = std::make_shared(std::move(value)); + } + +private: + std::shared_ptr _derivedValue; +}; + +/** + Class for composing multiple properties into a derived property value + */ +template class DerivedSkProp : public BaseDerivedProp { +public: + explicit DerivedSkProp(const std::function &onChange) + : BaseDerivedProp(onChange) {} + + /** + Returns the derived value + */ + sk_sp getDerivedValue() { return _derivedValue; } + + /** + Returns true if is optional and one of the child props has a value, or all + props if optional is false. + */ + bool isSet() override { return _derivedValue != nullptr; }; + +protected: + /** + Set derived value from sub classes + */ + void setDerivedValue(sk_sp value) { + setIsChanged(_derivedValue != value); + _derivedValue = value; + } + + /** + Set derived value from sub classes + */ + void setDerivedValue(const T &&value) { + setIsChanged(true); + _derivedValue = sk_make_sp(std::move(value)); + } + +private: + sk_sp _derivedValue; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DrawingContext.cpp b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DrawingContext.cpp new file mode 100644 index 00000000000000..b8cd985a42aac6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DrawingContext.cpp @@ -0,0 +1,55 @@ +#include "DrawingContext.h" + +#include "ConcatablePaint.h" +#include "JsiDomNode.h" +#include "PaintProps.h" + +#include + +namespace RNSkia { + +DrawingContext::DrawingContext(std::shared_ptr paint) { + _declarationContext = std::make_unique(); + paint->setAntiAlias(true); + _paints.push_back(paint); +} + +DrawingContext::DrawingContext() + : DrawingContext(std::make_shared()) {} + +bool DrawingContext::saveAndConcat( + PaintProps *paintProps, + const std::vector> &children, + std::shared_ptr paintCache) { + + if (paintCache) { + _paints.push_back(paintCache); + return true; + } + + ConcatablePaint paint(_declarationContext.get(), paintProps, children); + if (!paint.isEmpty()) { + save(); + paint.concatTo(getPaint()); + return true; + } + + return false; +} + +void DrawingContext::save() { + // Copy paint and push + _paints.push_back(std::make_shared(*getPaint())); +} + +void DrawingContext::restore() { _paints.pop_back(); } + +SkCanvas *DrawingContext::getCanvas() { return _canvas; } + +void DrawingContext::setCanvas(SkCanvas *canvas) { _canvas = canvas; } + +std::shared_ptr DrawingContext::getPaint() { + return _paints[_paints.size() - 1]; +} + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DrawingContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DrawingContext.h new file mode 100644 index 00000000000000..b347acd5505059 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/DrawingContext.h @@ -0,0 +1,104 @@ +#pragma once + +#include "JsiHostObject.h" + +#include "Declaration.h" +#include "DeclarationContext.h" + +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRefCnt.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class PaintProps; +class JsiDomNode; + +class DomRenderContext { +public: + float getScaledWidth() { return _scaledWidth; } + float getScaledHeight() { return _scaledHeight; } + + void setScaledWidth(float v) { _scaledWidth = v; } + void setScaledHeight(float v) { _scaledHeight = v; } + + void setRequestRedraw(std::function &&requestRedraw) { + _requestRedraw = std::move(requestRedraw); + } + + const std::function &getRequestRedraw() { return _requestRedraw; } + +private: + float _scaledWidth = -1; + float _scaledHeight = -1; + std::function _requestRedraw; +}; + +class DrawingContext : public DomRenderContext, + public std::enable_shared_from_this { +public: + /** + Creates a root drawing context with paint and opacity + */ + DrawingContext(); + + /** + Creates a drawing context with the given paint as its starting paint object + */ + explicit DrawingContext(std::shared_ptr paint); + + /** + Factory for saving/restoring the context for a node + */ + bool saveAndConcat(PaintProps *paintProps, + const std::vector> &children, + std::shared_ptr paintCache); + void restore(); + + /** + Returns true if the current cache is changed + */ + bool isChanged(); + + /** + Get/Sets the canvas object + */ + SkCanvas *getCanvas(); + + /** + Sets the canvas + */ + void setCanvas(SkCanvas *canvas); + + /** + Gets the paint object + */ + std::shared_ptr getPaint(); + + /* + Returns the root declaratiins object + */ + DeclarationContext *getDeclarationContext() { + return _declarationContext.get(); + } + +private: + void save(); + + explicit DrawingContext(const char *source); + SkCanvas *_canvas = nullptr; + std::vector> _paints; + std::unique_ptr _declarationContext; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDependencyManager.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDependencyManager.h new file mode 100644 index 00000000000000..6fb59310f8fa14 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDependencyManager.h @@ -0,0 +1,297 @@ +#pragma once + +#include "JsiHostObject.h" + +#include "RNSkPlatformContext.h" + +#include "JsiDomNode.h" + +#include +#include +#include +#include +#include +#include + +namespace RNSkia { + +static PropId PropNameSelector = JsiPropId::get("selector"); +static PropId PropNameValue = JsiPropId::get("value"); + +class JsiDependencyManager + : public JsiHostObject, + public std::enable_shared_from_this { +public: + JsiDependencyManager(std::shared_ptr context, + jsi::Runtime &runtime, + const jsi::Value ®isterValuesCallback) + : _registerValuesCallback(std::make_shared( + registerValuesCallback.asObject(runtime))), + JsiHostObject() {} + + ~JsiDependencyManager() { unsubscribeAll(); } + + /** + Call to unsubscribe all value listeners from the given node based on the + current list of subscriptions for the node. This function is typically called + when the node is unmounted or when one or more properties have changed. NOTE: + In this implementation we call unsubscribe directly without going through the + JSI method - but the method is kept for compatibility with the JS + implementation + */ + JSI_HOST_FUNCTION(unsubscribeNode) { + // (node: Node) + auto node = + getArgumentAsHostObject(runtime, arguments, count, 0); + unsubscribeNode(node.get()); + return jsi::Value::undefined(); + } + + /** + Adds listeners to the provided values so that the node is notified when a + value changes. + */ + JSI_HOST_FUNCTION(subscribeNode) { + // subscribeNode

(node: Node, props: AnimatedProps

) + auto node = + getArgumentAsHostObject(runtime, arguments, count, 0); + auto nextProps = getArgumentAsObject(runtime, arguments, count, 1); + + // Save unsubscribe callbacks + std::vector< + std::pair, std::function>> + unsubscribers; + + // Enumerate registered keys for the given node to only handle known + // properties + node->getPropsContainer()->enumerateMappedProps( + [&](const PropId key, const std::vector &propMapping) { + auto jsValue = nextProps.getProperty(runtime, key); + JsiValue nativeValue(runtime, jsValue); + + if (isAnimatedValue(nativeValue)) { + // Handle Skia Animation Values + auto animatedValue = getAnimatedValue(nativeValue); + auto unsubscribe = animatedValue->addListener( + [animatedValue, propMapping](jsi::Runtime &runtime) { + // Get value from animation value + auto nextJsValue = animatedValue->getCurrent(runtime); + // Update all props that listens to this animation value + for (auto &prop : propMapping) { + prop->updateValue(runtime, nextJsValue); + } + }); + + // Save unsubscribe methods + unsubscribers.push_back(std::make_pair(animatedValue, unsubscribe)); + + } else if (isSelector(nativeValue)) { + // Handle Skia Animation Value Selectors + auto animatedValue = std::dynamic_pointer_cast( + nativeValue.getValue(PropNameValue).getAsHostObject()); + + auto selector = + nativeValue.getValue(PropNameSelector).getAsFunction(); + // Add subscription to animated value in selector + auto unsubscribe = animatedValue->addListener( + [nativeValue, propMapping, selector = std::move(selector), + animatedValue](jsi::Runtime &runtime) { + // Get value from animation value + jsi::Value jsValue = animatedValue->getCurrent(runtime); + // Call selector to transform new value + auto selectedJsValue = + selector(runtime, jsi::Value::null(), &jsValue, 1); + // Update all props that listens to this animation value + for (auto &prop : propMapping) { + prop->updateValue(runtime, selectedJsValue); + } + }); + + // Save unsubscribe methods + unsubscribers.push_back(std::make_pair(animatedValue, unsubscribe)); + } + }); + + // Now let's store the subscription info + _subscriptions.emplace(node.get(), unsubscribers); + + // Set callback for unsubscribing + node->setDisposeCallback([node, weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + self->unsubscribeNode(node.get()); + } + }); + + return jsi::Value::undefined(); + } + + /** + Called when the hosting container is mounted or updated. This ensures that we + have a ref to the underlying SkiaView so that we can registers redraw + listeners on values used in the current View automatically. + */ + JSI_HOST_FUNCTION(update) { + if (_unregisterValues != nullptr) { + // unregisterValues is a pointer to unsubscribing to the automatic + // re-render when a value change + _unregisterValues->asFunction(runtime).call(runtime, + jsi::Value::undefined(), 0); + _unregisterValues = nullptr; + } + + // Now let's create connection between view and unique values + std::set> uniqueValues; + + for (auto &nodeSub : _subscriptions) { + for (auto &sub : nodeSub.second) { + if (uniqueValues.count(sub.first) == 0) { + uniqueValues.emplace(sub.first); + } + } + } + + // Copy to args + auto array = jsi::Array(runtime, uniqueValues.size()); + size_t i = 0; + for (auto &el : uniqueValues) { + array.setValueAtIndex(runtime, i++, + jsi::Object::createFromHostObject(runtime, el)); + } + + // Call JS registerValues callback + auto func = _registerValuesCallback->asFunction(runtime); + _unregisterValues = std::make_shared( + func.call(runtime, array, 1).asObject(runtime)); + + return jsi::Value::undefined(); + } + + /** + Called when the hosting container is unmounted or recreated. This ensures + that we remove all subscriptions to Skia values so that we don't have any + listeners left after the component is removed. + + * Called when the hosting container is unmounted or recreated. This ensures + that we remove + * all subscriptions to Skia values so that we don't have any listeners left + after + * the component is removed. + */ + JSI_HOST_FUNCTION(remove) { + if (_unregisterValues != nullptr) { + // unregisterValues is a pointer to unsubscribing to the automatic + // re-render when a value change + _unregisterValues->asFunction(runtime).call(runtime, + jsi::Value::undefined(), 0); + _unregisterValues = nullptr; + } + + unsubscribeAll(); + + _registerValuesCallback = nullptr; + + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiDependencyManager, unsubscribeNode), + JSI_EXPORT_FUNC(JsiDependencyManager, subscribeNode), + JSI_EXPORT_FUNC(JsiDependencyManager, update), + JSI_EXPORT_FUNC(JsiDependencyManager, remove)) + + /** + Constructor to add to the Api object + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + // Params: registerValues: (values: Array>) => () => + // void + auto obj = std::make_shared(context, runtime, + arguments[0]); + + return jsi::Object::createFromHostObject(runtime, std::move(obj)); + }; + } + +private: + /** + Removes all subscriptions + */ + void unsubscribeAll() { + // Unregister all nodes + std::vector tmp; + tmp.reserve(_subscriptions.size()); + for (auto &subInfo : _subscriptions) { + tmp.push_back(subInfo.first); + } + for (auto &node : tmp) { + unsubscribeNode(node); + } + + // Clear all subscriptions + _subscriptions.clear(); + } + + /** + Unsubscribes from a given node + */ + void unsubscribeNode(JsiDomNode *node) { + if (_subscriptions.count(node) > 0) { + auto subscriptions = _subscriptions.at(node); + for (auto &p : subscriptions) { + p.second(); + } + + // Remove node's subscriptions + _subscriptions.erase(node); + + // Remove node's callback to avoid keeping + // cyclic dependencies between dep manager and the node + node->setDisposeCallback(nullptr); + } + } + /** + Returns true if the given value is a HostObject and it inherits from + RNSkReadonlyValue. + */ + bool isAnimatedValue(JsiValue &value) { + return value.getType() == PropType::HostObject && + std::dynamic_pointer_cast( + value.getAsHostObject()) != nullptr; + } + + /** + Returns the RNSkReadonlyValue pointer for a value that is an Animated value + */ + std::shared_ptr getAnimatedValue(JsiValue &value) { + return std::dynamic_pointer_cast( + value.getAsHostObject()); + } + + /** + Returns true if the value is a selector. A Selector is a JS object that has + two properties, the selector and the the value. The selector is a function + that is used to transform the value - which is an animated skia value. + */ + bool isSelector(JsiValue &value) { + // Handling selectors is rather easy, we just add + // a listener on the selector's callback and then we'll do the javascript + // resolving in the callback (which will always be on the Javascript + // thread)! + if (value.getType() == PropType::Object) { + if (value.hasValue(PropNameSelector) && value.hasValue(PropNameValue)) { + return true; + } + } + return false; + } + + std::shared_ptr _registerValuesCallback; + std::shared_ptr _unregisterValues; + std::map, + std::function>>> + _subscriptions; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomDeclarationNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomDeclarationNode.h new file mode 100644 index 00000000000000..d9ec57debedfbf --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomDeclarationNode.h @@ -0,0 +1,119 @@ + +#pragma once + +#include "DrawingContext.h" +#include "JsiDomNode.h" + +#include +#include + +namespace RNSkia { + +enum DeclarationType { + Unknown = 0, + Paint = 1, + Shader = 2, + ImageFilter = 3, + ColorFilter = 4, + PathEffect = 5, + MaskFilter = 6, +}; + +class JsiDomDeclarationNode : public JsiDomNode { +public: + JsiDomDeclarationNode(std::shared_ptr context, + const char *type, DeclarationType declarationType) + : JsiDomNode(context, type, NodeClass::DeclarationNode), + _declarationType(declarationType) {} + + JSI_PROPERTY_GET(declarationType) { + // FIXME: Shouldn't this be the declaration type instead? It has been + return jsi::String::createFromUtf8(runtime, std::string(getType())); + } + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiDomDeclarationNode, + declarationType), + JSI_EXPORT_PROP_GET(JsiDomNode, type)) + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiDomNode, addChild), + JSI_EXPORT_FUNC(JsiDomNode, removeChild), + JSI_EXPORT_FUNC(JsiDomNode, insertChildBefore), + JSI_EXPORT_FUNC(JsiDomNode, setProps), + JSI_EXPORT_FUNC(JsiDomNode, setProp), + JSI_EXPORT_FUNC(JsiDomNode, dispose), + JSI_EXPORT_FUNC(JsiDomNode, children)) + + /** + Called when rendering the tree to create all derived values from all nodes. + */ + void decorateContext(DeclarationContext *context) override { + JsiDomNode::decorateContext(context); + +#if SKIA_DOM_DEBUG + printDebugInfo("Begin decorate " + std::string(getType())); +#endif + + // decorate drawing context + decorate(context); + +#if SKIA_DOM_DEBUG + printDebugInfo("End / Commit decorate " + std::string(getType())); +#endif + } + + DeclarationType getDeclarationType() { return _declarationType; } + + /** + Override to implement materialization + */ + virtual void decorate(DeclarationContext *context) = 0; + +protected: + /** + Invalidates and marks then context as changed. The implementation in the + declaration node is to pass the call upwards to the parent node + */ + void invalidateContext() override { + if (getParent() != nullptr) { + getParent()->invalidateContext(); + } + } + + /** + A property changed + */ + void onPropertyChanged(BaseNodeProp *prop) override { invalidateContext(); } + + /** + Validates that only declaration nodes can be children + */ + void addChild(std::shared_ptr child) override { + if (child->getNodeClass() != NodeClass::DeclarationNode) { + getContext()->raiseError(std::runtime_error( + "Cannot add a child of type \"" + std::string(child->getType()) + + "\" to a \"" + std::string(getType()) + "\".")); + } + JsiDomNode::addChild(child); + } + + /** + Validates that only declaration nodes can be children + */ + void insertChildBefore(std::shared_ptr child, + std::shared_ptr before) override { + if (child->getNodeClass() != NodeClass::DeclarationNode) { + getContext()->raiseError(std::runtime_error( + "Cannot add a child of type \"" + std::string(child->getType()) + + "\" to a \"" + std::string(getType()) + "\".")); + } + JsiDomNode::insertChildBefore(child, before); + } + +private: + /** + Type of declaration + */ + DeclarationType _declarationType; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomDrawingNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomDrawingNode.h new file mode 100644 index 00000000000000..d0514e62b863b0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomDrawingNode.h @@ -0,0 +1,71 @@ +#pragma once + +#include "JsiDomRenderNode.h" +#include "JsiPaintNode.h" + +#include + +namespace RNSkia { + +class JsiDomDrawingNode : public JsiDomRenderNode { +public: + JsiDomDrawingNode(std::shared_ptr context, + const char *type) + : JsiDomRenderNode(context, type) {} + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomRenderNode::defineProperties(container); + _paintProp = container->defineProperty(); + } + + /** + Override to implement drawing. + */ + virtual void draw(DrawingContext *context) = 0; + + void renderNode(DrawingContext *context) override { +#if SKIA_DOM_DEBUG + printDebugInfo("Begin Draw", 1); +#endif + // Save paint if the paint property is set + if (_paintProp->isSet()) { + auto localCtx = _paintProp->getUnsafeDerivedValue().get(); + localCtx->setCanvas(context->getCanvas()); + draw(localCtx); + } else { + // Call abstract draw method + draw(context); + } + + // Draw once more for each child paint node + auto declarationCtx = context->getDeclarationContext(); + for (auto &child : getChildren()) { + if (child->getNodeClass() == NodeClass::DeclarationNode && + std::static_pointer_cast(child) + ->getDeclarationType() == DeclarationType::Paint) { + auto paintNode = std::static_pointer_cast(child); + // Draw once again with the paint + declarationCtx->save(); + paintNode->decorate(declarationCtx); + auto paint = declarationCtx->getPaints()->pop(); + declarationCtx->restore(); + + // FIXME: Can we avoid creating a new drawing context here each time? + auto localContext = + std::make_shared(std::shared_ptr(paint)); + localContext->setCanvas(context->getCanvas()); + draw(localContext.get()); + } + } + +#if SKIA_DOM_DEBUG + printDebugInfo("End Draw", 1); +#endif + } + +private: + PaintDrawingContextProp *_paintProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomNode.h new file mode 100644 index 00000000000000..3d47ec57cf85cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomNode.h @@ -0,0 +1,556 @@ +#pragma once + +#include "JsiHostObject.h" +#include "NodeProp.h" +#include "NodePropsContainer.h" + +#include +#include +#include +#include + +#include "RNSkPlatformContext.h" + +namespace RNSkia { + +template class JsiDomNodeCtor { +public: + /** + Constructor to add to the Api object + */ + static const jsi::HostFunctionType + createCtor(std::shared_ptr context) { + return JSI_HOST_FUNCTION_LAMBDA { + auto node = std::make_shared(context); + node->initializeNode(runtime, thisValue, arguments, count); + return jsi::Object::createFromHostObject(runtime, std::move(node)); + }; + } +}; + +static std::atomic NodeIdent = 1000; + +typedef enum { + RenderNode = 1, + DeclarationNode = 2, +} NodeClass; + +/** + Implements an abstract base class for nodes in the Skia Reconciler. This node + coresponds to the native implementation of the Node.ts class in Javascript. + */ +class JsiDomNode : public JsiHostObject, + public std::enable_shared_from_this { +public: + /** + Contructor. Takes as parameters the values comming from the JS world that + initialized the class. + */ + JsiDomNode(std::shared_ptr context, const char *type, + NodeClass nodeClass) + : _type(type), _context(context), _nodeClass(nodeClass), + _nodeId(NodeIdent++), JsiHostObject() { +#if SKIA_DOM_DEBUG + printDebugInfo("JsiDomNode." + std::string(_type) + + " CTOR - nodeId: " + std::to_string(_nodeId)); +#endif + } + + virtual ~JsiDomNode() { +#if SKIA_DOM_DEBUG + printDebugInfo("JsiDomNode." + std::string(_type) + + " DTOR - nodeId: " + std::to_string(_nodeId)); +#endif + } + + /** + Called when creating the node, resolves properties from the node constructor. + These properties are materialized, ie. no animated values or anything. + */ + JSI_HOST_FUNCTION(initializeNode) { + return setProps(runtime, thisValue, arguments, count); + } + + /** + JS-function for setting the properties from the JS reconciler on the node. + */ + JSI_HOST_FUNCTION(setProps) { + if (count == 1) { + // Initialize properties container + setProps(runtime, arguments[0]); + } else { + setEmptyProps(); + } + return jsi::Value::undefined(); + } + + /** + Updates the selected property value + */ + JSI_HOST_FUNCTION(setProp) { + if (_propsContainer == nullptr) { + // TODO: we ignore individual properties updates if the initial properties + // hasn't been defined. It is likely an error if we reach this branch and + // perhaps should throw an exception but platformContext isn't available + // here. + return jsi::Value::undefined(); + } + auto propName = arguments[0].asString(runtime).utf8(runtime); + const jsi::Value &propValue = arguments[1]; + + // Enumerate all props with this name and update. The + // enumerateMappedPropsByName function is thread safe and locks props so it + // can be called from all threads. + _propsContainer->enumerateMappedPropsByName(propName, [&](NodeProp *prop) { + prop->updateValue(runtime, propValue); + }); + + return jsi::Value::undefined(); + } + + /** + JS Function to be called when the node is no longer part of the reconciler + tree. Use for cleaning up. + */ + JSI_HOST_FUNCTION(dispose) { + dispose(false); + return jsi::Value::undefined(); + } + + /** + JS Function for adding a child node to this node. + */ + JSI_HOST_FUNCTION(addChild) { + // child: Node + auto newChild = + getArgumentAsHostObject(runtime, arguments, count, 0); + addChild(newChild); + return jsi::Value::undefined(); + } + + /* + JS Function for removing a child node from this node + */ + JSI_HOST_FUNCTION(removeChild) { + auto child = + getArgumentAsHostObject(runtime, arguments, count, 0); + removeChild(child); + return jsi::Value::undefined(); + } + + /** + JS Function for insering a child node to a specific location in the children + array on this node + */ + JSI_HOST_FUNCTION(insertChildBefore) { + // child: Node, before: Node + auto child = + getArgumentAsHostObject(runtime, arguments, count, 0); + auto before = + getArgumentAsHostObject(runtime, arguments, count, 1); + insertChildBefore(child, before); + return jsi::Value::undefined(); + } + + /** + JS Function for getting child nodes for this node + */ + JSI_HOST_FUNCTION(children) { + auto array = jsi::Array(runtime, _children.size()); + + size_t index = 0; + for (auto child : _children) { + array.setValueAtIndex(runtime, index++, child->asHostObject(runtime)); + } + return array; + } + + /** + JS Property for getting the type of node + */ + JSI_PROPERTY_GET(type) { + return jsi::String::createFromUtf8(runtime, getType()); + } + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiDomNode, type)) + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiDomNode, setProps), + JSI_EXPORT_FUNC(JsiDomNode, setProp), + JSI_EXPORT_FUNC(JsiDomNode, addChild), + JSI_EXPORT_FUNC(JsiDomNode, removeChild), + JSI_EXPORT_FUNC(JsiDomNode, insertChildBefore), + JSI_EXPORT_FUNC(JsiDomNode, children), + JSI_EXPORT_FUNC(JsiDomNode, dispose)) + + /** + Returns the node type. + */ + const char *getType() { return _type; } + + /** + Returns the identifier for the node + */ + size_t getNodeId() { return _nodeId; } + + /** + Returns the container for node properties + */ + NodePropsContainer *getPropsContainer() { return _propsContainer.get(); } + + /** + Callback that will be called when the node is disposed - typically registered + from the dependency manager so that nodes can be removed and unsubscribed + from when removed from the reconciler tree. + */ + void setDisposeCallback(std::function disposeCallback) { + _disposeCallback = disposeCallback; + } + + /** + Invalidates and marks then context as changed. The default behaviour is an + empty implementation + */ + virtual void invalidateContext() = 0; + + /* + Returns the class of node so that we can do loops faster without + having to check using runtime type information + */ + NodeClass getNodeClass() { return _nodeClass; } + + /** + Updates any pending property changes in all nodes and child nodes. This + function will swap any pending property changes in this and children with any + waiting values that has been set by the javascript thread. Props will also be + marked as changed so that we can calculate wether updates are required or + not. + */ + void commitPendingChanges() { + // Update properties container + if (_propsContainer != nullptr) { + _propsContainer->updatePendingValues(); + } + + // Run all pending node operations + { + std::lock_guard lock(_childrenLock); + for (auto &op : _queuedNodeOps) { + op(); + } + + _queuedNodeOps.clear(); + } + + // Update children + for (auto &child : _children) { + child->commitPendingChanges(); + } + } + + /** + When pending properties has been updated and all rendering is done, we call + this function to mark any changes as processed. This call also resolves all + child nodes + */ + virtual void resetPendingChanges() { + // Mark self as resolved + if (_propsContainer != nullptr) { + _propsContainer->markAsResolved(); + } + + // Now let's invalidate if needed + if (_isDisposing && !_isDisposed) { + invalidate(); + } + + // Resolve children + for (auto &child : _children) { + child->resetPendingChanges(); + } + } + + /** + Empty implementation of the decorate context method + */ + virtual void decorateContext(DeclarationContext *context) { + // Empty implementation + } + + /** + Called when a node has been removed from the dom tree and needs to be cleaned + up. If the invalidate parameter is set, we will invalidate the node directly. + Calling dispose from the JS dispose function calls this with invalidate set + to false, while the dom render view calls this with true. + */ + virtual void dispose(bool immediate) { + if (_isDisposing) { + return; + } + _isDisposing = true; + if (immediate) { + invalidate(); + } + } + +protected: + /** + Adds an operation that will be executed when the render cycle is finished. + */ + void enqueAsynOperation(std::function &&fp) { + std::lock_guard lock(_childrenLock); + _queuedNodeOps.push_back(std::move(fp)); + } + /** + Override to define properties in node implementations + */ + virtual void defineProperties(NodePropsContainer *container) {} + + /** + Returns the platform context + */ + std::shared_ptr getContext() { return _context; } + + /** + Returns this node as a host object that can be returned to the JS side. + */ + jsi::Object asHostObject(jsi::Runtime &runtime) { + return jsi::Object::createFromHostObject(runtime, shared_from_this()); + } + + /** + Native implementation of the set properties method. This is called from the + reconciler when properties are set due to changes in React. + */ + void setProps(jsi::Runtime &runtime, const jsi::Value &maybeProps) { +#if SKIA_DOM_DEBUG + printDebugInfo("JS:setProps(nodeId: " + std::to_string(_nodeId) + ")"); +#endif + // Initialize properties container + ensurePropertyContainer(); + + // Update properties container + _propsContainer->setProps(runtime, maybeProps); + + // Invalidate context + invalidateContext(); + } + + /** + Called for components that has no properties + */ + void setEmptyProps() { +#if SKIA_DOM_DEBUG + printDebugInfo("JS:setEmptyProps(nodeId: " + std::to_string(_nodeId) + ")"); +#endif + // Initialize properties container + ensurePropertyContainer(); + } + + /** + Returns all child JsiDomNodes for this node. + */ + const std::vector> &getChildren() { + std::lock_guard lock(_childrenLock); + return _children; + } + + /** + Override to be notified when a node property has changed + */ + virtual void onPropertyChanged(BaseNodeProp *prop) {} + + /** + Adds a child node to the array of children for this node + */ + virtual void addChild(std::shared_ptr child) { +#if SKIA_DOM_DEBUG + printDebugInfo("JS:addChild(childId: " + std::to_string(child->_nodeId) + + ")"); +#endif + enqueAsynOperation([child, weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + self->_children.push_back(child); + child->setParent(self.get()); + } + }); + } + + /** + Inserts a child node before a given child node in the children array for this + node + */ + virtual void insertChildBefore(std::shared_ptr child, + std::shared_ptr before) { +#if SKIA_DOM_DEBUG + printDebugInfo( + "JS:insertChildBefore(childId: " + std::to_string(child->_nodeId) + + ", beforeId: " + std::to_string(before->_nodeId) + ")"); +#endif + enqueAsynOperation([child, before, weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + auto position = + std::find(self->_children.begin(), self->_children.end(), before); + self->_children.insert(position, child); + child->setParent(self.get()); + } + }); + } + + /** + Removes a child. Removing a child will remove the child from the array of + children and call dispose on the child node. + */ + virtual void removeChild(std::shared_ptr child) { +#if SKIA_DOM_DEBUG + printDebugInfo("JS:removeChild(childId: " + std::to_string(child->_nodeId) + + ")"); +#endif + auto removeChild = [child, + weakSelf = weak_from_this()](bool immediate = false) { + auto self = weakSelf.lock(); + if (self) { + // Delete child itself + self->_children.erase( + std::remove_if(self->_children.begin(), self->_children.end(), + [child](const auto &node) { return node == child; }), + self->_children.end()); + + child->dispose(immediate); + } + }; + + if (_isDisposing) { + removeChild(false); + } else { + enqueAsynOperation(removeChild); + } + } + +#if SKIA_DOM_DEBUG + std::string getLevelIndentation(size_t indentation = 0) { + JsiDomNode *curParent = _parent; + while (curParent != nullptr) { + indentation++; + curParent = curParent->getParent(); + } + return std::string(indentation * 2, ' '); + } + + void printDebugInfo(const std::string &message, size_t indentation = 0) { + RNSkLogger::logToConsole("%s%s %lu: %s", + getLevelIndentation(indentation).c_str(), + getType(), getNodeId(), message.c_str()); + } +#endif + + /** + Sets the parent node + */ + void setParent(JsiDomNode *parent) { _parent = parent; } + + /** + Returns the parent node if set. + */ + JsiDomNode *getParent() { return _parent; } + + /** + Loops through all declaration nodes and gives each one of them the + opportunity to decorate the context. + */ + void decorateChildren(DeclarationContext *context) { + for (auto &child : getChildren()) { + // All JsiDomNodes has the decorateContext method - but only the + // JsiDomDeclarationNode is actually doing stuff inside this method. + child->decorateContext(context); + } + } + +private: + /** + Invalidates the node - meaning removing and clearing children and properties + **/ + void invalidate() { + if (_isDisposing && !_isDisposed) { +#if SKIA_DOM_DEBUG + printDebugInfo("JsiDomNode::invalidate: nodeid: " + + std::to_string(_nodeId)); +#endif + + _isDisposed = true; + + // Clear parent + this->setParent(nullptr); + + // Clear any async operations + _queuedNodeOps.clear(); + + // Callback signaling that we're done + if (_disposeCallback != nullptr) { + _disposeCallback(); + _disposeCallback = nullptr; + } + + // Clear props + if (_propsContainer != nullptr) { + _propsContainer->dispose(); + } + + // Remove children + std::vector> tmp; + { + std::lock_guard lock(_childrenLock); + tmp.reserve(_children.size()); + for (auto &child : _children) { + tmp.push_back(child); + } + _children.clear(); + } + for (auto &child : tmp) { + child->dispose(true); + } + } + } + + /** + Creates and sets up the property container + */ + void ensurePropertyContainer() { + if (_propsContainer == nullptr) { + _propsContainer = std::make_shared( + getType(), [weakSelf = weak_from_this()](BaseNodeProp *p) { + auto self = weakSelf.lock(); + if (self) { + self->onPropertyChanged(p); + } + }); + + // Ask sub classes to define their properties + defineProperties(_propsContainer.get()); + } + } + + const char *_type; + std::shared_ptr _context; + + std::shared_ptr _propsContainer; + + std::function _disposeCallback; + + std::vector> _children; + std::mutex _childrenLock; + + std::atomic _isDisposing = {false}; + bool _isDisposed = false; + + size_t _nodeId; + + std::vector> _queuedNodeOps; + + JsiDomNode *_parent = nullptr; + + NodeClass _nodeClass; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomRenderNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomRenderNode.h new file mode 100644 index 00000000000000..d811203a703be1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/JsiDomRenderNode.h @@ -0,0 +1,262 @@ + +#pragma once + +#include "ClipProp.h" +#include "DrawingContext.h" +#include "JsiDomDeclarationNode.h" +#include "JsiDomNode.h" +#include "LayerProp.h" +#include "MatrixProp.h" +#include "PaintProps.h" +#include "PointProp.h" +#include "RRectProp.h" +#include "RectProp.h" +#include "TransformProp.h" + +#include +#include +#include + +namespace RNSkia { + +class JsiDomRenderNode : public JsiDomNode { +public: + JsiDomRenderNode(std::shared_ptr context, + const char *type) + : JsiDomNode(context, type, NodeClass::RenderNode) {} + + void render(DrawingContext *context) { +#if SKIA_DOM_DEBUG + printDebugInfo("Begin Render"); +#endif + + auto parentPaint = context->getPaint(); + auto cache = + _paintCache.parent == parentPaint ? _paintCache.child : nullptr; + + auto shouldRestore = + context->saveAndConcat(_paintProps, getChildren(), cache); + + auto shouldTransform = _matrixProp->isSet() || _transformProp->isSet(); + auto shouldSave = + shouldTransform || _clipProp->isSet() || _layerProp->isSet(); + + // Handle matrix/transforms + if (shouldSave) { + // Save canvas state + if (_layerProp->isSet()) { + if (_layerProp->isBool()) { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo("canvas->saveLayer()"); +#endif + context->getCanvas()->saveLayer( + SkCanvas::SaveLayerRec(nullptr, nullptr, nullptr, 0)); + } else { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo("canvas->saveLayer(paint)"); +#endif + context->getCanvas()->saveLayer(SkCanvas::SaveLayerRec( + nullptr, _layerProp->getDerivedValue().get(), nullptr, 0)); + } + } else { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo("canvas->save()"); +#endif + context->getCanvas()->save(); + } + + if (_originProp->isSet()) { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo("canvas->translate(origin)"); +#endif + // Handle origin + context->getCanvas()->translate(_originProp->getDerivedValue()->x(), + _originProp->getDerivedValue()->y()); + } + + if (shouldTransform) { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo( + "canvas->concat(" + + std::string(_matrixProp->isSet() ? "matrix" : "transform") + + std::string(")")); +#endif + auto matrix = _matrixProp->isSet() ? _matrixProp->getDerivedValue() + : _transformProp->getDerivedValue(); + + // Concat canvas' matrix with our matrix + context->getCanvas()->concat(*matrix); + } + + // Clipping + if (_clipProp->isSet()) { + auto invert = _invertClip->isSet() && _invertClip->value().getAsBool(); + clip(context, context->getCanvas(), invert); + } + + if (_originProp->isSet()) { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo("canvas->translate(-origin)"); +#endif + // Handle origin + context->getCanvas()->translate(-_originProp->getDerivedValue()->x(), + -_originProp->getDerivedValue()->y()); + } + } + + // Render the node + renderNode(context); + + // Restore if needed + if (shouldSave) { +#if SKIA_DOM_DEBUG_VERBOSE + printDebugInfo("canvas->restore()"); +#endif + context->getCanvas()->restore(); + } + + if (shouldRestore) { + _paintCache.parent = parentPaint; + _paintCache.child = context->getPaint(); + context->restore(); + } + +#if SKIA_DOM_DEBUG + printDebugInfo("End Render"); +#endif + } + + /** + Override reset (last thing that happens in the render cycle) to also reset + the changed flag on the local drawing context if necessary. + */ + void resetPendingChanges() override { JsiDomNode::resetPendingChanges(); } + + /** + Overridden dispose to release resources + */ + void dispose(bool immediate) override { + JsiDomNode::dispose(immediate); + _paintCache.clear(); + } + +protected: + /** + Invalidates and marks then context as changed. + */ + void invalidateContext() override { + enqueAsynOperation([weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + std::static_pointer_cast(self)->_paintCache.parent = + nullptr; + std::static_pointer_cast(self)->_paintCache.child = + nullptr; + } + }); + } + + /** + Override to implement rendering where the current state of the drawing + context is correctly set. + */ + virtual void renderNode(DrawingContext *context) = 0; + + /** + Define common properties for all render nodes + */ + void defineProperties(NodePropsContainer *container) override { + JsiDomNode::defineProperties(container); + + _paintProps = container->defineProperty(); + + _matrixProp = container->defineProperty("matrix"); + _transformProp = container->defineProperty("transform"); + _originProp = container->defineProperty("origin"); + _clipProp = container->defineProperty("clip"); + _invertClip = container->defineProperty("invertClip"); + _layerProp = container->defineProperty("layer"); + } + + /** + Validates that only declaration nodes can be children + */ + void addChild(std::shared_ptr child) override { + JsiDomNode::addChild(child); + _paintCache.parent = nullptr; + _paintCache.child = nullptr; + } + + /** + Validates that only declaration nodes can be children + */ + void insertChildBefore(std::shared_ptr child, + std::shared_ptr before) override { + JsiDomNode::insertChildBefore(child, before); + _paintCache.parent = nullptr; + _paintCache.child = nullptr; + } + + /** + A property changed + */ + void onPropertyChanged(BaseNodeProp *prop) override { + static std::vector paintProps = { + JsiPropId::get("color"), JsiPropId::get("strokeWidth"), + JsiPropId::get("blendMode"), JsiPropId::get("strokeCap"), + JsiPropId::get("strokeJoin"), JsiPropId::get("strokeMiter"), + JsiPropId::get("style"), JsiPropId::get("antiAlias"), + JsiPropId::get("opacity")}; + + // We'll invalidate paint if a prop change happened in a paint property + if (std::find(paintProps.begin(), paintProps.end(), prop->getName()) != + paintProps.end()) { + invalidateContext(); + } + } + +private: + /** + Clips the canvas depending on the clip property + */ + void clip(DrawingContext *context, SkCanvas *canvas, bool invert) { + auto op = invert ? SkClipOp::kDifference : SkClipOp::kIntersect; + if (_clipProp->getRect() != nullptr) { +#if SKIA_DOM_DEBUG + printDebugInfo("canvas->clipRect()"); +#endif + canvas->clipRect(*_clipProp->getRect(), op, true); + } else if (_clipProp->getRRect() != nullptr) { +#if SKIA_DOM_DEBUG + printDebugInfo("canvas->clipRRect()"); +#endif + canvas->clipRRect(*_clipProp->getRRect(), op, true); + } else if (_clipProp->getPath() != nullptr) { +#if SKIA_DOM_DEBUG + printDebugInfo("canvas->clipPath()"); +#endif + canvas->clipPath(*_clipProp->getPath(), op, true); + } + } + + struct PaintCache { + void clear() { + parent = nullptr; + child = nullptr; + } + std::shared_ptr parent; + std::shared_ptr child; + }; + + PaintCache _paintCache; + + PointProp *_originProp; + MatrixProp *_matrixProp; + TransformProp *_transformProp; + NodeProp *_invertClip; + ClipProp *_clipProp; + LayerProp *_layerProp; + PaintProps *_paintProps; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/NodeProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/NodeProp.h new file mode 100644 index 00000000000000..e3df3bdd2f2cfd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/NodeProp.h @@ -0,0 +1,139 @@ +#pragma once + +#include "BaseNodeProp.h" +#include "JsiValue.h" + +#include +#include +#include +#include + +namespace RNSkia { + +/** + Simple class for reading a property by name from the Dom Node properties + object. + */ +class NodeProp : public BaseNodeProp, + public std::enable_shared_from_this { +public: + /** + Constructs a new optional dom node properrty + */ + explicit NodeProp(const std::string &name, + const std::function &onChange) + : _name(JsiPropId::get(name)), _onChange(onChange), BaseNodeProp() {} + + /** + Reads JS value and swaps out with a new value + */ + void readValueFromJs(jsi::Runtime &runtime, + const ReadPropFunc &read) override { + // If the value is a nullptr this is the first call to the + // readValueFromJS Function (which comes from the reconciler + // setting a new property value on the property + if (_value == nullptr) { + _value = std::make_unique(runtime, read(runtime, _name, this)); + _isChanged = true; + _hasNewValue = false; + } else { + // Otherwise we'll just update the buffer and commit it later. + std::lock_guard lock(_swapMutex); + if (_buffer == nullptr) { + _buffer = + std::make_unique(runtime, read(runtime, _name, this)); + } else { + _buffer->setCurrent(runtime, read(runtime, _name, this)); + } + _hasNewValue = *_buffer.get() != *_value.get(); + if (_hasNewValue && _onChange != nullptr) { + _onChange(this); + } + } + } + + /** + Property value has changed - let's save this as a change to be commited later + */ + void updateValue(jsi::Runtime &runtime, const jsi::Value &value) { + // Always use the next field since this method is called on the JS thread + // and we don't want to rip out the underlying value object. + std::lock_guard lock(_swapMutex); + if (_buffer == nullptr) { + _buffer = std::make_unique(runtime, value); + } else { + _buffer->setCurrent(runtime, value); + } + // This is almost always a change - meaning a swap is + // cheaper than comparing for equality. + _hasNewValue = true; + if (_onChange != nullptr) { + _onChange(this); + } + } + + /** + Returns true if the property is set and is not undefined or null + */ + bool isSet() override { + return _value != nullptr && !_value->isUndefinedOrNull(); + } + + /** + True if the property has changed since we last visited it + */ + bool isChanged() override { return _isChanged; } + + /** + Starts the process of updating and reading props + */ + void updatePendingChanges() override { + // If the value has changed we should swap the + // buffers + if (_hasNewValue && _buffer != nullptr) { + { + // Swap buffers + std::lock_guard lock(_swapMutex); + _value.swap(_buffer); + + // turn off pending changes flag + _hasNewValue = false; + } + + // Mark as changed. + _isChanged = true; + } + } + + /* + Ends the visit cycle + */ + void markAsResolved() override { _isChanged = false; } + + /** + Returns pointer to the value contained by the property if the property is + set. + */ + const JsiValue &value() { + assert(isSet()); + return *_value; + } + + /** + Returns the name of the property + */ + std::string getName() override { return std::string(_name); } + +private: + PropId _name; + + std::function _onChange; + + std::unique_ptr _value; + std::unique_ptr _buffer; + std::atomic _isChanged = {false}; + std::atomic _hasNewValue = {false}; + std::mutex _swapMutex; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/NodePropsContainer.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/NodePropsContainer.h new file mode 100644 index 00000000000000..7348276ea40b27 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/base/NodePropsContainer.h @@ -0,0 +1,158 @@ +#pragma once + +#include "DrawingContext.h" +#include "JsiValue.h" +#include "NodeProp.h" + +#include +#include +#include +#include +#include + +namespace RNSkia { + +/** + This class manages marshalling from JS values over JSI to C++ values and is + typically called when a new node is created or an existing node is updated from + the reconciler. + */ +class NodePropsContainer { +public: + /** + Constructor for the node prop container + */ + explicit NodePropsContainer( + PropId componentType, + const std::function &onPropChanged) + : _onPropChanged(onPropChanged), _type(componentType) {} + + /** + Returns true if there are any changes in the props container in the current + being/end visit + */ + bool isChanged() { + for (auto &prop : _properties) { + if (prop->isChanged()) { + return true; + } + } + return false; + } + + /** + Enumerate all mapped properties + */ + void enumerateMappedProps( + const std::function)> &callback) { + std::lock_guard lock(_mappedPropsLock); + for (auto &props : _mappedProperties) { + callback(props.first, props.second); + } + } + + /** + Enumerates a named property instances from the mapped properties list + */ + void + enumerateMappedPropsByName(const std::string &name, + const std::function &callback) { + std::lock_guard lock(_mappedPropsLock); + auto propMapIt = _mappedProperties.find(JsiPropId::get(name)); + if (propMapIt != _mappedProperties.end()) { + for (auto &prop : propMapIt->second) { + callback(prop); + } + } + } + + /** + Updates any props that has changes waiting, updates props that have derived + values + */ + void updatePendingValues() { + for (auto &prop : _properties) { + prop->updatePendingChanges(); + if (prop->isRequired() && !prop->isSet()) { + throw std::runtime_error("Missing one or more required properties " + + std::string(prop->getName()) + " in the " + + _type + " component."); + } + } + } + + /** + We're done, mark any changes as committed in all props + */ + void markAsResolved() { + for (auto &prop : _properties) { + prop->markAsResolved(); + } + } + + /** + Clears all props and data from the container + */ + void dispose() { + std::lock_guard lock(_mappedPropsLock); + _properties.clear(); + _mappedProperties.clear(); + } + + /** + Called when the React / JS side sets properties on a node + */ + void setProps(jsi::Runtime &runtime, const jsi::Value &maybePropsObject) { + std::lock_guard lock(_mappedPropsLock); + + // Clear property mapping + _mappedProperties.clear(); + + if (!maybePropsObject.isObject()) { + throw jsi::JSError(runtime, "Expected property object."); + } + + auto props = maybePropsObject.asObject(runtime); + + // Use specialized reader function to be able to intercept calls that + // reads specific named values from the js property object. + auto read = [&](jsi::Runtime &runtime, PropId name, NodeProp *prop) { + if (_mappedProperties.count(name) == 0) { + std::vector tmp; + _mappedProperties[name] = std::move(tmp); + } + _mappedProperties.at(name).push_back(prop); + return props.getProperty(runtime, name); + }; + + for (auto &prop : _properties) { + prop->readValueFromJs(runtime, read); + } + } + + /** + Defines a property that will be added to the container + */ + template ::value>> + _Tp *defineProperty(_Args &&...__args) { + // Create property and set onChange callback + auto prop = + std::make_shared<_Tp>(std::forward<_Args>(__args)..., _onPropChanged); + + // Add to props list + _properties.push_back(prop); + + return prop.get(); + } + +private: + std::function _onPropChanged; + std::vector> _properties; + std::map> _mappedProperties; + PropId _type; + std::mutex _mappedPropsLock; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBackdropFilterNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBackdropFilterNode.h new file mode 100644 index 00000000000000..b176bc10f440a7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBackdropFilterNode.h @@ -0,0 +1,49 @@ +#pragma once + +#include "CircleProp.h" +#include "JsiDomDrawingNode.h" + +#include + +namespace RNSkia { + +class JsiBackdropFilterNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiBackdropFilterNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skBackdropFilter") {} + +protected: + void draw(DrawingContext *context) override { + auto children = getChildren(); + + if (children.size() == 0) { + return; + } + + auto canvas = context->getCanvas(); + auto firstChild = children[0]; + sk_sp imageFilter; + + if (firstChild->getNodeClass() == NodeClass::DeclarationNode) { + context->getDeclarationContext()->save(); + firstChild->decorateContext(context->getDeclarationContext()); + auto imgF = context->getDeclarationContext()->getImageFilters()->pop(); + if (imgF) { + imageFilter = imgF; + } else { + auto cf = context->getDeclarationContext()->getColorFilters()->pop(); + if (cf) { + imageFilter = SkImageFilters::ColorFilter(cf, nullptr); + } + } + context->getDeclarationContext()->restore(); + } + + canvas->saveLayer( + SkCanvas::SaveLayerRec(nullptr, nullptr, imageFilter.get(), 0)); + canvas->restore(); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBlendNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBlendNode.h new file mode 100644 index 00000000000000..4dd6d8f6f5bd54 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBlendNode.h @@ -0,0 +1,94 @@ +#pragma once + +#include "JsiDomDeclarationNode.h" + +#include +#include +#include + +namespace RNSkia { + +class JsiBlendNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiBlendNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skBlend", + DeclarationType::ImageFilter) {} + + void decorate(DeclarationContext *context) override { + + // No need to do anything if there are no children here + if (getChildren().size() == 0) { + return; + } + + decorateChildren(context); + + // Blend mode + auto blendMode = *_blendProp->getDerivedValue(); + + // Shader + auto shader = context->getShaders()->popAsOne( + [blendMode](sk_sp inner, sk_sp outer) { + return SkShaders::Blend(blendMode, outer, inner); + }); + + if (shader != nullptr) { + context->getShaders()->push(shader); + } + + auto imageFilter = + context->getImageFilters()->Declaration>::popAsOne( + [blendMode](sk_sp inner, + sk_sp outer) { + return SkImageFilters::Blend(blendMode, outer, inner); + }); + if (imageFilter != nullptr) { + context->getImageFilters()->push(imageFilter); + } + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _blendProp = container->defineProperty("mode"); + _blendProp->require(); + } + + /** + Validates that only declaration nodes can be children + */ + void addChild(std::shared_ptr child) override { + JsiDomDeclarationNode::addChild(child); + // Verify declaration of either shader or image filter + verifyChild(child); + } + + /** + Validates that only declaration nodes can be children + */ + void insertChildBefore(std::shared_ptr child, + std::shared_ptr before) override { + JsiDomDeclarationNode::insertChildBefore(child, before); + // Verify declaration of either shader or image filter + verifyChild(child); + } + +private: + void verifyChild(std::shared_ptr child) { + if (child->getNodeClass() != NodeClass::DeclarationNode || + (std::static_pointer_cast(child) + ->getDeclarationType() != DeclarationType::Shader && + std::static_pointer_cast(child) + ->getDeclarationType() != DeclarationType::ImageFilter)) { + // We'll raise an error when other children are added. + std::runtime_error("Blend nodes only supports either shaders or image " + "filters as children, got " + + std::string(child->getType()) + "."); + } + } + + BlendModeProp *_blendProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBlurMaskNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBlurMaskNode.h new file mode 100644 index 00000000000000..e98b29e4c60cee --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBlurMaskNode.h @@ -0,0 +1,75 @@ +#pragma once + +#include "JsiDomDeclarationNode.h" + +#include "NodeProp.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBlurTypes.h" +#include "SkMaskFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class JsiBlurMaskNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiBlurMaskNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skBlurMaskFilter", + DeclarationType::MaskFilter) {} + + void decorate(DeclarationContext *context) override { + + bool respectCTM = + _respectCTM->isSet() ? _respectCTM->value().getAsBool() : true; + SkBlurStyle style = SkBlurStyle::kNormal_SkBlurStyle; + if (_style->isSet()) { + style = getBlurStyleFromString(_style->value().getAsString()); + } + + auto filter = + SkMaskFilter::MakeBlur(style, _blur->value().getAsNumber(), respectCTM); + + // Set the mask filter + context->getMaskFilters()->push(filter); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _style = container->defineProperty("style"); + _respectCTM = container->defineProperty("respectCTM"); + _blur = container->defineProperty("blur"); + + _blur->require(); + } + +private: + SkBlurStyle getBlurStyleFromString(const std::string &value) { + if (value == "normal") { + return SkBlurStyle::kNormal_SkBlurStyle; + } else if (value == "solid") { + return SkBlurStyle::kSolid_SkBlurStyle; + } else if (value == "outer") { + return SkBlurStyle::kOuter_SkBlurStyle; + } else if (value == "inner") { + return SkBlurStyle::kInner_SkBlurStyle; + } + getContext()->raiseError(std::runtime_error( + "The value \"" + value + "\" is not " + "a valid blur style.")); + return SkBlurStyle::kNormal_SkBlurStyle; + } + + NodeProp *_style; + NodeProp *_respectCTM; + NodeProp *_blur; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBoxNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBoxNode.h new file mode 100644 index 00000000000000..33991ce34fabdb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBoxNode.h @@ -0,0 +1,94 @@ +#pragma once + +#include "JsiBoxShadowNode.h" +#include "JsiDomRenderNode.h" + +#include +#include + +namespace RNSkia { + +class JsiBoxNode : public JsiDomRenderNode, public JsiDomNodeCtor { +public: + explicit JsiBoxNode(std::shared_ptr context) + : JsiDomRenderNode(context, "skBox") {} + +protected: + void renderNode(DrawingContext *context) override { + // Get rect - we'll try to end up with an rrect: + auto box = *_boxProp->getDerivedValue(); + + // Get shadows + std::vector> shadows; + for (auto &child : getChildren()) { + auto shadowNode = std::dynamic_pointer_cast(child); + if (shadowNode != nullptr && shadowNode->getBoxShadowProps()->isSet()) { + shadows.push_back(shadowNode); + } + } + // Render outer shadows + for (auto &shadow : shadows) { + if (!shadow->getBoxShadowProps()->isInner()) { + // Now let's render + auto dx = shadow->getBoxShadowProps()->getDx(); + auto dy = shadow->getBoxShadowProps()->getDy(); + auto spread = shadow->getBoxShadowProps()->getSpread(); + + context->getCanvas()->drawRRect( + inflate(box, spread, spread, dx, dy), + *shadow->getBoxShadowProps()->getDerivedValue()); + } + } + + // Render box + context->getCanvas()->drawRRect(box, *context->getPaint()); + + // Render inner shadows + for (auto &shadow : shadows) { + if (shadow->getBoxShadowProps()->isInner()) { + // Now let's render + auto dx = shadow->getBoxShadowProps()->getDx(); + auto dy = shadow->getBoxShadowProps()->getDy(); + auto spread = shadow->getBoxShadowProps()->getSpread(); + auto delta = SkPoint::Make(10 + std::abs(dx), 10 + std::abs(dy)); + + context->getCanvas()->save(); + context->getCanvas()->clipRRect(box, SkClipOp::kIntersect, false); + + auto inner = deflate(box, spread, spread, dx, dy); + auto outer = inflate(box, delta.x(), delta.y()); + + // Render! + context->getCanvas()->drawDRRect( + outer, inner, *shadow->getBoxShadowProps()->getDerivedValue()); + + context->getCanvas()->restore(); + } + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomRenderNode::defineProperties(container); + _boxProp = container->defineProperty("box"); + _boxProp->require(); + } + +private: + SkRRect inflate(const SkRRect &box, SkScalar dx, SkScalar dy, SkScalar tx = 0, + SkScalar ty = 0) { + return SkRRect::MakeRectXY( + SkRect::MakeXYWH(box.rect().x() - dx + tx, box.rect().y() - dy + ty, + box.rect().width() + 2 * dx, + box.rect().height() + 2 * dy), + box.getSimpleRadii().x() + dx, box.getSimpleRadii().y() + dy); + } + + SkRRect deflate(const SkRRect &box, SkScalar dx, SkScalar dy, SkScalar tx = 0, + SkScalar ty = 0) { + return inflate(box, -dx, -dy, tx, ty); + } + + BoxProps *_boxProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBoxShadowNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBoxShadowNode.h new file mode 100644 index 00000000000000..b3d97160963dc4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiBoxShadowNode.h @@ -0,0 +1,33 @@ +#pragma once + +#include "BoxShadowProps.h" +#include "JsiDomDeclarationNode.h" + +#include + +namespace RNSkia { + +class JsiBoxShadowNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiBoxShadowNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skBoxShadow", + DeclarationType::Unknown) {} + + BoxShadowProps *getBoxShadowProps() { return _boxShadowProps; } + + void decorate(DeclarationContext *context) override { + // Do nothing, we are just a container for properties + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _boxShadowProps = container->defineProperty(); + } + +private: + BoxShadowProps *_boxShadowProps; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiCircleNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiCircleNode.h new file mode 100644 index 00000000000000..3ea2ec03963222 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiCircleNode.h @@ -0,0 +1,35 @@ +#pragma once + +#include "CircleProp.h" +#include "JsiDomDrawingNode.h" + +#include + +namespace RNSkia { + +class JsiCircleNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiCircleNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skCircle") {} + +protected: + void draw(DrawingContext *context) override { + auto circle = _circleProp->getDerivedValue(); + auto r = _radiusProp->value().getAsNumber(); + context->getCanvas()->drawCircle(*circle, r, *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _circleProp = container->defineProperty(); + _radiusProp = container->defineProperty("r"); + _radiusProp->require(); + } + +private: + CircleProp *_circleProp; + NodeProp *_radiusProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiColorFilterNodes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiColorFilterNodes.h new file mode 100644 index 00000000000000..bef1c97472bc91 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiColorFilterNodes.h @@ -0,0 +1,164 @@ +#pragma once + +#include "JsiDomDeclarationNode.h" + +#include "BlendModeProp.h" +#include "ColorProp.h" +#include "NodeProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkColorFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class JsiBaseColorFilterNode : public JsiDomDeclarationNode { +public: + JsiBaseColorFilterNode(std::shared_ptr context, + const char *type) + : JsiDomDeclarationNode(context, type, DeclarationType::ColorFilter) {} + +protected: + void composeAndPush(DeclarationContext *context, sk_sp cf1) { + context->save(); + decorateChildren(context); + auto cf2 = context->getColorFilters()->popAsOne(); + context->restore(); + auto cf = cf2 ? SkColorFilters::Compose(cf1, cf2) : cf1; + context->getColorFilters()->push(cf); + } +}; + +class JsiMatrixColorFilterNode + : public JsiBaseColorFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiMatrixColorFilterNode( + std::shared_ptr context) + : JsiBaseColorFilterNode(context, "skMatrixColorFilter") {} + + void decorate(DeclarationContext *context) override { + auto array = _matrixProp->value().getAsArray(); + float matrix[20]; + for (int i = 0; i < 20; i++) { + if (array.size() > i) { + matrix[i] = array[i].getAsNumber(); + } + } + composeAndPush(context, SkColorFilters::Matrix(matrix)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _matrixProp = container->defineProperty("matrix"); + _matrixProp->require(); + } + +private: + NodeProp *_matrixProp; +}; + +class JsiBlendColorFilterNode : public JsiBaseColorFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiBlendColorFilterNode(std::shared_ptr context) + : JsiBaseColorFilterNode(context, "skBlendColorFilter") {} + + void decorate(DeclarationContext *context) override { + auto color = _colorProp->getDerivedValue(); + auto mode = _blendModeProp->getDerivedValue(); + composeAndPush(context, SkColorFilters::Blend(*color, *mode)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _blendModeProp = container->defineProperty("mode"); + _colorProp = container->defineProperty("color"); + + _blendModeProp->require(); + _colorProp->require(); + } + +private: + BlendModeProp *_blendModeProp; + ColorProp *_colorProp; +}; + +class JsiLinearToSRGBGammaColorFilterNode + : public JsiBaseColorFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiLinearToSRGBGammaColorFilterNode( + std::shared_ptr context) + : JsiBaseColorFilterNode(context, "skLinearToSRGBGammaColorFilter") {} + + void decorate(DeclarationContext *context) override { + composeAndPush(context, SkColorFilters::LinearToSRGBGamma()); + } +}; + +class JsiSRGBToLinearGammaColorFilterNode + : public JsiBaseColorFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiSRGBToLinearGammaColorFilterNode( + std::shared_ptr context) + : JsiBaseColorFilterNode(context, "skSRGBToLinearGammaColorFilter") {} + + void decorate(DeclarationContext *context) override { + composeAndPush(context, SkColorFilters::SRGBToLinearGamma()); + } +}; + +class JsiLumaColorFilterNode : public JsiBaseColorFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiLumaColorFilterNode(std::shared_ptr context) + : JsiBaseColorFilterNode(context, "skLumaColorFilter") {} + + void decorate(DeclarationContext *context) override { + composeAndPush(context, SkLumaColorFilter::Make()); + } +}; + +class JsiLerpColorFilterNode : public JsiBaseColorFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiLerpColorFilterNode(std::shared_ptr context) + : JsiBaseColorFilterNode(context, "skLerpColorFilter") {} + + void decorate(DeclarationContext *context) override { + context->save(); + decorateChildren(context); + auto second = context->getColorFilters()->pop(); + auto first = context->getColorFilters()->pop(); + context->restore(); + + if (first == nullptr || second == nullptr) { + throw std::runtime_error( + "LerpColorFilterNode: missing two color filters as children"); + } + + auto t = _tProp->value().getAsNumber(); + context->getColorFilters()->push(SkColorFilters::Lerp(t, first, second)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _tProp = container->defineProperty("t"); + _tProp->require(); + } + +private: + NodeProp *_tProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiCustomDrawingNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiCustomDrawingNode.h new file mode 100644 index 00000000000000..896015649dc4bb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiCustomDrawingNode.h @@ -0,0 +1,127 @@ +#pragma once + +#include "DrawingProp.h" +#include "JsiDomDrawingNode.h" + +#include "JsiSkCanvas.h" +#include "JsiSkPaint.h" + +#include +#include +#include + +namespace RNSkia { + +class JsiCustomDrawingNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiCustomDrawingNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skCustomDrawing") {} + +protected: + void draw(DrawingContext *context) override { + if (_drawing != nullptr) { + + // Only repaint the picture IF we did not get to the draw function + // from a redrawRequest after creating the picture! + if (!_inRedrawCycle || _drawingProp->isChanged()) { + + float scaledWidth = context->getScaledWidth(); + float scaledHeight = context->getScaledHeight(); + auto paint = context->getPaint(); + auto platformContext = getContext(); + auto requestRedraw = context->getRequestRedraw(); + + // Create/set the paint/canvas wrappers + if (_jsiPaint == nullptr) { + _jsiPaint = std::make_shared(getContext(), *paint); + } else { + _jsiPaint->fromPaint(*paint); + } + + if (_jsiCanvas == nullptr) { + _jsiCanvas = std::make_shared(getContext()); + } + + // Run rendering on the javascript thread + getContext()->runOnJavascriptThread([this, platformContext, + requestRedraw, scaledWidth, + scaledHeight]() { + // Get the runtime + auto runtime = platformContext->getJsRuntime(); + + // Create the picture recorder + SkPictureRecorder recorder; + SkRTreeFactory factory; + SkCanvas *canvas = + recorder.beginRecording(scaledWidth, scaledHeight, &factory); + + auto jsiCanvas = + std::make_shared(platformContext, canvas); + + // Create context wrapper + auto jsiCtx = jsi::Object(*runtime); + jsiCtx.setProperty( + *runtime, "paint", + jsi::Object::createFromHostObject(*runtime, this->_jsiPaint)); + + jsiCtx.setProperty( + *runtime, "canvas", + jsi::Object::createFromHostObject(*runtime, jsiCanvas)); + + std::array args; + args[0] = std::move(jsiCtx); + + // Draw + _drawing(*runtime, jsi::Value::undefined(), + static_cast(args.data()), 1); + + auto picture = recorder.finishRecordingAsPicture(); + { + // Lock access to the picture property's setter + std::lock_guard lock(_pictureLock); + this->_drawingProp->setPicture(picture); + } + + // Ask view to redraw itself + _inRedrawCycle = true; + requestRedraw(); + }); + } + } + + if (_drawingProp->isSet()) { + std::lock_guard lock(_pictureLock); + context->getCanvas()->drawPicture(_drawingProp->getDerivedValue()); + _inRedrawCycle = false; + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + + NotifyNeedRenderCallback cb = + std::bind(&JsiCustomDrawingNode::notifyPictureNeeded, this, + std::placeholders::_1); + + _drawingProp = container->defineProperty("drawing", cb); + } + +private: + void notifyPictureNeeded(jsi::HostFunctionType drawing) { + _drawing = drawing; + } + + jsi::HostFunctionType _drawing; + + DrawingProp *_drawingProp; + + std::array _argsCache; + std::shared_ptr _jsiPaint; + std::shared_ptr _jsiCanvas; + + std::atomic _inRedrawCycle = {false}; + std::mutex _pictureLock; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiDiffRectNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiDiffRectNode.h new file mode 100644 index 00000000000000..e8926d9f6aaf5d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiDiffRectNode.h @@ -0,0 +1,37 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "RRectProp.h" + +#include + +namespace RNSkia { + +class JsiDiffRectNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiDiffRectNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skDiffRect") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawDRRect(*_outerRectProp->getDerivedValue(), + *_innerRectProp->getDerivedValue(), + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _innerRectProp = container->defineProperty("inner"); + _outerRectProp = container->defineProperty("outer"); + + _innerRectProp->require(); + _outerRectProp->require(); + } + +private: + RRectProp *_innerRectProp; + RRectProp *_outerRectProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiFillNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiFillNode.h new file mode 100644 index 00000000000000..13e11d83aac1cd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiFillNode.h @@ -0,0 +1,22 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "RectProp.h" + +#include + +namespace RNSkia { + +class JsiFillNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiFillNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skFill") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawPaint(*context->getPaint()); + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiGlyphsNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiGlyphsNode.h new file mode 100644 index 00000000000000..a54a6e38407892 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiGlyphsNode.h @@ -0,0 +1,53 @@ +#pragma once + +#include "JsiDomDrawingNode.h" + +#include "FontProp.h" +#include "GlyphsProp.h" + +#include + +namespace RNSkia { + +class JsiGlyphsNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiGlyphsNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skGlyphs") {} + +protected: + void draw(DrawingContext *context) override { + auto x = _xProp->value().getAsNumber(); + auto y = _yProp->value().getAsNumber(); + auto font = _fontProp->getDerivedValue(); + if (font != nullptr) { + auto glyphInfo = _glyphsProp->getDerivedValue(); + + context->getCanvas()->drawGlyphs( + static_cast(glyphInfo->glyphIds.size()), + glyphInfo->glyphIds.data(), glyphInfo->positions.data(), + SkPoint::Make(x, y), *font, *context->getPaint()); + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + + _fontProp = container->defineProperty("font"); + _glyphsProp = container->defineProperty("glyphs"); + _xProp = container->defineProperty("x"); + _yProp = container->defineProperty("y"); + + _glyphsProp->require(); + _xProp->require(); + _yProp->require(); + } + +private: + FontProp *_fontProp; + GlyphsProp *_glyphsProp; + NodeProp *_xProp; + NodeProp *_yProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiGroupNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiGroupNode.h new file mode 100644 index 00000000000000..0d42adb0a7e11b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiGroupNode.h @@ -0,0 +1,25 @@ + +#pragma once + +#include "JsiDomRenderNode.h" + +#include + +namespace RNSkia { + +class JsiGroupNode : public JsiDomRenderNode, + public JsiDomNodeCtor { +public: + explicit JsiGroupNode(std::shared_ptr context) + : JsiDomRenderNode(context, "skGroup") {} + + void renderNode(DrawingContext *context) override { + for (auto &child : getChildren()) { + if (child->getNodeClass() == NodeClass::RenderNode) { + std::static_pointer_cast(child)->render(context); + } + } + } +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageFilterNodes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageFilterNodes.h new file mode 100644 index 00000000000000..7273a5b7987da3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageFilterNodes.h @@ -0,0 +1,361 @@ +#pragma once + +#include "JsiColorFilterNodes.h" +#include "JsiDomDeclarationNode.h" +#include "JsiShaderNodes.h" +#include "JsiSkRuntimeEffect.h" + +#include "NodeProp.h" +#include "RadiusProp.h" +#include "TileModeProp.h" +#include "UniformsProp.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkImageFilter.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class JsiBaseImageFilterNode : public JsiDomDeclarationNode { +public: + JsiBaseImageFilterNode(std::shared_ptr context, + const char *type) + : JsiDomDeclarationNode(context, type, DeclarationType::ImageFilter) {} + +protected: + void composeAndPush(DeclarationContext *context, sk_sp imgf1) { + context->save(); + decorateChildren(context); + auto imgf2 = context->getImageFilters()->popAsOne(); + auto cf = context->getColorFilters()->popAsOne(); + context->restore(); + if (cf != nullptr) { + imgf2 = SkImageFilters::Compose(imgf2, + SkImageFilters::ColorFilter(cf, nullptr)); + } + auto imgf = + imgf2 != nullptr ? SkImageFilters::Compose(imgf1, imgf2) : imgf1; + + context->getImageFilters()->push(imgf); + } +}; + +class JsiBlendImageFilterNode : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiBlendImageFilterNode(std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skBlendImageFilter") {} + + void decorate(DeclarationContext *context) override { + + if (getChildren().size() != 2) { + throw std::runtime_error("Blend image filter needs two child nodes."); + } + + auto background = context->getImageFilters()->pop(); + auto foreground = context->getImageFilters()->pop(); + + SkBlendMode blendMode = *_blendModeProp->getDerivedValue(); + composeAndPush(context, + SkImageFilters::Blend(blendMode, background, foreground)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _blendModeProp = container->defineProperty("mode"); + _blendModeProp->require(); + } + +private: + BlendModeProp *_blendModeProp; +}; + +class JsiDropShadowImageFilterNode + : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiDropShadowImageFilterNode( + std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skDropShadowImageFilter") {} + + void decorate(DeclarationContext *context) override { + + auto color = _colorProp->getDerivedValue(); + auto dx = _dxProp->value().getAsNumber(); + auto dy = _dyProp->value().getAsNumber(); + auto blur = _blurProp->value().getAsNumber(); + auto input = context->getImageFilters()->pop(); + + auto inner = _innerProp->isSet() && _innerProp->value().getAsBool(); + auto shadowOnly = + _shadowOnlyProp->isSet() && _shadowOnlyProp->value().getAsBool(); + + if (inner) { + auto srcGraphic = SkImageFilters::ColorFilter( + SkColorFilters::Blend(SK_ColorBLACK, SkBlendMode::kDst), nullptr); + auto srcAlpha = SkImageFilters::ColorFilter( + SkColorFilters::Blend(SK_ColorBLACK, SkBlendMode::kSrcIn), nullptr); + auto f1 = SkImageFilters::ColorFilter( + SkColorFilters::Blend(*color, SkBlendMode::kSrcOut), nullptr); + auto f2 = SkImageFilters::Offset(dx, dy, f1); + auto f3 = SkImageFilters::Blur(blur, blur, SkTileMode::kDecal, f2); + auto f4 = SkImageFilters::Blend(SkBlendMode::kSrcIn, srcAlpha, f3); + if (shadowOnly) { + composeAndPush(context, f4); + } else { + composeAndPush(context, SkImageFilters::Compose( + input ? input : nullptr, + SkImageFilters::Blend(SkBlendMode::kSrcOver, + srcGraphic, f4))); + } + + } else { + composeAndPush( + context, + shadowOnly ? SkImageFilters::DropShadowOnly( + dx, dy, blur, blur, *color, input ? input : nullptr) + : SkImageFilters::DropShadow(dx, dy, blur, blur, *color, + input ? input : nullptr)); + } + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _dxProp = container->defineProperty("dx"); + _dyProp = container->defineProperty("dy"); + _blurProp = container->defineProperty("blur"); + _colorProp = container->defineProperty("color"); + + _innerProp = container->defineProperty("inner"); + _shadowOnlyProp = container->defineProperty("shadowOnly"); + + _dxProp->require(); + _dyProp->require(); + _blurProp->require(); + _colorProp->require(); + } + +private: + NodeProp *_dxProp; + NodeProp *_dyProp; + NodeProp *_blurProp; + ColorProp *_colorProp; + NodeProp *_innerProp; + NodeProp *_shadowOnlyProp; +}; + +class JsiDisplacementMapImageFilterNode + : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiDisplacementMapImageFilterNode( + std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skDisplacementMapImageFilter") {} + + void decorate(DeclarationContext *context) override { + decorateChildren(context); + auto channelX = + getColorChannelFromStringValue(_channelXProp->value().getAsString()); + auto channelY = + getColorChannelFromStringValue(_channelYProp->value().getAsString()); + auto scale = _scaleProp->value().getAsNumber(); + auto shader = context->getShaders()->pop(); + if (!shader) { + throw std::runtime_error("DisplacementMap expects a shader as child"); + } + auto map = SkImageFilters::Shader(shader); + auto input = context->getImageFilters()->pop(); + auto imgf = SkImageFilters::DisplacementMap(channelX, channelY, scale, map, + input ? input : nullptr); + context->getImageFilters()->push(imgf); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _channelXProp = container->defineProperty("channelX"); + _channelYProp = container->defineProperty("channelY"); + _scaleProp = container->defineProperty("scale"); + + _channelXProp->require(); + _channelYProp->require(); + _scaleProp->require(); + } + +private: + SkColorChannel getColorChannelFromStringValue(const std::string &value) { + if (value == "r") { + return SkColorChannel::kR; + } else if (value == "g") { + return SkColorChannel::kG; + } else if (value == "b") { + return SkColorChannel::kB; + } else if (value == "a") { + return SkColorChannel::kA; + } + throw std::runtime_error("Value \"" + value + + "\" is not a valid color channel."); + } + + NodeProp *_channelXProp; + NodeProp *_channelYProp; + NodeProp *_scaleProp; +}; + +class JsiBlurImageFilterNode : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiBlurImageFilterNode(std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skBlurImageFilter") {} + + void decorate(DeclarationContext *context) override { + auto input = context->getImageFilters()->pop(); + auto imageFilter = SkImageFilters::Blur( + _blurProp->getDerivedValue()->x(), _blurProp->getDerivedValue()->y(), + _tileModeProp->isSet() ? *_tileModeProp->getDerivedValue() + : SkTileMode::kDecal, + input); + composeAndPush(context, imageFilter); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _blurProp = container->defineProperty("blur"); + _tileModeProp = container->defineProperty("mode"); + + _blurProp->require(); + } + +private: + RadiusProp *_blurProp; + TileModeProp *_tileModeProp; +}; + +class JsiOffsetImageFilterNode + : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiOffsetImageFilterNode( + std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skOffsetImageFilter") {} + + void decorate(DeclarationContext *context) override { + decorateChildren(context); + auto input = context->getImageFilters()->pop(); + composeAndPush(context, + SkImageFilters::Offset(_xProp->value().getAsNumber(), + _yProp->value().getAsNumber(), + input ? input : nullptr)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _xProp = container->defineProperty("x"); + _yProp = container->defineProperty("y"); + + _xProp->require(); + _yProp->require(); + } + +private: + NodeProp *_xProp; + NodeProp *_yProp; +}; + +class JsiMorphologyImageFilterNode + : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + enum Type { Dilate, Erode }; + + explicit JsiMorphologyImageFilterNode( + std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skMorphologyImageFilter") {} + + void decorate(DeclarationContext *context) override { + auto op = getTypeFromStringValue(_operatorProp->value().getAsString()); + auto radius = _radiusProp->getDerivedValue(); + auto input = context->getImageFilters()->pop(); + + if (op == Type::Dilate) { + composeAndPush(context, SkImageFilters::Dilate(radius->x(), radius->y(), + input ? input : nullptr)); + } else { + composeAndPush(context, SkImageFilters::Erode(radius->x(), radius->y(), + input ? input : nullptr)); + } + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _operatorProp = container->defineProperty("operator"); + _radiusProp = container->defineProperty("radius"); + + _operatorProp->require(); + _radiusProp->require(); + } + +private: + Type getTypeFromStringValue(const std::string &value) { + if (value == "erode") { + return Type::Erode; + } else if (value == "dilate") { + return Type::Dilate; + } + throw std::runtime_error("Value \"" + value + + "\" is not valid for the operator property in the " + "MorphologyImageFilter component."); + } + NodeProp *_operatorProp; + RadiusProp *_radiusProp; +}; + +class JsiRuntimeShaderImageFilterNode + : public JsiBaseImageFilterNode, + public JsiDomNodeCtor { +public: + explicit JsiRuntimeShaderImageFilterNode( + std::shared_ptr context) + : JsiBaseImageFilterNode(context, "skRuntimeShaderImageFilter") {} + + void decorate(DeclarationContext *context) override { + auto source = _sourceProp->value().getAs(); + if (source == nullptr) { + throw std::runtime_error("Expected runtime effect when reading source " + "property of RuntimeEffectImageFilter."); + } + + auto builder = SkRuntimeShaderBuilder(source->getObject()); + auto input = context->getImageFilters()->pop(); + _uniformsProp->processUniforms(builder); + + composeAndPush(context, SkImageFilters::RuntimeShader(builder, "", input)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _sourceProp = container->defineProperty("source"); + _uniformsProp = + container->defineProperty("uniforms", _sourceProp); + + _sourceProp->require(); + } + +private: + NodeProp *_sourceProp; + UniformsProp *_uniformsProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageNode.h new file mode 100644 index 00000000000000..46d6a2943fd1d4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageNode.h @@ -0,0 +1,38 @@ +#pragma once + +#include "ImageProps.h" +#include "JsiDomDrawingNode.h" + +#include + +namespace RNSkia { + +class JsiImageNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiImageNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skImage") {} + +protected: + void draw(DrawingContext *context) override { + auto rects = _imageProps->getDerivedValue(); + auto image = _imageProps->getImage(); + if (image == nullptr) { + return; + } + + context->getCanvas()->drawImageRect( + image, rects->src, rects->dst, SkSamplingOptions(), + context->getPaint().get(), SkCanvas::kStrict_SrcRectConstraint); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _imageProps = container->defineProperty(); + } + +private: + ImageProps *_imageProps; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageSvgNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageSvgNode.h new file mode 100644 index 00000000000000..1b207807263ffd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiImageSvgNode.h @@ -0,0 +1,63 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "RectProp.h" +#include "SvgProp.h" + +#include + +namespace RNSkia { + +class JsiImageSvgNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiImageSvgNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skImageSvg") {} + +protected: + void draw(DrawingContext *context) override { + auto svgDom = _svgDomProp->getDerivedValue(); + if (svgDom != nullptr) { + auto rect = _rectProp->getDerivedValue(); + auto x = _xProp->isSet() ? _xProp->value().getAsNumber() : -1; + auto y = _yProp->isSet() ? _yProp->value().getAsNumber() : -1; + auto width = _widthProp->isSet() ? _widthProp->value().getAsNumber() : -1; + auto height = + _widthProp->isSet() ? _heightProp->value().getAsNumber() : -1; + context->getCanvas()->save(); + if (rect != nullptr) { + context->getCanvas()->translate(rect->x(), rect->y()); + svgDom->setContainerSize(SkSize::Make(rect->width(), rect->height())); + } else { + if (x != -1 && y != -1) { + context->getCanvas()->translate(x, y); + } + if (width != -1 && height != -1) { + svgDom->setContainerSize(SkSize::Make(width, height)); + } + } + svgDom->render(context->getCanvas()); + context->getCanvas()->restore(); + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _svgDomProp = container->defineProperty("svg"); + _rectProp = container->defineProperty("rect"); + _xProp = container->defineProperty("x"); + _yProp = container->defineProperty("y"); + _widthProp = container->defineProperty("width"); + _heightProp = container->defineProperty("height"); + } + +private: + SvgProp *_svgDomProp; + RectProps *_rectProp; + NodeProp *_xProp; + NodeProp *_yProp; + NodeProp *_widthProp; + NodeProp *_heightProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiLayerNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiLayerNode.h new file mode 100644 index 00000000000000..adc44060743ce5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiLayerNode.h @@ -0,0 +1,74 @@ +#pragma once + +#include "JsiBoxShadowNode.h" +#include "JsiDomRenderNode.h" +#include "JsiPaintNode.h" + +#include +#include + +namespace RNSkia { + +class JsiLayerNode : public JsiDomRenderNode, + public JsiDomNodeCtor { +public: + explicit JsiLayerNode(std::shared_ptr context) + : JsiDomRenderNode(context, "skLayer") {} + +protected: + void renderNode(DrawingContext *context) override { + + auto hasLayer = false; + auto children = getChildren(); + + // Is the first children a layer? + for (size_t i = 0; i < children.size(); ++i) { + if (i == 0) { + // Check for paint node as layer + if (children.at(i)->getNodeClass() == NodeClass::DeclarationNode) { + auto declarationNode = + std::static_pointer_cast(children.at(i)); + + if (declarationNode->getDeclarationType() == DeclarationType::Paint) { + // Yes, it is a paint node - which we can use as a layer. + auto declarationContext = context->getDeclarationContext(); + auto layerNode = + std::static_pointer_cast(children.at(i)); + + // Save canvas with the paint node's paint! + declarationContext->save(); + layerNode->decorate(declarationContext); + auto paint = declarationContext->getPaints()->pop(); + declarationContext->restore(); + + if (paint) { + hasLayer = true; + context->getCanvas()->saveLayer( + SkCanvas::SaveLayerRec(nullptr, paint.get(), nullptr, 0)); + } + + continue; + } + } + } + + // Render rest of the children + if (children.at(i)->getNodeClass() == NodeClass::RenderNode) { + std::static_pointer_cast(children.at(i)) + ->render(context); + } + } + + if (hasLayer) { + context->getCanvas()->restore(); + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomRenderNode::defineProperties(container); + } + +private: +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiLineNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiLineNode.h new file mode 100644 index 00000000000000..2fd74466574535 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiLineNode.h @@ -0,0 +1,38 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "PointProp.h" + +#include + +namespace RNSkia { + +class JsiLineNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiLineNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skLine") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawLine( + _p1Prop->getDerivedValue()->x(), _p1Prop->getDerivedValue()->y(), + _p2Prop->getDerivedValue()->x(), _p2Prop->getDerivedValue()->y(), + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _p1Prop = container->defineProperty("p1"); + _p2Prop = container->defineProperty("p2"); + + _p1Prop->require(); + _p2Prop->require(); + } + +private: + PointProp *_p1Prop; + PointProp *_p2Prop; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiOvalNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiOvalNode.h new file mode 100644 index 00000000000000..b2c5bb6dbf4704 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiOvalNode.h @@ -0,0 +1,32 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "RectProp.h" + +#include + +namespace RNSkia { + +class JsiOvalNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiOvalNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skOval") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawOval(*_rectProp->getDerivedValue(), + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _rectProp = container->defineProperty("rect"); + _rectProp->require(); + } + +private: + RectProps *_rectProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPaintNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPaintNode.h new file mode 100644 index 00000000000000..d967b7515c8b27 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPaintNode.h @@ -0,0 +1,115 @@ +#pragma once + +#include "JsiDomDeclarationNode.h" +#include "PaintProps.h" + +#include + +namespace RNSkia { + +class JsiPaintNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiPaintNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skPaint", DeclarationType::Paint) {} + + void decorate(DeclarationContext *context) override { + auto paint = std::make_shared(); + paint->setAntiAlias(true); + + if (_paintProps->getOpacity()->isSet()) { + paint->setAlphaf(paint->getAlphaf() * + _paintProps->getOpacity()->value().getAsNumber()); + } + + if (_paintProps->getColor()->isSet()) { + auto currentOpacity = paint->getAlphaf(); + paint->setShader(nullptr); + paint->setColor(*_paintProps->getColor()->getDerivedValue()); + paint->setAlphaf(paint->getAlphaf() * currentOpacity); + } + + if (_paintProps->getStrokeWidth()->isSet()) { + paint->setStrokeWidth( + _paintProps->getStrokeWidth()->value().getAsNumber()); + } + + if (_paintProps->getBlendMode()->isSet()) { + paint->setBlendMode(*_paintProps->getBlendMode()->getDerivedValue()); + } + + if (_paintProps->getStyle()->isSet()) { + auto styleValue = _paintProps->getStyle()->value().getAsString(); + if (styleValue == "stroke") { + paint->setStyle(SkPaint::Style::kStroke_Style); + } else if (styleValue == "fill") { + paint->setStyle(SkPaint::Style::kFill_Style); + } else { + throw std::runtime_error( + styleValue + " is not a valud value for the style property."); + } + } + + if (_paintProps->getStrokeJoin()->isSet()) { + paint->setStrokeJoin(*_paintProps->getStrokeJoin()->getDerivedValue()); + } + + if (_paintProps->getStrokeCap()->isSet()) { + paint->setStrokeCap(*_paintProps->getStrokeCap()->getDerivedValue()); + } + + if (_paintProps->getStrokeMiter()->isSet()) { + paint->setStrokeMiter( + _paintProps->getStrokeMiter()->value().getAsNumber()); + } + + if (_paintProps->getAntiAlias()->isSet()) { + paint->setAntiAlias(_paintProps->getAntiAlias()->value().getAsBool()); + } + + context->save(); + decorateChildren(context); + + auto imageFilter = context->getImageFilters()->popAsOne(); + auto colorFilter = context->getColorFilters()->popAsOne(); + auto shader = context->getShaders()->pop(); + auto maskFilter = context->getMaskFilters()->pop(); + auto pathEffect = context->getPathEffects()->popAsOne(); + + context->restore(); + + if (imageFilter) { + paint->setImageFilter(imageFilter); + } + + if (colorFilter) { + paint->setColorFilter(colorFilter); + } + + if (shader) { + paint->setShader(shader); + } + + if (maskFilter) { + paint->setMaskFilter(maskFilter); + } + + if (pathEffect) { + paint->setPathEffect(pathEffect); + } + + context->getPaints()->push(paint); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _paintProps = container->defineProperty(); + } + +private: + PaintProps *_paintProps; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPatchNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPatchNode.h new file mode 100644 index 00000000000000..8563d02ee5a929 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPatchNode.h @@ -0,0 +1,50 @@ +#pragma once + +#include "BezierProps.h" +#include "BlendModeProp.h" +#include "ColorProp.h" +#include "JsiDomDrawingNode.h" +#include "PointsProp.h" + +#include + +namespace RNSkia { + +class JsiPatchNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiPatchNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skPatch") {} + +protected: + void draw(DrawingContext *context) override { + SkBlendMode defaultBlendMode = + _colorsProp->isSet() ? SkBlendMode::kDstOver : SkBlendMode::kSrcOver; + context->getCanvas()->drawPatch( + _patchProp->getDerivedValue()->data(), + _colorsProp->isSet() ? _colorsProp->getDerivedValue()->data() : nullptr, + _textureProp->isSet() ? _textureProp->getDerivedValue()->data() + : nullptr, + _blendModeProp->isSet() ? *_blendModeProp->getDerivedValue() + : defaultBlendMode, + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _colorsProp = container->defineProperty("colors"); + _textureProp = container->defineProperty("texture"); + _blendModeProp = container->defineProperty("blendMode"); + _patchProp = container->defineProperty("patch"); + + _patchProp->require(); + } + +private: + ColorsProp *_colorsProp; + PointsProp *_textureProp; + BlendModeProp *_blendModeProp; + BezierProp *_patchProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPathEffectNodes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPathEffectNodes.h new file mode 100644 index 00000000000000..d9d8b249c8a030 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPathEffectNodes.h @@ -0,0 +1,268 @@ +#pragma once + +#include "JsiDomDeclarationNode.h" + +#include "NodeProp.h" + +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPathEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class JsiBasePathEffectNode : public JsiDomDeclarationNode { +public: + JsiBasePathEffectNode(std::shared_ptr context, + const char *type) + : JsiDomDeclarationNode(context, type, DeclarationType::PathEffect) {} + +protected: + void composeAndPush(DeclarationContext *context, sk_sp pe1) { + context->save(); + decorateChildren(context); + auto pe2 = context->getPathEffects()->popAsOne(); + context->restore(); + auto pe = pe2 ? SkPathEffect::MakeCompose(pe1, pe2) : pe1; + context->getPathEffects()->push(pe); + } +}; + +class JsiDashPathEffectNode : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiDashPathEffectNode(std::shared_ptr context) + : JsiBasePathEffectNode(context, "skDashPathEffect") {} + + void decorate(DeclarationContext *context) override { + + // Phase + auto phase = _phase->isSet() ? _phase->value().getAsNumber() : 0; + + // Copy intervals + std::vector intervals; + auto intervalsArray = _intervals->value().getAsArray(); + for (size_t i = 0; i < intervalsArray.size(); ++i) { + intervals.push_back(intervalsArray[i].getAsNumber()); + } + + // Create effect + auto pathEffect = SkDashPathEffect::Make( + intervals.data(), static_cast(intervals.size()), phase); + + composeAndPush(context, pathEffect); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _intervals = container->defineProperty("intervals"); + _phase = container->defineProperty("phase"); + + _intervals->require(); + } + +private: + NodeProp *_intervals; + NodeProp *_phase; +}; + +class JsiDiscretePathEffectNode + : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiDiscretePathEffectNode( + std::shared_ptr context) + : JsiBasePathEffectNode(context, "skDiscretePathEffect") {} + + void decorate(DeclarationContext *context) override { + // Create effect + auto pathEffect = + SkDiscretePathEffect::Make(_lengthProp->value().getAsNumber(), + _deviationProp->value().getAsNumber(), + _seedProp->value().getAsNumber()); + + composeAndPush(context, pathEffect); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _lengthProp = container->defineProperty("length"); + _deviationProp = container->defineProperty("deviation"); + _seedProp = container->defineProperty("seed"); + + _lengthProp->require(); + _deviationProp->require(); + _seedProp->require(); + } + +private: + NodeProp *_lengthProp; + NodeProp *_deviationProp; + NodeProp *_seedProp; +}; + +class JsiCornerPathEffectNode : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiCornerPathEffectNode(std::shared_ptr context) + : JsiBasePathEffectNode(context, "skCornerPathEffect") {} + + void decorate(DeclarationContext *context) override { + // Create effect + auto pathEffect = SkCornerPathEffect::Make(_rProp->value().getAsNumber()); + + composeAndPush(context, pathEffect); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _rProp = container->defineProperty("r"); + _rProp->require(); + } + +private: + NodeProp *_rProp; +}; + +class JsiPath1DPathEffectNode : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiPath1DPathEffectNode(std::shared_ptr context) + : JsiBasePathEffectNode(context, "skPath1DPathEffect") {} + + void decorate(DeclarationContext *context) override { + // Create effect + auto pathEffect = SkPath1DPathEffect::Make( + *_pathProp->getDerivedValue(), _advanceProp->value().getAsNumber(), + _phaseProp->value().getAsNumber(), + getStyleFromStringValue(_styleProp->value().getAsString())); + + composeAndPush(context, pathEffect); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _phaseProp = container->defineProperty("phase"); + _advanceProp = container->defineProperty("advance"); + _pathProp = container->defineProperty("path"); + _styleProp = container->defineProperty("style"); + + _phaseProp->require(); + _advanceProp->require(); + _pathProp->require(); + _styleProp->require(); + } + +private: + SkPath1DPathEffect::Style getStyleFromStringValue(const std::string &value) { + if (value == "translate") { + return SkPath1DPathEffect::kTranslate_Style; + } else if (value == "rotate") { + return SkPath1DPathEffect::kRotate_Style; + } else if (value == "morph") { + return SkPath1DPathEffect::kMorph_Style; + } + throw std::runtime_error("Value \"" + value + + "\" is not a valid Path1D effect style."); + } + + NodeProp *_phaseProp; + NodeProp *_advanceProp; + NodeProp *_styleProp; + PathProp *_pathProp; +}; + +class JsiPath2DPathEffectNode : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiPath2DPathEffectNode(std::shared_ptr context) + : JsiBasePathEffectNode(context, "skPath2DPathEffect") {} + +protected: + void decorate(DeclarationContext *context) override { + + // Create effect + auto pathEffect = SkPath2DPathEffect::Make(*_matrixProp->getDerivedValue(), + *_pathProp->getDerivedValue()); + + composeAndPush(context, pathEffect); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _matrixProp = container->defineProperty("matrix"); + _pathProp = container->defineProperty("path"); + + _matrixProp->require(); + _pathProp->require(); + } + +private: + MatrixProp *_matrixProp; + PathProp *_pathProp; +}; + +class JsiLine2DPathEffectNode : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiLine2DPathEffectNode(std::shared_ptr context) + : JsiBasePathEffectNode(context, "skLine2DPathEffect") {} + +protected: + void decorate(DeclarationContext *context) override { + + // Create effect + auto pathEffect = SkLine2DPathEffect::Make( + _widthProp->value().getAsNumber(), *_matrixProp->getDerivedValue()); + + composeAndPush(context, pathEffect); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + + _matrixProp = container->defineProperty("matrix"); + _widthProp = container->defineProperty("width"); + + _matrixProp->require(); + _widthProp->require(); + } + +private: + MatrixProp *_matrixProp; + NodeProp *_widthProp; +}; + +class JsiSumPathEffectNode : public JsiBasePathEffectNode, + public JsiDomNodeCtor { +public: + explicit JsiSumPathEffectNode(std::shared_ptr context) + : JsiBasePathEffectNode(context, "skSumPathEffect") {} + +protected: + void decorate(DeclarationContext *context) override { + decorateChildren(context); + auto pe = + context->getPathEffects()->Declaration>::popAsOne( + [=](sk_sp inner, sk_sp outer) { + return SkPathEffect::MakeSum(inner, outer); + }); + context->getPathEffects()->push(pe); + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPathNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPathNode.h new file mode 100644 index 00000000000000..e98ec8f13bcd97 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPathNode.h @@ -0,0 +1,181 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "PathProp.h" + +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkTrimPathEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +static PropId PropNameMiterLimit = JsiPropId::get("miter_limit"); +static PropId PropNamePrecision = JsiPropId::get("precision"); + +class JsiPathNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiPathNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skPath") {} + +protected: + void draw(DrawingContext *context) override { + if (getPropsContainer()->isChanged()) { + auto start = saturate( + _startProp->isSet() ? _startProp->value().getAsNumber() : 0.0); + auto end = + saturate(_endProp->isSet() ? _endProp->value().getAsNumber() : 1.0); + // Can we use the path directly, or do we need to copy to + // mutate / modify the path? + auto hasStartOffset = start != 0.0; + auto hasEndOffset = end != 1.0; + auto hasFillStyle = _fillTypeProp->isSet(); + auto hasStrokeOptions = + _strokeOptsProp->isSet() && + _strokeOptsProp->value().getType() == PropType::Object; + + auto willMutatePath = hasStartOffset == true || hasEndOffset == true || + hasFillStyle == true || hasStrokeOptions == true; + + if (willMutatePath) { + // We'll trim the path + SkPath filteredPath(*_pathProp->getDerivedValue()); + auto pe = + SkTrimPathEffect::Make(start, end, SkTrimPathEffect::Mode::kNormal); + + if (pe != nullptr) { + SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle); + if (!pe->filterPath(&filteredPath, filteredPath, &rec, nullptr)) { + throw std::runtime_error( + "Failed trimming path with parameters start: " + + std::to_string(start) + ", end: " + std::to_string(end)); + } + filteredPath.swap(filteredPath); + _path = std::make_shared(filteredPath); + } else if (hasStartOffset || hasEndOffset) { + throw std::runtime_error( + "Failed trimming path with parameters start: " + + std::to_string(start) + ", end: " + std::to_string(end)); + } else { + _path = std::make_shared(filteredPath); + } + + // Set fill style + if (_fillTypeProp->isSet()) { + auto fillType = _fillTypeProp->value().getAsString(); + auto p = std::make_shared(*_path.get()); + p->setFillType(getFillTypeFromStringValue(fillType)); + _path = std::const_pointer_cast(p); + } + + // do we have a special paint here? + if (_strokeOptsProp->isSet()) { + auto opts = _strokeOptsProp->value(); + SkPaint strokePaint; + + if (opts.hasValue(JsiPropId::get("strokeCap"))) { + strokePaint.setStrokeCap(StrokeCapProp::getCapFromString( + opts.getValue(JsiPropId::get("strokeCap")).getAsString())); + } + + if (opts.hasValue(JsiPropId::get("strokeJoin"))) { + strokePaint.setStrokeJoin(StrokeJoinProp::getJoinFromString( + opts.getValue(JsiPropId::get("strokeJoin")).getAsString())); + } + + if (opts.hasValue(PropNameWidth)) { + strokePaint.setStrokeWidth( + opts.getValue(PropNameWidth).getAsNumber()); + } + + if (opts.hasValue(PropNameMiterLimit)) { + strokePaint.setStrokeMiter( + opts.getValue(PropNameMiterLimit).getAsNumber()); + } + + double precision = 1.0; + if (opts.hasValue(PropNamePrecision)) { + precision = opts.getValue(PropNamePrecision).getAsNumber(); + } + + // _path is const so we can't mutate it directly, let's replace the + // path like this: + auto p = std::make_shared(*_path.get()); + if (!skpathutils::FillPathWithPaint(*_path.get(), strokePaint, + p.get(), nullptr, precision)) { + _path = nullptr; + } else { + _path = std::const_pointer_cast(p); + } + } + + } else { + // We'll just draw the pure path + _path = _pathProp->getDerivedValue(); + } + } + + if (_path == nullptr) { + throw std::runtime_error( + "Path node could not resolve path props correctly."); + } + + context->getCanvas()->drawPath(*_path, *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _pathProp = container->defineProperty("path"); + _startProp = container->defineProperty("start"); + _endProp = container->defineProperty("end"); + _fillTypeProp = container->defineProperty("fillType"); + _strokeOptsProp = container->defineProperty("stroke"); + + _pathProp->require(); + } + +private: + float saturate(float x) { return std::max(0.0f, std::min(1.0f, x)); } + + SkPathFillType getFillTypeFromStringValue(const std::string &value) { + if (value == "winding") { + return SkPathFillType::kWinding; + } else if (value == "evenOdd") { + return SkPathFillType::kEvenOdd; + } else if (value == "inverseWinding") { + return SkPathFillType::kInverseWinding; + } else if (value == "inverseEvenOdd") { + return SkPathFillType::kInverseEvenOdd; + } + throw std::runtime_error("Could not convert value \"" + value + + "\" to path fill type."); + } + + PathProp *_pathProp; + NodeProp *_startProp; + NodeProp *_endProp; + NodeProp *_fillTypeProp; + NodeProp *_strokeOptsProp; + + std::shared_ptr _path; +}; + +class StrokeOptsProps : public BaseDerivedProp { +public: + explicit StrokeOptsProps(const std::function &onChange) + : BaseDerivedProp(onChange) { + _strokeProp = defineProperty("stroke"); + } + +private: + NodeProp *_strokeProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPictureNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPictureNode.h new file mode 100644 index 00000000000000..b2280c644de205 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPictureNode.h @@ -0,0 +1,31 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "PictureProp.h" + +#include + +namespace RNSkia { + +class JsiPictureNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiPictureNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skPicture") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawPicture(_pictureProp->getDerivedValue()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _pictureProp = container->defineProperty("picture"); + _pictureProp->require(); + } + +private: + PictureProp *_pictureProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPointsNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPointsNode.h new file mode 100644 index 00000000000000..25eb21c23da867 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiPointsNode.h @@ -0,0 +1,48 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "PointsProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkCanvas.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +static PropId PropNamePointsMode = JsiPropId::get("mode"); + +class JsiPointsNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiPointsNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skPoints") {} + +protected: + void draw(DrawingContext *context) override { + auto mode = _pointModeProp->getDerivedValue(); + auto points = _pointsProp->getDerivedValue(); + + context->getCanvas()->drawPoints(*mode, points->size(), points->data(), + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _pointModeProp = container->defineProperty("mode"); + _pointsProp = container->defineProperty("points"); + + _pointsProp->require(); + _pointModeProp->require(); + } + +private: + PointModeProp *_pointModeProp; + PointsProp *_pointsProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiRRectNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiRRectNode.h new file mode 100644 index 00000000000000..66f686bcbef800 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiRRectNode.h @@ -0,0 +1,33 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "RRectProp.h" + +#include + +namespace RNSkia { + +class JsiRRectNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiRRectNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skRRect") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawRRect(*_rrectProp->getDerivedValue(), + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + + _rrectProp = container->defineProperty("rect"); + _rrectProp->require(); + } + +private: + RRectProps *_rrectProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiRectNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiRectNode.h new file mode 100644 index 00000000000000..2bcb1b6295b58c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiRectNode.h @@ -0,0 +1,33 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "RectProp.h" + +#include + +namespace RNSkia { + +class JsiRectNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiRectNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skRect") {} + +protected: + void draw(DrawingContext *context) override { + context->getCanvas()->drawRect(*_rectProp->getDerivedValue(), + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + + _rectProp = container->defineProperty("rect"); + _rectProp->require(); + } + +private: + RectProps *_rectProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiShaderNodes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiShaderNodes.h new file mode 100644 index 00000000000000..6a4e3069d522ef --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiShaderNodes.h @@ -0,0 +1,463 @@ +#pragma once + +#include "JsiDomDeclarationNode.h" + +#include "BlendModeProp.h" +#include "ColorProp.h" +#include "NodeProp.h" +#include "NumbersProp.h" +#include "TileModeProp.h" +#include "TransformsProps.h" +#include "UniformsProp.h" + +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkShader.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class JsiShaderNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiShaderNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skShader", DeclarationType::Shader) {} + + void decorate(DeclarationContext *context) override { + decorateChildren(context); + auto source = _sourceProp->value().getAs(); + if (source == nullptr) { + throw std::runtime_error("Expected runtime effect when reading source " + "property of RuntimeEffectImageFilter."); + } + auto uniforms = + _uniformsProp->isSet() ? _uniformsProp->getDerivedValue() : nullptr; + + SkMatrix lm; + auto tm = + _transformProp->isSet() ? _transformProp->getDerivedValue() : nullptr; + + if (tm != nullptr) { + if (_originProp->isSet()) { + auto tr = _originProp->getDerivedValue(); + lm.preTranslate(tr->x(), tr->y()); + lm.preConcat(*tm); + lm.preTranslate(-tr->x(), -tr->y()); + } else { + lm.preConcat(*tm); + } + } + + // get all children that are shader nodes + auto children = context->getShaders()->popAll(); + + // Update shader + context->getShaders()->push(source->getObject()->makeShader( + uniforms, children.data(), children.size(), &lm)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _sourceProp = container->defineProperty("source"); + _uniformsProp = + container->defineProperty("uniforms", _sourceProp); + _transformProp = container->defineProperty("transform"); + _originProp = container->defineProperty("origin"); + + _sourceProp->require(); + } + +private: + NodeProp *_sourceProp; + UniformsProp *_uniformsProp; + TransformProp *_transformProp; + PointProp *_originProp; +}; + +class JsiImageShaderNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiImageShaderNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skImageShader", + DeclarationType::Shader) {} + + void decorate(DeclarationContext *context) override { + + auto image = _imageProps->getImage(); + if (image == nullptr) { + return; + } + + auto rect = _imageProps->getRect(); + auto lm = + _transformProp->isSet() ? _transformProp->getDerivedValue() : nullptr; + + if (rect != nullptr && lm != nullptr) { + auto rc = _imageProps->getDerivedValue(); + auto m3 = _imageProps->rect2rect(rc->src, rc->dst); + if (_transformProp->isChanged() || _imageProps->isChanged()) { + // To modify the matrix we need to copy it since we're not allowed to + // modify values contained in properties - this would have caused the + // matrix to be translated and scaled more and more for each render + // even thought the matrix prop did not change. + _matrix.reset(); + _matrix.preConcat(m3); + if (_originProp->isSet()) { + auto tr = _originProp->getDerivedValue(); + _matrix.preTranslate(tr->x(), tr->y()); + _matrix.preConcat(*lm); + _matrix.preTranslate(-tr->x(), -tr->y()); + } else { + _matrix.preConcat(*lm); + } + } + } + + context->getShaders()->push(image->makeShader( + *_txProp->getDerivedValue(), *_tyProp->getDerivedValue(), + SkSamplingOptions( + getFilterModeFromString(_filterModeProp->value().getAsString()), + getMipmapModeFromString(_mipmapModeProp->value().getAsString())), + &_matrix)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _txProp = container->defineProperty("tx"); + _tyProp = container->defineProperty("ty"); + _filterModeProp = container->defineProperty("fm"); + _mipmapModeProp = container->defineProperty("mm"); + + _imageProps = container->defineProperty(); + _transformProp = container->defineProperty("transform"); + _originProp = container->defineProperty("origin"); + + _txProp->require(); + _tyProp->require(); + _filterModeProp->require(); + _mipmapModeProp->require(); + + _transformProp->require(); + + // Add and require the image + container->defineProperty("image"); + } + +private: + SkFilterMode getFilterModeFromString(const std::string &value) { + if (value == "last") { + return SkFilterMode::kLast; + } else if (value == "linear") { + return SkFilterMode::kLinear; + } else if (value == "nearest") { + return SkFilterMode::kNearest; + } + throw std::runtime_error("The value \"" + value + + "\" is not a valid Filter Mode."); + } + + SkMipmapMode getMipmapModeFromString(const std::string &value) { + if (value == "last") { + return SkMipmapMode::kLast; + } else if (value == "last") { + return SkMipmapMode::kLast; + } else if (value == "last") { + return SkMipmapMode::kLast; + } else if (value == "none") { + return SkMipmapMode::kNone; + } + throw std::runtime_error("The value \"" + value + + "\" is not a valid Mipmap Mode."); + } + + SkMatrix _matrix; + + TileModeProp *_txProp; + TileModeProp *_tyProp; + NodeProp *_filterModeProp; + NodeProp *_mipmapModeProp; + ImageProps *_imageProps; + TransformProp *_transformProp; + PointProp *_originProp; +}; + +class JsiColorShaderNode : public JsiDomDeclarationNode, + public JsiDomNodeCtor { +public: + explicit JsiColorShaderNode(std::shared_ptr context) + : JsiDomDeclarationNode(context, "skColorShader", + DeclarationType::Shader) {} + + void decorate(DeclarationContext *context) override { + if (_colorProp->isSet()) { + context->getShaders()->push( + SkShaders::Color(*_colorProp->getDerivedValue())); + } + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _colorProp = container->defineProperty("color"); + _colorProp->require(); + } + +private: + ColorProp *_colorProp; +}; + +class JsiBasePerlinNoiseNode : public JsiDomDeclarationNode { +public: + JsiBasePerlinNoiseNode(std::shared_ptr context, + PropId type) + : JsiDomDeclarationNode(context, type, DeclarationType::Shader) {} + + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _freqXProp = container->defineProperty("freqX"); + _freqYProp = container->defineProperty("freqY"); + _octavesProp = container->defineProperty("octaves"); + _seedProp = container->defineProperty("seed"); + _tileWidthProp = container->defineProperty("tileWidth"); + _tileHeightProp = container->defineProperty("tileHeight"); + + _freqXProp->require(); + _freqYProp->require(); + _octavesProp->require(); + _seedProp->require(); + _tileWidthProp->require(); + _tileHeightProp->require(); + } + + NodeProp *_freqXProp; + NodeProp *_freqYProp; + NodeProp *_octavesProp; + NodeProp *_seedProp; + NodeProp *_tileWidthProp; + NodeProp *_tileHeightProp; +}; + +class JsiTurbulenceNode : public JsiBasePerlinNoiseNode, + public JsiDomNodeCtor { +public: + explicit JsiTurbulenceNode(std::shared_ptr context) + : JsiBasePerlinNoiseNode(context, "skTurbulence") {} + + void decorate(DeclarationContext *context) override { + + SkISize size = SkISize::Make(_tileWidthProp->value().getAsNumber(), + _tileHeightProp->value().getAsNumber()); + + context->getShaders()->push(SkPerlinNoiseShader::MakeTurbulence( + _freqXProp->value().getAsNumber(), _freqYProp->value().getAsNumber(), + _octavesProp->value().getAsNumber(), _seedProp->value().getAsNumber(), + &size)); + } +}; + +class JsiFractalNoiseNode : public JsiBasePerlinNoiseNode, + public JsiDomNodeCtor { +public: + explicit JsiFractalNoiseNode(std::shared_ptr context) + : JsiBasePerlinNoiseNode(context, "skFractalNoise") {} + + void decorate(DeclarationContext *context) override { + + SkISize size = SkISize::Make(_tileWidthProp->value().getAsNumber(), + _tileHeightProp->value().getAsNumber()); + + context->getShaders()->push(SkPerlinNoiseShader::MakeFractalNoise( + _freqXProp->value().getAsNumber(), _freqYProp->value().getAsNumber(), + _octavesProp->value().getAsNumber(), _seedProp->value().getAsNumber(), + &size)); + } +}; + +class JsiBaseGradientNode : public JsiDomDeclarationNode { +public: + JsiBaseGradientNode(std::shared_ptr context, PropId type) + : JsiDomDeclarationNode(context, type, DeclarationType::Shader) {} + + void decorate(DeclarationContext *context) override { + + _colors = _colorsProp->getDerivedValue()->data(); + _colorCount = static_cast(_colorsProp->getDerivedValue()->size()); + _flags = _flagsProp->isSet() ? _flagsProp->value().getAsNumber() : 0; + _mode = + _modeProp->isSet() ? *_modeProp->getDerivedValue() : SkTileMode::kClamp; + _positions = _positionsProp->isSet() + ? _positionsProp->getDerivedValue()->data() + : nullptr; + _matrix = _transformsProps->isSet() + ? _transformsProps->getDerivedValue().get() + : nullptr; + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiDomDeclarationNode::defineProperties(container); + _transformsProps = container->defineProperty(); + + _colorsProp = container->defineProperty("colors"); + _positionsProp = container->defineProperty("positions"); + _modeProp = container->defineProperty("mode"); + _flagsProp = container->defineProperty("flags"); + + _colorsProp->require(); + } + + const SkColor *_colors; + double _flags; + int _colorCount; + SkTileMode _mode; + const SkScalar *_positions; + const SkMatrix *_matrix; + +private: + TransformsProps *_transformsProps; + ColorsProp *_colorsProp; + NumbersProp *_positionsProp; + TileModeProp *_modeProp; + NodeProp *_flagsProp; +}; + +class JsiLinearGradientNode : public JsiBaseGradientNode, + public JsiDomNodeCtor { +public: + explicit JsiLinearGradientNode(std::shared_ptr context) + : JsiBaseGradientNode(context, "skLinearGradient") {} + + void decorate(DeclarationContext *context) override { + JsiBaseGradientNode::decorate(context); + + SkPoint pts[] = {*_startProp->getDerivedValue(), + *_endProp->getDerivedValue()}; + auto shader = SkGradientShader::MakeLinear( + pts, _colors, _positions, _colorCount, _mode, _flags, _matrix); + context->getShaders()->push(shader); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiBaseGradientNode::defineProperties(container); + _startProp = container->defineProperty("start"); + _endProp = container->defineProperty("end"); + + _startProp->require(); + _endProp->require(); + } + +private: + PointProp *_startProp; + PointProp *_endProp; +}; + +class JsiRadialGradientNode : public JsiBaseGradientNode, + public JsiDomNodeCtor { +public: + explicit JsiRadialGradientNode(std::shared_ptr context) + : JsiBaseGradientNode(context, "skRadialGradient") {} + + void decorate(DeclarationContext *context) override { + JsiBaseGradientNode::decorate(context); + + auto c = _centerProp->getDerivedValue(); + auto r = _radiusProp->value().getAsNumber(); + auto shader = SkGradientShader::MakeRadial( + *c, r, _colors, _positions, _colorCount, _mode, _flags, _matrix); + context->getShaders()->push(shader); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiBaseGradientNode::defineProperties(container); + _centerProp = container->defineProperty("c"); + _radiusProp = container->defineProperty("r"); + + _centerProp->require(); + _radiusProp->require(); + } + +private: + PointProp *_centerProp; + NodeProp *_radiusProp; +}; + +class JsiSweepGradientNode : public JsiBaseGradientNode, + public JsiDomNodeCtor { +public: + explicit JsiSweepGradientNode(std::shared_ptr context) + : JsiBaseGradientNode(context, "skSweepGradient") {} + + void decorate(DeclarationContext *context) override { + JsiBaseGradientNode::decorate(context); + + auto start = _startProp->isSet() ? _startProp->value().getAsNumber() : 0; + auto end = _endProp->isSet() ? _endProp->value().getAsNumber() : 360; + auto c = _centerProp->getDerivedValue(); + + context->getShaders()->push(SkGradientShader::MakeSweep( + c->x(), c->y(), _colors, _positions, _colorCount, _mode, start, end, + _flags, _matrix)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiBaseGradientNode::defineProperties(container); + _startProp = container->defineProperty("start"); + _endProp = container->defineProperty("end"); + _centerProp = container->defineProperty("c"); + } + +private: + PointProp *_centerProp; + NodeProp *_startProp; + NodeProp *_endProp; +}; + +class JsiTwoPointConicalGradientNode + : public JsiBaseGradientNode, + public JsiDomNodeCtor { +public: + explicit JsiTwoPointConicalGradientNode( + std::shared_ptr context) + : JsiBaseGradientNode(context, "skTwoPointConicalGradient") {} + + void decorate(DeclarationContext *context) override { + JsiBaseGradientNode::decorate(context); + + auto start = _startProp->getDerivedValue(); + auto end = _endProp->getDerivedValue(); + auto startR = _startRProp->value().getAsNumber(); + auto endR = _endRProp->value().getAsNumber(); + + context->getShaders()->push(SkGradientShader::MakeTwoPointConical( + *start, startR, *end, endR, _colors, _positions, _colorCount, _mode, + _flags, _matrix)); + } + +protected: + void defineProperties(NodePropsContainer *container) override { + JsiBaseGradientNode::defineProperties(container); + _startProp = container->defineProperty("start"); + _startRProp = container->defineProperty("startR"); + _endProp = container->defineProperty("end"); + _endRProp = container->defineProperty("endR"); + } + +private: + PointProp *_startProp; + NodeProp *_startRProp; + PointProp *_endProp; + NodeProp *_endRProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextBlobNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextBlobNode.h new file mode 100644 index 00000000000000..2a324a48259e79 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextBlobNode.h @@ -0,0 +1,44 @@ +#pragma once + +#include "JsiDomDrawingNode.h" + +#include "TextBlobProp.h" + +#include + +namespace RNSkia { + +class JsiTextBlobNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiTextBlobNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skTextBlob") {} + +protected: + void draw(DrawingContext *context) override { + auto blob = _textBlobProp->getDerivedValue(); + auto x = _xProp->value().getAsNumber(); + auto y = _yProp->value().getAsNumber(); + + context->getCanvas()->drawTextBlob(blob, x, y, *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + + _textBlobProp = container->defineProperty("blob"); + _xProp = container->defineProperty("x"); + _yProp = container->defineProperty("y"); + + _textBlobProp->require(); + _xProp->require(); + _yProp->require(); + } + +private: + TextBlobProp *_textBlobProp; + NodeProp *_xProp; + NodeProp *_yProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextNode.h new file mode 100644 index 00000000000000..71a26b81794007 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextNode.h @@ -0,0 +1,51 @@ +#pragma once + +#include "JsiDomDrawingNode.h" + +#include "FontProp.h" + +#include + +namespace RNSkia { + +class JsiTextNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiTextNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skText") {} + +protected: + void draw(DrawingContext *context) override { + auto text = _textProp->value().getAsString().c_str(); + auto x = _xProp->value().getAsNumber(); + auto y = _yProp->value().getAsNumber(); + auto font = _fontProp->getDerivedValue(); + + if (font != nullptr) { + context->getCanvas()->drawSimpleText(text, strlen(text), + SkTextEncoding::kUTF8, x, y, *font, + *context->getPaint()); + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + + _fontProp = container->defineProperty("font"); + _textProp = container->defineProperty("text"); + _xProp = container->defineProperty("x"); + _yProp = container->defineProperty("y"); + + _textProp->require(); + _xProp->require(); + _yProp->require(); + } + +private: + FontProp *_fontProp; + NodeProp *_textProp; + NodeProp *_xProp; + NodeProp *_yProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextPathNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextPathNode.h new file mode 100644 index 00000000000000..ec08389fbb934b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiTextPathNode.h @@ -0,0 +1,33 @@ +#pragma once + +#include "JsiDomDrawingNode.h" +#include "TextBlobProp.h" + +#include + +namespace RNSkia { + +class JsiTextPathNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiTextPathNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skTextPath") {} + +protected: + void draw(DrawingContext *context) override { + auto blob = _textBlobProp->getDerivedValue(); + if (blob != nullptr) { + context->getCanvas()->drawTextBlob(blob, 0, 0, *context->getPaint()); + } + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _textBlobProp = container->defineProperty(); + } + +private: + TextPathBlobProp *_textBlobProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiVerticesNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiVerticesNode.h new file mode 100644 index 00000000000000..fc9a69724bab1a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/nodes/JsiVerticesNode.h @@ -0,0 +1,41 @@ +#pragma once + +#include "JsiDomDrawingNode.h" + +#include "BlendModeProp.h" +#include "VerticesProps.h" + +#include + +namespace RNSkia { + +class JsiVerticesNode : public JsiDomDrawingNode, + public JsiDomNodeCtor { +public: + explicit JsiVerticesNode(std::shared_ptr context) + : JsiDomDrawingNode(context, "skVertices") {} + +protected: + void draw(DrawingContext *context) override { + SkBlendMode defaultBlendMode = _verticesProps->hasColors() + ? SkBlendMode::kDstOver + : SkBlendMode::kSrcOver; + context->getCanvas()->drawVertices(_verticesProps->getDerivedValue(), + _blendModeProp->isSet() + ? *_blendModeProp->getDerivedValue() + : defaultBlendMode, + *context->getPaint()); + } + + void defineProperties(NodePropsContainer *container) override { + JsiDomDrawingNode::defineProperties(container); + _verticesProps = container->defineProperty(); + _blendModeProp = container->defineProperty("blendMode"); + } + +private: + VerticesProps *_verticesProps; + BlendModeProp *_blendModeProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BezierProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BezierProps.h new file mode 100644 index 00000000000000..4829ebe4899177 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BezierProps.h @@ -0,0 +1,65 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkPicture.h" + +#include +#include +#include + +namespace RNSkia { + +class BezierProp : public DerivedProp> { +public: + explicit BezierProp(PropId name, + const std::function &onChange) + : DerivedProp>(onChange) { + _bezierProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_bezierProp->value().getType() == PropType::Array) { + // Patch requires a path with the following constraints: + // M tl + // C c1 c2 br + // C c1 c2 bl + // C c1 c2 tl (the redundant point in the last command is removed) + auto arr = _bezierProp->value().getAsArray(); + std::vector points; + points.reserve(12); + + points.push_back( + PointProp::processValue(arr[0].getValue(JsiPropId::get("pos")))); + points.push_back( + PointProp::processValue(arr[0].getValue(JsiPropId::get("c2")))); + points.push_back( + PointProp::processValue(arr[1].getValue(JsiPropId::get("c1")))); + points.push_back( + PointProp::processValue(arr[1].getValue(JsiPropId::get("pos")))); + points.push_back( + PointProp::processValue(arr[1].getValue(JsiPropId::get("c2")))); + points.push_back( + PointProp::processValue(arr[2].getValue(JsiPropId::get("c1")))); + points.push_back( + PointProp::processValue(arr[2].getValue(JsiPropId::get("pos")))); + points.push_back( + PointProp::processValue(arr[2].getValue(JsiPropId::get("c2")))); + points.push_back( + PointProp::processValue(arr[3].getValue(JsiPropId::get("c1")))); + points.push_back( + PointProp::processValue(arr[3].getValue(JsiPropId::get("pos")))); + points.push_back( + PointProp::processValue(arr[3].getValue(JsiPropId::get("c2")))); + points.push_back( + PointProp::processValue(arr[0].getValue(JsiPropId::get("c1")))); + + setDerivedValue(std::move(points)); + } + } + +private: + NodeProp *_bezierProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BlendModeProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BlendModeProp.h new file mode 100644 index 00000000000000..6b95b5e72ce7b7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BlendModeProp.h @@ -0,0 +1,103 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkBlendMode.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class BlendModeProp : public DerivedProp { +public: + explicit BlendModeProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _blendMode = defineProperty(name); + } + + void updateDerivedValue() override { + if (_blendMode->isSet() && (_blendMode->isChanged())) { + auto blendModeValue = _blendMode->value().getAsString(); + setDerivedValue(getBlendModeFromString(blendModeValue)); + } + } + +private: + SkBlendMode getBlendModeFromString(const std::string &value) { + if (value == "clear") { + return SkBlendMode::kClear; + } else if (value == "src") { + return SkBlendMode::kSrc; + } else if (value == "dst") { + return SkBlendMode::kDst; + } else if (value == "srcOver") { + return SkBlendMode::kSrcOver; + } else if (value == "dstOver") { + return SkBlendMode::kDstOver; + } else if (value == "srcIn") { + return SkBlendMode::kSrcIn; + } else if (value == "dstIn") { + return SkBlendMode::kDstIn; + } else if (value == "srcOut") { + return SkBlendMode::kSrcOut; + } else if (value == "dstOut") { + return SkBlendMode::kDstOut; + } else if (value == "srcATop") { + return SkBlendMode::kSrcATop; + } else if (value == "dstATop") { + return SkBlendMode::kDstATop; + } else if (value == "xor") { + return SkBlendMode::kXor; + } else if (value == "plus") { + return SkBlendMode::kPlus; + } else if (value == "modulate") { + return SkBlendMode::kModulate; + } else if (value == "screen") { + return SkBlendMode::kScreen; + } else if (value == "overlay") { + return SkBlendMode::kOverlay; + } else if (value == "darken") { + return SkBlendMode::kDarken; + } else if (value == "lighten") { + return SkBlendMode::kLighten; + } else if (value == "colorDodge") { + return SkBlendMode::kColorDodge; + } else if (value == "colorBurn") { + return SkBlendMode::kColorBurn; + } else if (value == "hardLight") { + return SkBlendMode::kHardLight; + } else if (value == "softLight") { + return SkBlendMode::kSoftLight; + } else if (value == "difference") { + return SkBlendMode::kDifference; + } else if (value == "exclusion") { + return SkBlendMode::kExclusion; + } else if (value == "multiply") { + return SkBlendMode::kMultiply; + } else if (value == "hue") { + return SkBlendMode::kHue; + } else if (value == "saturation") { + return SkBlendMode::kSaturation; + } else if (value == "color") { + return SkBlendMode::kColor; + } else if (value == "luminosity") { + return SkBlendMode::kLuminosity; + } + + throw std::runtime_error("Property value \"" + value + + "\" is not a legal blend mode."); + } + + NodeProp *_blendMode; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BoxShadowProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BoxShadowProps.h new file mode 100644 index 00000000000000..fa43c8613df08a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/BoxShadowProps.h @@ -0,0 +1,62 @@ +#pragma once + +#include "NodeProp.h" + +#include +#include + +#include "SkBlurTypes.h" + +namespace RNSkia { + +class BoxShadowProps : public DerivedProp { +public: + explicit BoxShadowProps(const std::function &onChange) + : DerivedProp(onChange) { + _dxProp = defineProperty("dx"); + _dyProp = defineProperty("dy"); + _spreadProp = defineProperty("spread"); + _blurProp = defineProperty("blur"); + _colorProp = defineProperty("color"); + _innerProp = defineProperty("inner"); + + _blurProp->require(); + } + + void updateDerivedValue() override { + SkColor color = + _colorProp->isSet() ? *_colorProp->getDerivedValue() : SK_ColorBLACK; + SkScalar blur = _blurProp->value().getAsNumber(); + + auto paint = SkPaint(); + paint.setAntiAlias(true); + paint.setColor(color); + auto filter = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, blur, true); + paint.setMaskFilter(filter); + + setDerivedValue(std::move(paint)); + } + + bool isInner() { + return _innerProp->isSet() ? _innerProp->value().getAsBool() : false; + } + SkScalar getDx() { + return _dxProp->isSet() ? _dxProp->value().getAsNumber() : 0; + } + SkScalar getDy() { + return _dyProp->isSet() ? _dyProp->value().getAsNumber() : 0; + } + SkScalar getSpread() { + return _spreadProp->isSet() ? _spreadProp->value().getAsNumber() : 0; + } + +private: + NodeProp *_dxProp; + NodeProp *_dyProp; + NodeProp *_spreadProp; + NodeProp *_blurProp; + ColorProp *_colorProp; + NodeProp *_innerProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/CircleProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/CircleProp.h new file mode 100644 index 00000000000000..bdbdf596078811 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/CircleProp.h @@ -0,0 +1,49 @@ +#pragma once + +#include "NodeProp.h" +#include "PointProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPoint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +static PropId PropNameCx = JsiPropId::get("cx"); +static PropId PropNameCy = JsiPropId::get("cy"); +static PropId PropNameC = JsiPropId::get("c"); + +class CircleProp : public DerivedProp { +public: + explicit CircleProp(const std::function &onChange) + : DerivedProp(onChange) { + _c = defineProperty("c"); + _cx = defineProperty("cx"); + _cy = defineProperty("cy"); + } + + void updateDerivedValue() override { + // Read in this order since point with x:0/y:0 is default for + // the c property. + if (_cx->isSet() && _cy->isSet()) { + setDerivedValue(SkPoint::Make(_cx->value().getAsNumber(), + _cy->value().getAsNumber())); + } else if (_c->isSet()) { + setDerivedValue(_c->getUnsafeDerivedValue()); + } else { + setDerivedValue(SkPoint::Make(0.0, 0.0)); + } + } + +private: + PointProp *_c; + NodeProp *_cx; + NodeProp *_cy; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ClipProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ClipProp.h new file mode 100644 index 00000000000000..d7e88061029428 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ClipProp.h @@ -0,0 +1,57 @@ +#pragma once + +#include "NodeProp.h" + +#include "PathProp.h" +#include "RRectProp.h" +#include "RectProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPath.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class ClipProp : public BaseDerivedProp { +public: + explicit ClipProp(PropId name, + const std::function &onChange) + : BaseDerivedProp(onChange) { + _clipProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_clipProp->isSet()) { + auto value = _clipProp->value(); + _rect = RectProp::processRect(value); + _rrect = nullptr; + _path = nullptr; + if (!_rect) { + _path = PathProp::processPath(value); + if (!_path) { + _rrect = RRectProp::processRRect(value); + } + } + } + } + + bool isSet() override { return _clipProp->isSet(); } + + const SkPath *getPath() { return _path.get(); } + const SkRect *getRect() { return _rect.get(); } + const SkRRect *getRRect() { return _rrect.get(); } + +private: + NodeProp *_clipProp; + + std::shared_ptr _path; + std::shared_ptr _rect; + std::shared_ptr _rrect; +}; + +} // namespace RNSkia \ No newline at end of file diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ColorProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ColorProp.h new file mode 100644 index 00000000000000..4a391fad654264 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ColorProp.h @@ -0,0 +1,96 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "third_party/CSSColorParser.h" + +#include +#include +#include + +namespace RNSkia { + +static PropId PropName0 = JsiPropId::get("0"); +static PropId PropName1 = JsiPropId::get("1"); +static PropId PropName2 = JsiPropId::get("2"); +static PropId PropName3 = JsiPropId::get("3"); + +class ColorProp : public DerivedProp { +public: + explicit ColorProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _colorProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_colorProp->isSet()) { + // Color might be a number, a string or a Float32Array of rgba values + setDerivedValue( + std::make_shared(parseColorValue(_colorProp->value()))); + } else { + setDerivedValue(nullptr); + } + } + + static SkColor parseColorValue(const JsiValue &color) { + if (color.getType() == PropType::Object) { + // Float array + auto r = color.getValue(PropName0); + auto g = color.getValue(PropName1); + auto b = color.getValue(PropName2); + auto a = color.getValue(PropName3); + return SkColorSetARGB(a.getAsNumber() * 255.0f, r.getAsNumber() * 255.0f, + g.getAsNumber() * 255.0f, b.getAsNumber() * 255.0f); + + } else if (color.getType() == PropType::Array) { + auto r = color.getAsArray().at(0); + auto g = color.getAsArray().at(1); + auto b = color.getAsArray().at(2); + auto a = color.getAsArray().at(3); + return SkColorSetARGB(a.getAsNumber() * 255.0f, r.getAsNumber() * 255.0f, + g.getAsNumber() * 255.0f, b.getAsNumber() * 255.0f); + } else if (color.getType() == PropType::Number) { + return static_cast(color.getAsNumber()); + } else { + auto parsedColor = CSSColorParser::parse(color.getAsString()); + if (parsedColor.a == -1.0f) { + return SK_ColorBLACK; + } else { + return SkColorSetARGB(parsedColor.a * 255, parsedColor.r, parsedColor.g, + parsedColor.b); + } + } + } + +private: + NodeProp *_colorProp; +}; + +class ColorsProp : public DerivedProp> { +public: + explicit ColorsProp(PropId name, + const std::function &onChange) + : DerivedProp>(onChange) { + _colorsProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_colorsProp->isSet()) { + auto colors = _colorsProp->value().getAsArray(); + std::vector derivedColors; + derivedColors.reserve(colors.size()); + + for (size_t i = 0; i < colors.size(); ++i) { + derivedColors.push_back(ColorProp::parseColorValue(colors[i])); + } + setDerivedValue(std::move(derivedColors)); + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_colorsProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/DrawingProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/DrawingProp.h new file mode 100644 index 00000000000000..bfd6e756827e2c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/DrawingProp.h @@ -0,0 +1,35 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkFont.h" + +#include + +namespace RNSkia { + +using NotifyNeedRenderCallback = + std::function; + +class DrawingProp : public DerivedSkProp { +public: + DrawingProp(PropId name, NotifyNeedRenderCallback notifyPictureNeeded, + const std::function &onChange) + : _notifyPictureNeeded(notifyPictureNeeded), DerivedSkProp( + onChange) { + _drawingProp = defineProperty(name); + } + + void updateDerivedValue() override { + auto drawingFunc = _drawingProp->value().getAsFunction(); + _notifyPictureNeeded(drawingFunc); + } + + void setPicture(sk_sp picture) { setDerivedValue(picture); } + +private: + NodeProp *_drawingProp; + NotifyNeedRenderCallback _notifyPictureNeeded; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/FontProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/FontProp.h new file mode 100644 index 00000000000000..72af25df73eb71 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/FontProp.h @@ -0,0 +1,42 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkFont.h" + +#include + +namespace RNSkia { + +class FontProp : public DerivedProp { +public: + explicit FontProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _fontProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_fontProp->isSet()) { + if (_fontProp->value().getType() == PropType::HostObject) { + auto ptr = _fontProp->value().getAs(); + if (ptr == nullptr) { + throw std::runtime_error( + "Expected SkFont object for the Font property."); + } + setDerivedValue(ptr->getObject()); + + } else { + throw std::runtime_error( + "Expected SkFont object or null/undefined for the Font property."); + } + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_fontProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/GlyphsProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/GlyphsProp.h new file mode 100644 index 00000000000000..414f4f6ff683cd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/GlyphsProp.h @@ -0,0 +1,55 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "PointProp.h" + +#include +#include +#include + +namespace RNSkia { + +static PropId PropNamePos = JsiPropId::get("pos"); +static PropId PropNameId = JsiPropId::get("id"); + +struct GlyphInfo { + std::vector glyphIds; + std::vector positions; +}; + +class GlyphsProp : public DerivedProp { +public: + explicit GlyphsProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _glyphsProp = defineProperty(name); + } + + void updateDerivedValue() override { + auto arr = _glyphsProp->value().getAsArray(); + + GlyphInfo glyphInfo; + + std::vector glyphIds; + std::vector positions; + + glyphIds.reserve(arr.size()); + positions.reserve(arr.size()); + + for (size_t i = 0; i < arr.size(); ++i) { + auto obj = arr[i]; + auto pos = PointProp::processValue(obj.getValue(PropNamePos)); + auto identifier = + static_cast(obj.getValue(PropNameId).getAsNumber()); + glyphInfo.positions.push_back(pos); + glyphInfo.glyphIds.push_back(identifier); + } + + setDerivedValue(std::move(glyphInfo)); + } + +private: + NodeProp *_glyphsProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ImageProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ImageProps.h new file mode 100644 index 00000000000000..bc2cfdf6d1fbb2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/ImageProps.h @@ -0,0 +1,196 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkImage.h" + +#include +#include +#include + +namespace RNSkia { + +struct FitSizes { + SkSize src; + SkSize dst; +}; + +struct FitRects { + SkRect src; + SkRect dst; +}; + +static PropId PropNameImage = JsiPropId::get("image"); +static PropId PropNameFit = JsiPropId::get("fit"); + +class ImageProp : public DerivedSkProp { +public: + explicit ImageProp(PropId name, + const std::function &onChange) + : DerivedSkProp(onChange) { + _imageProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_imageProp->isSet()) { + // Check for host object + if (_imageProp->value().getType() == PropType::HostObject) { + // This should be an SkImage wrapper: + auto ptr = std::dynamic_pointer_cast( + _imageProp->value().getAsHostObject()); + if (ptr == nullptr) { + // If not - throw an exception + throw std::runtime_error("Expected SkImage object for the " + + std::string(getName()) + + " property. Got a " + + _imageProp->value().getTypeAsString( + _imageProp->value().getType()) + + "."); + } + setDerivedValue(ptr->getObject()); + } else { + // Should be a host object if set + throw std::runtime_error( + "Expected SkImage object or null/undefined for the " + + std::string(getName()) + " property."); + } + } else { + // Set to null + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_imageProp; +}; + +class ImageProps : public DerivedProp { +public: + explicit ImageProps(const std::function &onChange) + : DerivedProp(onChange) { + _fitProp = defineProperty(PropNameFit); + _imageProp = defineProperty(PropNameImage); + _rectProp = defineProperty(PropNameRect); + } + + void updateDerivedValue() override { + auto image = _imageProp->getDerivedValue(); + if (image == nullptr) { + setDerivedValue(nullptr); + return; + } + + auto imageRect = SkRect::MakeXYWH(0, 0, image->width(), image->height()); + + auto rect = _rectProp->getDerivedValue() ? *_rectProp->getDerivedValue() + : imageRect; + auto fit = _fitProp->isSet() ? _fitProp->value().getAsString() : "contain"; + + setDerivedValue(fitRects(fit, imageRect, rect)); + } + + sk_sp getImage() { return _imageProp->getDerivedValue(); } + + std::shared_ptr getRect() { + return _rectProp->getDerivedValue(); + } + + SkMatrix rect2rect(SkRect src, SkRect dst) { + auto sx = dst.width() / src.width(); + auto sy = dst.height() / src.height(); + auto tx = dst.x() - src.x() * sx; + auto ty = dst.y() - src.y() * sy; + SkMatrix m3; + m3.preTranslate(tx, ty); + m3.preScale(sx, sy); + return m3; + } + +private: + SkSize size(double width, double height) { + return SkSize::Make(width, height); + } + + FitRects fitRects(const std::string &fit, SkRect rect, SkRect rect2) { + auto sizes = applyBoxFit(fit, size(rect.width(), rect.height()), + size(rect2.width(), rect2.height())); + + auto src = inscribe(sizes.src, rect); + auto dst = inscribe(sizes.dst, rect2); + + return {.src = src, .dst = dst}; + } + + SkRect inscribe(SkSize size, SkRect rect) { + auto halfWidthDelta = (rect.width() - size.width()) / 2.0; + auto halfHeightDelta = (rect.height() - size.height()) / 2.0; + return SkRect::MakeXYWH(rect.x() + halfWidthDelta, + rect.y() + halfHeightDelta, size.width(), + size.height()); + } + + FitSizes applyBoxFit(const std::string fit, SkSize input, SkSize output) { + SkSize src = size(0, 0); + SkSize dst = size(0, 0); + + if (input.height() <= 0.0 || input.width() <= 0.0 || + output.height() <= 0.0 || output.width() <= 0.0) { + return {.src = src, .dst = dst}; + } + + if (fit == "fill") { + src = input; + dst = output; + } else if (fit == "contain") { + src = input; + if (output.width() / output.height() > src.width() / src.height()) { + dst = size((src.width() * output.height()) / src.height(), + output.height()); + } else { + dst = + size(output.width(), (src.height() * output.width()) / src.width()); + } + } else if (fit == "cover") { + if (output.width() / output.height() > input.width() / input.height()) { + src = size(input.width(), + (input.width() * output.height()) / output.width()); + } else { + src = size((input.height() * output.width()) / output.height(), + input.height()); + } + dst = output; + } else if (fit == "fitWidth") { + src = size(input.width(), + (input.width() * output.height()) / output.width()); + dst = size(output.width(), (src.height() * output.width()) / src.width()); + } else if (fit == "fitHeight") { + src = size((input.height() * output.width()) / output.height(), + input.height()); + dst = + size((src.width() * output.height()) / src.height(), output.height()); + } else if (fit == "none") { + src = size(std::min(input.width(), output.width()), + std::min(input.height(), output.height())); + dst = src; + } else if (fit == "scaleDown") { + src = input; + dst = input; + auto aspectRatio = input.width() / input.height(); + if (dst.height() > output.height()) { + dst = size(output.height() * aspectRatio, output.height()); + } + if (dst.width() > output.width()) { + dst = size(output.width(), output.width() / aspectRatio); + } + } else { + throw std::runtime_error("The value \"" + fit + + "\" is not a valid fit value."); + } + return {.src = src, .dst = dst}; + } + + NodeProp *_fitProp; + ImageProp *_imageProp; + RectProps *_rectProp; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/LayerProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/LayerProp.h new file mode 100644 index 00000000000000..ad013082d380ae --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/LayerProp.h @@ -0,0 +1,52 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "PaintProps.h" + +#include + +namespace RNSkia { + +class LayerProp : public DerivedProp { +public: + explicit LayerProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _layerPaintProp = defineProperty(name); + _layerBoolProp = defineProperty(name); + } + + /** + Returns true if is optional and one of the child props has a value, or all + props if optional is false. + */ + bool isSet() override { return DerivedProp::isSet() || _isBool; }; + + void updateDerivedValue() override { + if (_layerBoolProp->isSet() && + _layerBoolProp->value().getType() == PropType::Bool) { + _isBool = true; + setDerivedValue(nullptr); + return; + } + + if (_layerPaintProp->isSet()) { + // We have a paint object for the layer property + setDerivedValue(_layerPaintProp->getUnsafeDerivedValue()); + _isBool = false; + } else { + _isBool = false; + setDerivedValue(nullptr); + } + } + + bool isBool() { return _isBool; } + +private: + PaintProp *_layerPaintProp; + NodeProp *_layerBoolProp; + std::atomic _isBool; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/MatrixProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/MatrixProp.h new file mode 100644 index 00000000000000..f3d8b59d9f8090 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/MatrixProp.h @@ -0,0 +1,35 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "JsiSkMatrix.h" + +#include + +namespace RNSkia { + +static PropId PropNameMatrix = JsiPropId::get("matrix"); + +class MatrixProp : public DerivedProp { +public: + explicit MatrixProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _matrixProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_matrixProp->isSet() && + _matrixProp->value().getType() == PropType::HostObject) { + // Try reading as SkMatrix + auto matrix = _matrixProp->value().getAs(); + if (matrix != nullptr) { + setDerivedValue(matrix->getObject()); + } + } + } + +private: + NodeProp *_matrixProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/NumbersProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/NumbersProp.h new file mode 100644 index 00000000000000..90f2863d0bc70f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/NumbersProp.h @@ -0,0 +1,67 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include +#include +#include +#include + +namespace RNSkia { + +class NumbersProp : public DerivedProp> { +public: + explicit NumbersProp(PropId name, + const std::function &onChange) + : DerivedProp>(onChange) { + _positionProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_positionProp->isSet()) { + auto positions = _positionProp->value().getAsArray(); + std::vector derivedPositions; + derivedPositions.reserve(positions.size()); + + for (size_t i = 0; i < positions.size(); ++i) { + derivedPositions.push_back(positions[i].getAsNumber()); + } + setDerivedValue(std::move(derivedPositions)); + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_positionProp; +}; + +class Numbers16Prop : public DerivedProp> { +public: + explicit Numbers16Prop(PropId name, + const std::function &onChange) + : DerivedProp>(onChange) { + _prop = defineProperty(name); + } + + void updateDerivedValue() override { + if (_prop->isSet()) { + auto positions = _prop->value().getAsArray(); + std::vector derivedPositions; + derivedPositions.reserve(positions.size()); + + for (size_t i = 0; i < positions.size(); ++i) { + derivedPositions.push_back( + static_cast(positions[i].getAsNumber())); + } + setDerivedValue(std::move(derivedPositions)); + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_prop; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PaintProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PaintProps.h new file mode 100644 index 00000000000000..f131b6a7149f73 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PaintProps.h @@ -0,0 +1,130 @@ +#pragma once + +#include "BlendModeProp.h" +#include "ColorProp.h" +#include "NodeProp.h" +#include "StrokeProps.h" + +#include "JsiSkPaint.h" +#include "third_party/CSSColorParser.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPaint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class PaintProp : public DerivedProp { +public: + explicit PaintProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _paintProp = defineProperty(name); + } + + explicit PaintProp(const std::function &onChange) + : PaintProp(JsiPropId::get("paint"), onChange) {} + + void updateDerivedValue() override { + if (_paintProp->isSet()) { + if (_paintProp->value().getType() == PropType::HostObject) { + // Read paint property as Host Object - JsiSkPaint + auto ptr = _paintProp->value().getAs(); + if (ptr != nullptr) { + setDerivedValue(ptr->getObject()); + } else { + throw std::runtime_error("Expected SkPaint object, got unknown " + "object when reading paint property."); + } + } else { + setDerivedValue(nullptr); + } + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_paintProp; +}; + +class PaintDrawingContextProp : public DerivedProp { +public: + explicit PaintDrawingContextProp( + PropId name, const std::function &onChange) + : DerivedProp(onChange) { + _paintProp = defineProperty(name); + } + + explicit PaintDrawingContextProp( + const std::function &onChange) + : PaintDrawingContextProp(JsiPropId::get("paint"), onChange) {} + + void updateDerivedValue() override { + if (_paintProp->isSet()) { + if (_paintProp->value().getType() == PropType::HostObject) { + // Read paint property as Host Object - JsiSkPaint + auto ptr = _paintProp->value().getAs(); + if (ptr != nullptr) { + setDerivedValue(std::make_shared(ptr->getObject())); + } else { + throw std::runtime_error("Expected SkPaint object, got unknown " + "object when reading paint property."); + } + } else { + setDerivedValue(nullptr); + } + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_paintProp; +}; + +class PaintProps : public BaseDerivedProp { +public: + explicit PaintProps(const std::function &onChange) + : BaseDerivedProp(onChange) { + _color = defineProperty("color"); + _style = defineProperty("style"); + _strokeWidth = defineProperty("strokeWidth"); + _blendMode = defineProperty("blendMode"); + _strokeJoin = defineProperty("strokeJoin"); + _strokeCap = defineProperty("strokeCap"); + _strokeMiter = defineProperty("strokeMiter"); + _antiAlias = defineProperty("antiAlias"); + _opacity = defineProperty("opacity"); + } + + void updateDerivedValue() override {} + + ColorProp *getColor() { return _color; } + NodeProp *getStyle() { return _style; } + NodeProp *getStrokeWidth() { return _strokeWidth; } + BlendModeProp *getBlendMode() { return _blendMode; } + StrokeJoinProp *getStrokeJoin() { return _strokeJoin; } + StrokeCapProp *getStrokeCap() { return _strokeCap; } + NodeProp *getStrokeMiter() { return _strokeMiter; } + NodeProp *getAntiAlias() { return _antiAlias; } + NodeProp *getOpacity() { return _opacity; } + +private: + ColorProp *_color; + NodeProp *_style; + NodeProp *_strokeWidth; + BlendModeProp *_blendMode; + StrokeJoinProp *_strokeJoin; + StrokeCapProp *_strokeCap; + NodeProp *_strokeMiter; + NodeProp *_antiAlias; + NodeProp *_opacity; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PathProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PathProp.h new file mode 100644 index 00000000000000..b4b0860fe39cd6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PathProp.h @@ -0,0 +1,59 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "JsiSkPath.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPath.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class PathProp : public DerivedProp { +public: + explicit PathProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _pathProp = defineProperty(name); + } + + static std::shared_ptr processPath(const JsiValue &value) { + if (value.getType() == PropType::HostObject) { + // Try reading as Path + auto ptr = std::dynamic_pointer_cast(value.getAsHostObject()); + if (ptr != nullptr) { + return ptr->getObject(); + } + } else if (value.getType() == PropType::String) { + // Read as string + auto pathString = value.getAsString(); + SkPath result; + + if (SkParsePath::FromSVGString(pathString.c_str(), &result)) { + return std::make_shared(result); + } else { + throw std::runtime_error("Could not parse path from string."); + } + } + return nullptr; + } + + void updateDerivedValue() override { + if (!_pathProp->isSet()) { + setDerivedValue(nullptr); + return; + } + auto value = _pathProp->value(); + setDerivedValue(PathProp::processPath(value)); + } + +private: + NodeProp *_pathProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PictureProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PictureProp.h new file mode 100644 index 00000000000000..e63f8f31c235f9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PictureProp.h @@ -0,0 +1,40 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkPicture.h" + +#include +#include + +namespace RNSkia { + +class PictureProp : public DerivedSkProp { +public: + explicit PictureProp(PropId name, + const std::function &onChange) + : DerivedSkProp(onChange) { + _pictureProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_pictureProp->value().getType() != PropType::HostObject) { + throw std::runtime_error("Expected SkPicture object for the " + + std::string(getName()) + " property."); + } + + auto ptr = std::dynamic_pointer_cast( + _pictureProp->value().getAsHostObject()); + if (ptr == nullptr) { + throw std::runtime_error("Expected SkPicture object for the " + + std::string(getName()) + " property."); + } + + setDerivedValue(ptr->getObject()); + } + +private: + NodeProp *_pictureProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PointProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PointProp.h new file mode 100644 index 00000000000000..c6f3f5ba2a1458 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PointProp.h @@ -0,0 +1,65 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "JsiSkPoint.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPoint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +static PropId PropNameX = JsiPropId::get("x"); +static PropId PropNameY = JsiPropId::get("y"); + +class PointProp : public DerivedProp { +public: + explicit PointProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _pointProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_pointProp->isSet()) { + // Check for JsiSkRect and JsiSkPoint + setDerivedValue(processValue(_pointProp->value())); + } else { + setDerivedValue(nullptr); + } + } + + static SkPoint processValue(const JsiValue &value) { + if (value.getType() == PropType::HostObject) { + // Try reading as point + auto ptr = std::dynamic_pointer_cast(value.getAsHostObject()); + if (ptr != nullptr) { + return SkPoint::Make(ptr->getObject()->x(), ptr->getObject()->y()); + } else { + // Try reading as rect + auto ptr = + std::dynamic_pointer_cast(value.getAsHostObject()); + if (ptr != nullptr) { + return SkPoint::Make(ptr->getObject()->x(), ptr->getObject()->y()); + } + } + } else if (value.getType() == PropType::Object && + value.hasValue(PropNameX) && value.hasValue(PropNameY)) { + auto x = value.getValue(PropNameX); + auto y = value.getValue(PropNameY); + return SkPoint::Make(x.getAsNumber(), y.getAsNumber()); + } + throw std::runtime_error("Expected point value."); + } + +private: + NodeProp *_pointProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PointsProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PointsProp.h new file mode 100644 index 00000000000000..c45b938fc1fb28 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/PointsProp.h @@ -0,0 +1,81 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "JsiSkPoint.h" + +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPoint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class PointModeProp : public DerivedProp { +public: + explicit PointModeProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _pointModeProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_pointModeProp->isSet()) { + setDerivedValue( + getPointModeFromStringValue(_pointModeProp->value().getAsString())); + } else { + setDerivedValue(nullptr); + } + } + +private: + static SkCanvas::PointMode + getPointModeFromStringValue(const std::string &value) { + if (value == "points") { + return SkCanvas::PointMode::kPoints_PointMode; + } else if (value == "lines") { + return SkCanvas::PointMode::kLines_PointMode; + } else if (value == "polygon") { + return SkCanvas::PointMode::kPolygon_PointMode; + } + throw std::runtime_error( + "Expected valid point mode for Points node, got \"" + value + "\"."); + } + + NodeProp *_pointModeProp; +}; + +class PointsProp : public DerivedProp> { +public: + explicit PointsProp(PropId name, + const std::function &onChange) + : DerivedProp>(onChange) { + _pointsProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_pointsProp->isSet()) { + auto pointsArray = _pointsProp->value().getAsArray(); + std::vector points; + points.reserve(pointsArray.size()); + for (size_t i = 0; i < pointsArray.size(); ++i) { + auto p = pointsArray[i]; + points.push_back(PointProp::processValue(p)); + } + setDerivedValue(std::move(points)); + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_pointsProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RRectProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RRectProp.h new file mode 100644 index 00000000000000..e38fbcd9bfaf48 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RRectProp.h @@ -0,0 +1,172 @@ +#pragma once + +#include "JsiSkRRect.h" +#include "NodeProp.h" +#include "RectProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRRect.h" +#include "SkRect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +static PropId PropNameRx = JsiPropId::get("rx"); +static PropId PropNameRy = JsiPropId::get("ry"); +static PropId PropNameR = JsiPropId::get("r"); + +/** + Reads a rect from a given propety in the node. The name of the property is + provided on the constructor. The property can either be a Javascript property + or a host object representing an SkRect. + */ +class RRectProp : public DerivedProp { +public: + explicit RRectProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _prop = defineProperty(name); + } + + static std::shared_ptr processRRect(const JsiValue &value) { + if (value.getType() == PropType::HostObject) { + // Try reading as rect + auto rectPtr = + std::dynamic_pointer_cast(value.getAsHostObject()); + if (rectPtr != nullptr) { + auto rrect = rectPtr->getObject(); + return std::make_shared( + SkRRect::MakeRectXY(rrect->rect(), rrect->getSimpleRadii().x(), + rrect->getSimpleRadii().y())); + } + } else { + if (value.getType() == PropType::Object) { + if (value.hasValue(PropNameRect) && value.hasValue(PropNameRx) && + value.hasValue(PropNameRy)) { + auto rect = value.getValue(PropNameRect); + if (rect.hasValue(PropNameX) && rect.hasValue(PropNameY) && + rect.hasValue(PropNameWidth) && rect.hasValue(PropNameHeight)) { + auto x = rect.getValue(PropNameX); + auto y = rect.getValue(PropNameY); + auto width = rect.getValue(PropNameWidth); + auto height = rect.getValue(PropNameHeight); + auto rx = value.getValue(PropNameRx); + auto ry = value.getValue(PropNameRy); + + // Update cache from js object value + return std::make_shared(SkRRect::MakeRectXY( + SkRect::MakeXYWH(x.getAsNumber(), y.getAsNumber(), + width.getAsNumber(), height.getAsNumber()), + rx.getAsNumber(), ry.getAsNumber())); + } + } + } + } + return nullptr; + } + + void updateDerivedValue() override { + if (_prop->isSet()) { + auto value = _prop->value(); + setDerivedValue(RRectProp::processRRect(value)); + } + } + +private: + NodeProp *_prop; +}; + +/** + Reads rect properties from a node's properties + */ +class RRectPropFromProps : public DerivedProp { +public: + explicit RRectPropFromProps( + const std::function &onChange) + : DerivedProp(onChange) { + _x = defineProperty(PropNameX); + _y = defineProperty(PropNameY); + _width = defineProperty(PropNameWidth); + _height = defineProperty(PropNameHeight); + _r = defineProperty(PropNameR); + } + + void updateDerivedValue() override { + if (_x->isSet() && _y->isSet() && _width->isSet() && _height->isSet() && + _r->isSet()) { + setDerivedValue(SkRRect::MakeRectXY( + SkRect::MakeXYWH(_x->value().getAsNumber(), _y->value().getAsNumber(), + _width->value().getAsNumber(), + _height->value().getAsNumber()), + _r->value().getAsNumber(), _r->value().getAsNumber())); + } + } + +private: + NodeProp *_x; + NodeProp *_y; + NodeProp *_width; + NodeProp *_height; + NodeProp *_r; +}; + +/** + Reads rect props from either a given property or from the property object + itself. + */ +class RRectProps : public DerivedProp { +public: + explicit RRectProps(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _rectProp = defineProperty(name); + _rectPropFromProps = defineProperty(); + } + + void updateDerivedValue() override { + if (_rectProp->isSet()) { + setDerivedValue(_rectProp->getUnsafeDerivedValue()); + } else if (_rectPropFromProps->isSet()) { + setDerivedValue(_rectPropFromProps->getUnsafeDerivedValue()); + } else { + setDerivedValue(nullptr); + } + } + +private: + RRectProp *_rectProp; + RRectPropFromProps *_rectPropFromProps; +}; + +/** + Reads rect props from either a given property or from the property object + itself. + */ +class BoxProps : public DerivedProp { +public: + explicit BoxProps(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _boxProp = defineProperty(name); + } + + void updateDerivedValue() override { + auto value = _boxProp->value(); + auto rect = RectProp::processRect(value); + if (rect) { + setDerivedValue(SkRRect::MakeRect(*rect)); + } else { + setDerivedValue(RRectProp::processRRect(value)); + } + } + +private: + NodeProp *_boxProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RadiusProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RadiusProp.h new file mode 100644 index 00000000000000..dd858b148e59a2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RadiusProp.h @@ -0,0 +1,43 @@ +#pragma once + +#include "NodeProp.h" +#include "PointProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPoint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class RadiusProp : public DerivedProp { +public: + explicit RadiusProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _radiusProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_radiusProp->isSet()) { + // Check for simple number: + if (_radiusProp->value().getType() == PropType::Number) { + setDerivedValue(SkPoint::Make(_radiusProp->value().getAsNumber(), + _radiusProp->value().getAsNumber())); + } else { + setDerivedValue(PointProp::processValue(_radiusProp->value())); + } + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_radiusProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RectProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RectProp.h new file mode 100644 index 00000000000000..dc9247985ef569 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/RectProp.h @@ -0,0 +1,133 @@ +#pragma once + +#include "NodeProp.h" +#include "PointProp.h" + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +static PropId PropNameRect = JsiPropId::get("rect"); +static PropId PropNameWidth = JsiPropId::get("width"); +static PropId PropNameHeight = JsiPropId::get("height"); + +/** + Reads a rect from a given propety in the node. The name of the property is + provided on the constructor. The property can either be a Javascript property + or a host object representing an SkRect. + */ +class RectProp : public DerivedProp { +public: + explicit RectProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _prop = defineProperty(name); + } + + static std::shared_ptr processRect(const JsiValue &value) { + if (value.getType() == PropType::HostObject) { + auto rectPtr = + std::dynamic_pointer_cast(value.getAsHostObject()); + if (rectPtr != nullptr) { + return std::make_shared(SkRect::MakeXYWH( + rectPtr->getObject()->x(), rectPtr->getObject()->y(), + rectPtr->getObject()->width(), rectPtr->getObject()->height())); + } + } else if (value.getType() == PropType::Object && + value.hasValue(PropNameX) && value.hasValue(PropNameY) && + value.hasValue(PropNameWidth) && + value.hasValue(PropNameHeight)) { + // Save props for fast access + auto x = value.getValue(PropNameX); + auto y = value.getValue(PropNameY); + auto width = value.getValue(PropNameWidth); + auto height = value.getValue(PropNameHeight); + // Update cache from js object value + return std::make_shared( + SkRect::MakeXYWH(x.getAsNumber(), y.getAsNumber(), + width.getAsNumber(), height.getAsNumber())); + } + return nullptr; + } + + void updateDerivedValue() override { + if (_prop->isSet()) { + setDerivedValue(RectProp::processRect(_prop->value())); + } + } + +private: + NodeProp *_prop; +}; + +/** + Reads rect properties from a node's properties + */ +class RectPropFromProps : public DerivedProp { +public: + explicit RectPropFromProps( + const std::function &onChange) + : DerivedProp(onChange) { + _x = defineProperty(PropNameX); + _y = defineProperty(PropNameY); + _width = defineProperty(PropNameWidth); + _height = defineProperty(PropNameHeight); + } + + void updateDerivedValue() override { + if (_width->isSet() && _height->isSet()) { + auto x = 0.0; + auto y = 0.0; + if (_x->isSet()) { + x = _x->value().getAsNumber(); + } + if (_y->isSet()) { + y = _y->value().getAsNumber(); + } + setDerivedValue(SkRect::MakeXYWH(x, y, _width->value().getAsNumber(), + _height->value().getAsNumber())); + } + } + +private: + NodeProp *_x; + NodeProp *_y; + NodeProp *_width; + NodeProp *_height; +}; + +/** + Reads rect props from either a given property or from the property object + itself. + */ +class RectProps : public DerivedProp { +public: + explicit RectProps(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _rectProp = defineProperty(name); + _rectPropFromProps = defineProperty(); + } + + void updateDerivedValue() override { + if (_rectProp->isSet()) { + setDerivedValue(_rectProp->getUnsafeDerivedValue()); + } else if (_rectPropFromProps->isSet()) { + setDerivedValue(_rectPropFromProps->getUnsafeDerivedValue()); + } else { + setDerivedValue(nullptr); + } + } + +private: + RectProp *_rectProp; + RectPropFromProps *_rectPropFromProps; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/StrokeProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/StrokeProps.h new file mode 100644 index 00000000000000..25bb3e76f7a889 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/StrokeProps.h @@ -0,0 +1,79 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkPaint.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class StrokeCapProp : public DerivedProp { +public: + explicit StrokeCapProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _strokeCap = defineProperty(name); + } + + void updateDerivedValue() override { + if (_strokeCap->isSet() && (_strokeCap->isChanged())) { + auto capValue = _strokeCap->value().getAsString(); + setDerivedValue(getCapFromString(capValue)); + } + } + + static SkPaint::Cap getCapFromString(const std::string &value) { + if (value == "round") { + return SkPaint::Cap::kRound_Cap; + } else if (value == "butt") { + return SkPaint::Cap::kButt_Cap; + } else if (value == "square") { + return SkPaint::Cap::kSquare_Cap; + } + throw std::runtime_error("Property value \"" + value + + "\" is not a legal stroke cap."); + } + +private: + NodeProp *_strokeCap; +}; + +class StrokeJoinProp : public DerivedProp { +public: + explicit StrokeJoinProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _strokeJoin = defineProperty(name); + } + + void updateDerivedValue() override { + if (_strokeJoin->isSet() && (_strokeJoin->isChanged())) { + auto joinValue = _strokeJoin->value().getAsString(); + setDerivedValue(getJoinFromString(joinValue)); + } + } + + static SkPaint::Join getJoinFromString(const std::string &value) { + if (value == "miter") { + return SkPaint::Join::kMiter_Join; + } else if (value == "round") { + return SkPaint::Join::kRound_Join; + } else if (value == "bevel") { + return SkPaint::Join::kBevel_Join; + } + throw std::runtime_error("Property value \"" + value + + "\" is not a legal stroke join."); + } + +private: + NodeProp *_strokeJoin; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/SvgProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/SvgProp.h new file mode 100644 index 00000000000000..fedb1dde43f85e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/SvgProp.h @@ -0,0 +1,45 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkSVG.h" + +#include + +namespace RNSkia { + +class SvgProp : public DerivedSkProp { +public: + explicit SvgProp(PropId name, + const std::function &onChange) + : DerivedSkProp(onChange) { + _imageSvgProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_imageSvgProp->isSet()) { + + if (_imageSvgProp->value().getType() == PropType::HostObject) { + + auto ptr = std::dynamic_pointer_cast( + _imageSvgProp->value().getAsHostObject()); + if (ptr == nullptr) { + throw std::runtime_error( + "Expected SkSvgDom object for the svg property."); + } + setDerivedValue(ptr->getObject()); + } else { + throw std::runtime_error( + "Expected SkSvgDom object or null/undefined for the svg property."); + } + + } else { + setDerivedValue(nullptr); + } + } + +private: + NodeProp *_imageSvgProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TextBlobProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TextBlobProp.h new file mode 100644 index 00000000000000..5050baf1da47c6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TextBlobProp.h @@ -0,0 +1,133 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "JsiSkTextBlob.h" + +#include +#include +#include + +namespace RNSkia { + +class TextBlobProp : public DerivedSkProp { +public: + explicit TextBlobProp(PropId name, + const std::function &onChange) + : DerivedSkProp(onChange) { + _textBlobProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_textBlobProp->value().getType() != PropType::HostObject) { + throw std::runtime_error("Expected SkTextBlob object for the " + + std::string(getName()) + " property."); + } + + auto ptr = _textBlobProp->value().getAs(); + if (ptr == nullptr) { + throw std::runtime_error("Expected SkTextBlob object for the " + + std::string(getName()) + " property."); + } + + setDerivedValue(ptr->getObject()); + } + +private: + NodeProp *_textBlobProp; +}; + +class TextPathBlobProp : public DerivedSkProp { +public: + explicit TextPathBlobProp(const std::function &onChange) + : DerivedSkProp(onChange) { + _fontProp = defineProperty("font"); + _textProp = defineProperty("text"); + _pathProp = defineProperty("path"); + _offsetProp = defineProperty("initialOffset"); + + _textProp->require(); + _pathProp->require(); + _offsetProp->require(); + } + + void updateDerivedValue() override { + auto font = _fontProp->getDerivedValue(); + auto text = _textProp->value().getAsString(); + auto path = _pathProp->getDerivedValue(); + auto offset = _offsetProp->value().getAsNumber(); + + if (font != nullptr) { + // Get glyphs + auto numGlyphIds = + font->countText(text.c_str(), text.length(), SkTextEncoding::kUTF8); + + std::vector glyphIds; + glyphIds.reserve(numGlyphIds); + auto ids = font->textToGlyphs( + text.c_str(), text.length(), SkTextEncoding::kUTF8, + static_cast(glyphIds.data()), numGlyphIds); + + // Get glyph widths + int glyphsSize = static_cast(ids); + std::vector widthPtrs; + widthPtrs.resize(glyphsSize); + font->getWidthsBounds(glyphIds.data(), numGlyphIds, + static_cast(widthPtrs.data()), nullptr, + nullptr); // TODO: Should we use paint somehow here? + + std::vector rsx; + SkContourMeasureIter meas(*path, false, 1); + + auto cont = meas.next(); + auto dist = offset; + + for (size_t i = 0; i < text.length() && cont != nullptr; ++i) { + auto width = widthPtrs[i]; + dist += width / 2; + if (dist > cont->length()) { + // jump to next contour + cont = meas.next(); + if (cont == nullptr) { + // We have come to the end of the path - terminate the string + // right here. + text = text.substr(0, i); + break; + } + dist = width / 2; + } + // Gives us the (x, y) coordinates as well as the cos/sin of the tangent + // line at that position. + SkPoint pos; + SkVector tan; + if (!cont->getPosTan(dist, &pos, &tan)) { + throw std::runtime_error( + "Could not calculate distance when resolving text path"); + } + auto px = pos.x(); + auto py = pos.y(); + auto tx = tan.x(); + auto ty = tan.y(); + + auto adjustedX = px - (width / 2) * tx; + auto adjustedY = py - (width / 2) * ty; + + rsx.push_back(SkRSXform::Make(tx, ty, adjustedX, adjustedY)); + dist += width / 2; + } + + setDerivedValue(SkTextBlob::MakeFromRSXform(text.c_str(), text.length(), + rsx.data(), *font)); + } else { + setDerivedValue(nullptr); + } + } + +private: + FontProp *_fontProp; + NodeProp *_textProp; + PathProp *_pathProp; + NodeProp *_offsetProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TileModeProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TileModeProp.h new file mode 100644 index 00000000000000..34a0a95e572393 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TileModeProp.h @@ -0,0 +1,52 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkTileMode.h" + +#include +#include + +#pragma clang diagnostic pop + +namespace RNSkia { + +class TileModeProp : public DerivedProp { +public: + explicit TileModeProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _tileModeProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_tileModeProp->isSet()) { + setDerivedValue( + getTileModeFromStringValue(_tileModeProp->value().getAsString())); + } else { + setDerivedValue(nullptr); + } + } + +private: + SkTileMode getTileModeFromStringValue(const std::string &value) { + if (value == "clamp") { + return SkTileMode::kClamp; + } else if (value == "repeat") { + return SkTileMode::kRepeat; + } else if (value == "mirror") { + return SkTileMode::kMirror; + } else if (value == "decal") { + return SkTileMode::kDecal; + } + throw std::runtime_error("Value \"" + value + + "\" is not a valid tile mode."); + } + + NodeProp *_tileModeProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TransformProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TransformProp.h new file mode 100644 index 00000000000000..dfb30f842d867e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TransformProp.h @@ -0,0 +1,80 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "JsiSkMatrix.h" + +#include +#include + +namespace RNSkia { + +static PropId PropNameTranslateX = JsiPropId::get("translateX"); +static PropId PropNameTranslateY = JsiPropId::get("translateY"); +static PropId PropNameScale = JsiPropId::get("scale"); +static PropId PropNameScaleX = JsiPropId::get("scaleX"); +static PropId PropNameScaleY = JsiPropId::get("scaleY"); +static PropId PropNameSkewX = JsiPropId::get("skewX"); +static PropId PropNameSkewY = JsiPropId::get("skewY"); +static PropId PropNameRotate = JsiPropId::get("rotate"); +static PropId PropNameRotateZ = JsiPropId::get("rotateZ"); + +class TransformProp : public DerivedProp { +public: + explicit TransformProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _transformProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (!_transformProp->isSet()) { + setDerivedValue(nullptr); + } else if (_transformProp->value().getType() != PropType::Array) { + throw std::runtime_error( + "Expected array for transform property, got " + + JsiValue::getTypeAsString(_transformProp->value().getType())); + } else { + auto m = std::make_shared(SkMatrix()); + for (auto &el : _transformProp->value().getAsArray()) { + auto keys = el.getKeys(); + if (keys.size() == 0) { + throw std::runtime_error( + "Empty value in transform. Expected translateX, translateY, " + "scale, " + "scaleX, scaleY, skewX, skewY, rotate or rotateZ."); + } + auto key = el.getKeys().at(0); + auto value = el.getValue(key).getAsNumber(); + if (key == PropNameTranslateX) { + m->preTranslate(value, 0); + } else if (key == PropNameTranslateY) { + m->preTranslate(0, value); + } else if (key == PropNameScale) { + m->preScale(value, value); + } else if (key == PropNameScaleX) { + m->preScale(value, 1); + } else if (key == PropNameScaleY) { + m->preScale(1, value); + } else if (key == PropNameSkewX) { + m->preSkew(value, 0); + } else if (key == PropNameSkewY) { + m->preSkew(0, value); + } else if (key == PropNameRotate || key == PropNameRotateZ) { + m->preRotate(SkRadiansToDegrees(value)); + } else { + throw std::runtime_error( + "Unknown key in transform. Expected translateX, translateY, " + "scale, " + "scaleX, scaleY, skewX, skewY, rotate or rotateZ - got " + + std::string(key) + "."); + } + } + setDerivedValue(m); + } + } + +private: + NodeProp *_transformProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TransformsProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TransformsProps.h new file mode 100644 index 00000000000000..3173b8d32280ff --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/TransformsProps.h @@ -0,0 +1,66 @@ +#pragma once + +#include "MatrixProp.h" +#include "NodeProp.h" +#include "PointProp.h" +#include "TransformProp.h" + +#include +#include + +namespace RNSkia { + +class TransformsProps : public DerivedProp { +public: + explicit TransformsProps(const std::function &onChange) + : DerivedProp(onChange) { + _transformProp = defineProperty("transform"); + _originProp = defineProperty("origin"); + _matrixProp = defineProperty("matrix"); + } + + void updateDerivedValue() override { + if (_transformProp->isSet() || _originProp->isSet() || + _matrixProp->isSet()) { + + auto matrix = + _matrixProp->isSet() ? _matrixProp->getDerivedValue() : nullptr; + auto origin = + _originProp->isSet() ? _originProp->getDerivedValue() : nullptr; + auto transform = + _transformProp->isSet() ? _transformProp->getDerivedValue() : nullptr; + + auto lm = SkMatrix(); + if (matrix) { + if (origin) { + lm.preTranslate(origin->x(), origin->y()); + lm.preConcat(*matrix); + lm.preTranslate(-origin->x(), -origin->y()); + } else { + lm.setIdentity(); + lm.preConcat(*matrix); + } + } else if (transform) { + lm.setIdentity(); + if (origin) { + lm.preTranslate(origin->x(), origin->y()); + } + lm.preConcat(*transform); + if (origin) { + lm.preTranslate(-origin->x(), -origin->y()); + } + } + setDerivedValue(std::move(lm)); + + } else { + setDerivedValue(nullptr); + } + } + +private: + TransformProp *_transformProp; + PointProp *_originProp; + MatrixProp *_matrixProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/UniformsProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/UniformsProp.h new file mode 100644 index 00000000000000..8e222d6e1e2c84 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/UniformsProp.h @@ -0,0 +1,159 @@ +#pragma once + +#include "DerivedNodeProp.h" +#include "JsiSkRuntimeEffect.h" + +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkRuntimeEffect.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +bool isJSPoint(const JsiValue &value) { + return value.getType() == PropType::Object && value.hasValue(PropNameX) && + value.hasValue(PropNameY); +} + +bool isSkPoint(const JsiValue &value) { + return value.getType() == PropType::HostObject && + std::dynamic_pointer_cast(value.getAsHostObject()) != + nullptr; +} + +bool isIndexable(const JsiValue &value) { + return value.getType() == PropType::Object && value.hasValue(PropName0); +} + +void processValue(std::vector &values, const JsiValue &value) { + if (value.getType() == PropType::Number) { + auto n = value.getAsNumber(); + values.push_back(n); + } else if (value.getType() == PropType::Array) { + auto arrayValue = value.getAsArray(); + for (size_t i = 0; i < arrayValue.size(); ++i) { + auto a = arrayValue[i]; + processValue(values, a); + } + } else if (isJSPoint(value) || isSkPoint(value)) { + auto pointValue = PointProp::processValue(value); + values.push_back(pointValue.x()); + values.push_back(pointValue.y()); + } else if (isIndexable(value)) { + auto length = value.getKeys().size(); + for (size_t i = 0; i < length; ++i) { + values.push_back( + value.getValue(JsiPropId::get(std::to_string(i))).getAsNumber()); + } + } +} + +void processUniform(std::vector &values, SkRuntimeEffect *source, + const JsiValue &uniforms, SkRuntimeShaderBuilder *rtb) { + auto uniformsCount = source->uniforms().size(); + for (size_t i = 0; i < uniformsCount; ++i) { + auto it = source->uniforms().begin() + i; + auto name = JsiPropId::get(std::string(it->name)); + if (!uniforms.hasValue(name)) { + throw std::runtime_error("The runtime effect has the uniform value \"" + + std::string(name) + + "\" declared, but it is missing from the " + "uniforms property of the Runtime effect."); + } + auto value = uniforms.getValue(name); + if (rtb == nullptr) { + processValue(values, value); + } else { + std::vector uniformValue; + processValue(uniformValue, value); + rtb->uniform(name).set(uniformValue.data(), + static_cast(uniformValue.size())); + } + } +} + +class UniformsProp : public DerivedSkProp { +public: + UniformsProp(PropId name, NodeProp *sourceProp, + const std::function &onChange) + : DerivedSkProp(onChange) { + _uniformsProp = defineProperty(name); + _sourceProp = sourceProp; + } + + void updateDerivedValue() override { + if (!_uniformsProp->isSet()) { + return; + } + + // Get the effect + auto source = _sourceProp->value().getAs()->getObject(); + + // Flatten uniforms from property + std::vector uniformValues; + processUniform(uniformValues, source.get(), _uniformsProp->value(), + nullptr); + + // Cast uniforms according to the declaration in the shader + auto uniformsData = castUniforms(source.get(), uniformValues); + + // Save derived value + setDerivedValue(uniformsData); + } + + void processUniforms(SkRuntimeShaderBuilder &rtb) { + if (!_uniformsProp->isSet()) { + return; + } + + // Get the effect + auto source = _sourceProp->value().getAs()->getObject(); + // Flatten uniforms from property + std::vector uniformValues; + processUniform(uniformValues, source.get(), _uniformsProp->value(), &rtb); + } + +private: + sk_sp castUniforms(SkRuntimeEffect *source, + const std::vector &values) { + // Create memory for uniforms + auto uniformSize = source->uniformSize(); + if (values.size() * sizeof(float) != uniformSize) { + throw std::runtime_error( + "Uniforms size differs from effect's uniform size. Received " + + std::to_string(values.size()) + " expected " + + std::to_string(uniformSize / sizeof(float))); + } + auto uniformsData = SkData::MakeUninitialized(uniformSize); + + // Loop through all uniforms in the effect and load data from the flattened + // array of values + const auto &u = source->uniforms(); + for (std::size_t i = 0; i < u.size(); i++) { + auto it = source->uniforms().begin() + i; + RuntimeEffectUniform reu = JsiSkRuntimeEffect::fromUniform(*it); + for (std::size_t j = 0; j < reu.columns * reu.rows; ++j) { + const std::size_t offset = reu.slot + j; + float fValue = values.at(offset); + int iValue = static_cast(fValue); + auto value = reu.isInteger ? SkBits2Float(iValue) : fValue; + memcpy(SkTAddOffset(uniformsData->writable_data(), + offset * sizeof(value)), + &value, sizeof(value)); + } + } + + return uniformsData; + } + + NodeProp *_uniformsProp; + NodeProp *_sourceProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/VertexModeProp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/VertexModeProp.h new file mode 100644 index 00000000000000..548ac486027590 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/VertexModeProp.h @@ -0,0 +1,49 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkVertices.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class VertexModeProp : public DerivedProp { +public: + explicit VertexModeProp(PropId name, + const std::function &onChange) + : DerivedProp(onChange) { + _vertexModeProp = defineProperty(name); + } + + void updateDerivedValue() override { + if (_vertexModeProp->isSet() && (_vertexModeProp->isChanged())) { + auto vertexModeValue = _vertexModeProp->value().getAsString(); + setDerivedValue(getVertexModeFromStringValue(vertexModeValue)); + } + } + +private: + SkVertices::VertexMode + getVertexModeFromStringValue(const std::string &value) { + if (value == "triangles") { + return SkVertices::VertexMode::kTriangles_VertexMode; + } else if (value == "triangleStrip") { + return SkVertices::VertexMode::kTriangleStrip_VertexMode; + } else if (value == "triangleFan") { + return SkVertices::VertexMode::kTriangleFan_VertexMode; + } + throw std::runtime_error("Property value \"" + value + + "\" is not a legal blend mode."); + } + + NodeProp *_vertexModeProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/VerticesProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/VerticesProps.h new file mode 100644 index 00000000000000..c0e23f3d226458 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/dom/props/VerticesProps.h @@ -0,0 +1,63 @@ +#pragma once + +#include "DerivedNodeProp.h" + +#include "ColorProp.h" +#include "NumbersProp.h" +#include "PointsProp.h" +#include "VertexModeProp.h" + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" + +#include "SkVertices.h" + +#pragma clang diagnostic pop + +namespace RNSkia { + +class VerticesProps : public DerivedSkProp { +public: + explicit VerticesProps(const std::function &onChange) + : DerivedSkProp(onChange) { + _vertexModeProp = defineProperty("mode"); + _colorsProp = defineProperty("colors"); + _verticesProp = defineProperty("vertices"); + _texturesProp = defineProperty("textures"); + _indicesProp = defineProperty("indices"); + + _vertexModeProp->require(); + _verticesProp->require(); + } + + bool hasColors() { return _colorsProp->isSet(); } + + void updateDerivedValue() override { + const SkVertices::VertexMode *vertextMode = + _vertexModeProp->getDerivedValue().get(); + const std::vector *colors = _colorsProp->getDerivedValue().get(); + auto vertices = _verticesProp->getDerivedValue(); + auto textures = _texturesProp->getDerivedValue(); + auto indices = _indicesProp->getDerivedValue(); + + setDerivedValue(SkVertices::MakeCopy( + *vertextMode, static_cast(vertices->size()), + _verticesProp->isSet() ? vertices->data() : nullptr, + _texturesProp->isSet() ? textures->data() : nullptr, + _colorsProp->isSet() ? colors->data() : nullptr, + _indicesProp->isSet() ? static_cast(indices->size()) : 0, + _indicesProp->isSet() ? indices->data() : nullptr)); + } + +private: + VertexModeProp *_vertexModeProp; + ColorsProp *_colorsProp; + PointsProp *_verticesProp; + PointsProp *_texturesProp; + Numbers16Prop *_indicesProp; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkClockValue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkClockValue.h new file mode 100644 index 00000000000000..b65cb3b7997f0f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkClockValue.h @@ -0,0 +1,140 @@ + +#pragma once + +#include "RNSkPlatformContext.h" +#include "RNSkReadonlyValue.h" +#include + +#include +#include +#include +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; +/** + Implements a readonly Value that is updated every time the screen is redrawn. + Its value will be the number of milliseconds since the animation value was + started. + */ +class RNSkClockValue : public RNSkReadonlyValue { + enum RNSkClockState { NotStarted = 0, Running = 1, Stopped = 2 }; + +public: + RNSkClockValue(std::shared_ptr platformContext, + size_t identifier, jsi::Runtime &runtime, + const jsi::Value *arguments, size_t count) + : RNSkReadonlyValue(platformContext), _runtime(runtime), + _identifier(identifier) { + // Start by updating to zero (start value) + update(_runtime, static_cast(0)); + } + + virtual ~RNSkClockValue() { stopClock(); } + + JSI_HOST_FUNCTION(start) { + startClock(); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(stop) { + stopClock(); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkReadonlyValue, addListener), + JSI_EXPORT_FUNC(RNSkClockValue, start), + JSI_EXPORT_FUNC(RNSkClockValue, stop)) + + virtual void startClock() { + if (_state == RNSkClockState::Running) { + return; + } + + auto now = std::chrono::high_resolution_clock::now(); + if (_state == RNSkClockState::NotStarted) { + _start = now; + _stop = now; + } + + // Subtract pause time from start + auto timeSinceStop = now - _stop; + _start += timeSinceStop; + + _state = RNSkClockState::Running; + + getContext()->beginDrawLoop( + _identifier, [weakSelf = weak_from_this()](bool invalidated) { + auto self = weakSelf.lock(); + if (self) { + std::dynamic_pointer_cast(self)->notifyUpdate( + invalidated); + } + }); + } + + virtual void stopClock() { + if (_state == RNSkClockState::Running) { + _state = RNSkClockState::Stopped; + _stop = std::chrono::high_resolution_clock::now(); + getContext()->endDrawLoop(_identifier); + } + } + +protected: + virtual void tick(jsi::Runtime &runtime, const jsi::Value &value) { + RNSkClockValue::update(runtime, value); + } + + void notifyUpdate(bool invalidated) { + if (invalidated) { + stopClock(); + return; + } + + if (_state != RNSkClockState::Running) { + return; + } + + // Ensure we call any updates from the draw loop on the javascript thread + getContext()->runOnJavascriptThread( + // To ensure that this shared_ptr instance is not deallocated before we + // are done running the update lambda we pass a shared from this to the + // lambda scope. + [weakSelf = weak_from_this()]() { + auto self = weakSelf.lock(); + if (self) { + auto selfClockValue = + std::dynamic_pointer_cast(self); + if (selfClockValue->getState() == RNSkClockState::Running) { + auto now = std::chrono::high_resolution_clock::now(); + auto deltaFromStart = + std::chrono::duration_cast( + now - selfClockValue->_start) + .count(); + selfClockValue->tick(selfClockValue->_runtime, + static_cast(deltaFromStart)); + } + } + }); + } + + /** + Returns the draw identifier for the clock. This identifier is used + for the draw loop. + */ + size_t getIdentifier() { return _identifier; } + + /** + Returns the state of the clock + */ + RNSkClockState getState() { return _state; } + + jsi::Runtime &_runtime; + size_t _identifier; + std::chrono::time_point _start; + std::chrono::time_point _stop; + std::atomic _state = {RNSkClockState::NotStarted}; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkComputedValue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkComputedValue.h new file mode 100644 index 00000000000000..d6071bffac2d1c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkComputedValue.h @@ -0,0 +1,104 @@ + +#pragma once + +#include "RNSkPlatformContext.h" +#include "RNSkReadonlyValue.h" +#include + +#include +#include +#include +#include +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; + +/** + Creates a readonly value that depends on one or more other values. The derived + value has a callback function that is used to calculate the new value when any + of the dependencies change. + */ +class RNSkComputedValue : public RNSkReadonlyValue { +public: + RNSkComputedValue(std::shared_ptr platformContext, + jsi::Runtime &runtime, const jsi::Value *arguments, + size_t count) + : RNSkReadonlyValue(platformContext) { + // Verify input + if (!arguments[0].isObject() || + !arguments[0].asObject(runtime).isFunction(runtime)) { + throw jsi::JSError(runtime, + "Expected callback function as first parameter"); + } + + if (!arguments[1].isObject() || + !arguments[1].asObject(runtime).isArray(runtime)) { + throw jsi::JSError(runtime, + "Expected array of dependencies as second parameter"); + } + + // Get callback for calculating result + _callback = std::make_shared( + arguments[0].asObject(runtime).asFunction(runtime)); + } + + void invalidate() override { + RNSkReadonlyValue::invalidate(); + + // Unregister listeners + for (const auto &unsubscribe : _unsubscribers) { + unsubscribe(); + } + _unsubscribers.clear(); + } + + void initializeDependencies(jsi::Runtime &runtime, + const jsi::Value *arguments, size_t count) { + // Save dependencies + std::vector> dependencies; + + // Ensure that all dependencies are Values + auto deps = arguments[1].asObject(runtime).asArray(runtime); + const std::size_t size = deps.size(runtime); + dependencies.reserve(size); + for (size_t i = 0; i < size; ++i) { + auto dep = deps.getValueAtIndex(runtime, i); + if (!dep.isObject() || !dep.asObject(runtime).isHostObject(runtime)) { + continue; + } + auto value = + dep.asObject(runtime).asHostObject(runtime); + if (value == nullptr) { + continue; + } + dependencies.push_back(value); + } + + // register change handler on dependencies + _unsubscribers.reserve(_unsubscribers.size() + size); + for (const auto &dep : dependencies) { + _unsubscribers.push_back(dep->addListener([weakSelf = weak_from_this()]( + jsi::Runtime &runtime) { + auto self = weakSelf.lock(); + if (self) { + auto selfAsThis = std::dynamic_pointer_cast(self); + selfAsThis->dependencyUpdated(runtime); + } + })); + } + + // Set initial value + dependencyUpdated(runtime); + } + +private: + void dependencyUpdated(jsi::Runtime &runtime) { + // Calculate new value + update(runtime, _callback->call(runtime, nullptr, 0)); + } + + std::shared_ptr _callback; + std::vector> _unsubscribers; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkReadonlyValue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkReadonlyValue.h new file mode 100644 index 00000000000000..f8eb5aade60608 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkReadonlyValue.h @@ -0,0 +1,167 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "JsiSkHostObjects.h" +#include "JsiValueWrapper.h" +#include "RNSkPlatformContext.h" + +namespace RNSkia { +namespace jsi = facebook::jsi; + +/** + Implements a readonly Value that is updated every time the screen is redrawn. + Its value will be the number of milliseconds since the animation value was + started. + */ +class RNSkReadonlyValue + : public JsiSkHostObject, + public std::enable_shared_from_this { +public: + explicit RNSkReadonlyValue( + std::shared_ptr platformContext) + : JsiSkHostObject(platformContext), + _valueHolder(std::make_shared( + *platformContext->getJsRuntime())) {} + + virtual ~RNSkReadonlyValue() { invalidate(); } + + JSI_PROPERTY_GET(__typename__) { + return jsi::String::createFromUtf8(runtime, "RNSkValue"); + } + + JSI_PROPERTY_GET(current) { return getCurrent(runtime); } + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(RNSkReadonlyValue, + __typename__), + JSI_EXPORT_PROP_GET(RNSkReadonlyValue, current)) + + JSI_HOST_FUNCTION(addListener) { + if (!arguments[0].isObject() || + !arguments[0].asObject(runtime).isFunction(runtime)) { + throw jsi::JSError(runtime, "Expected function as first parameter."); + return jsi::Value::undefined(); + } + auto callback = std::make_shared( + arguments[0].asObject(runtime).asFunction(runtime)); + + auto unsubscribe = + addListener([weakSelf = weak_from_this(), + callback = std::move(callback)](jsi::Runtime &runtime) { + auto self = weakSelf.lock(); + if (self) { + auto selfReadonlyValue = + std::dynamic_pointer_cast(self); + callback->call(runtime, selfReadonlyValue->get_current(runtime)); + } + }); + + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, "unsubscribe"), 0, + JSI_HOST_FUNCTION_LAMBDA { + unsubscribe(); + return jsi::Value::undefined(); + }); + } + + JSI_HOST_FUNCTION(dispose) { + invalidate(); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkReadonlyValue, addListener), + JSI_EXPORT_FUNC(RNSkReadonlyValue, dispose)) + + /** + * Adds a callback that will be called whenever the value changes + * @param cb Callback + * @return unsubscribe function + */ + const std::function + addListener(const std::function cb) { + std::lock_guard lock(_mutex); + auto listenerId = _listenerId++; + _listeners.emplace(listenerId, cb); + return [weakSelf = weak_from_this(), listenerId]() { + auto self = weakSelf.lock(); + if (self) { + self->removeListener(listenerId); + } + }; + } + + /** + Updates the underlying value and notifies all listeners about the change. + Listeners are only notified if the value was actually changed for numeric, + boolean and string values. For all other values listeners are notified + without comparison. + @param runtime Current JS Runtime + @param value Next value + */ + virtual void update(jsi::Runtime &runtime, const jsi::Value &value) { + auto equal = _valueHolder->equals(runtime, value); + if (!equal) { + _valueHolder->setCurrent(runtime, value); + notifyListeners(runtime); + } + } + + /** + Override to implement invalidation logic for the value. In the base class + this function clears all subscribers. + */ + virtual void invalidate() { + std::lock_guard lock(_mutex); + _listeners.clear(); + } + + /** + Returns the current value as a jsi::Value + */ + jsi::Value getCurrent(jsi::Runtime &runtime) { + return _valueHolder->getCurrent(runtime); + } + + /** + Returns the underlying current value wrapper. This can be used to query the + holder for data type and get pointers to elements in the holder. + */ + std::shared_ptr getCurrent() { return _valueHolder; } + +protected: + /** + Notifies listeners about changes + @param runtime Current JS Runtime + */ + void notifyListeners(jsi::Runtime &runtime) { + std::lock_guard lock(_mutex); + for (const auto &listener : _listeners) { + listener.second(runtime); + } + } + + /** + Removes a subscription listeners + @param listenerId identifier of listener to remove + */ + void removeListener(long listenerId) { + std::lock_guard lock(_mutex); + _listeners.erase(listenerId); + } + +private: + std::shared_ptr _valueHolder; + + long _listenerId = 0; + std::unordered_map> _listeners; + std::mutex _mutex; +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkValue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkValue.h new file mode 100644 index 00000000000000..381e0b8c4d7c4c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/rnskia/values/RNSkValue.h @@ -0,0 +1,116 @@ +#pragma once + +#include +#include + +#include "JsiHostObject.h" +#include "RNSkAnimation.h" +#include "RNSkPlatformContext.h" +#include "RNSkReadonlyValue.h" +#include + +namespace RNSkia { +namespace jsi = facebook::jsi; +/** + Implements a Value that can be both read and written to. It inherits from the + ReadonlyValue with functionailty for subscribing to changes. + */ +class RNSkValue : public RNSkReadonlyValue { +public: + RNSkValue(std::shared_ptr platformContext, + jsi::Runtime &runtime, const jsi::Value *arguments, size_t count) + : RNSkReadonlyValue(platformContext) { + if (count == 1) { + update(runtime, arguments[0]); + } + } + + ~RNSkValue() { unsubscribe(); } + + JSI_PROPERTY_SET(current) { + // When someone else is setting the value we need to stop any ongoing + // animations + unsubscribe(); + update(runtime, value); + } + + JSI_PROPERTY_SET(animation) { + // Cancel existing animation + unsubscribe(); + + // Verify input + if (value.isObject() && + value.asObject(runtime).isHostObject(runtime)) { + auto animation = + value.asObject(runtime).getHostObject(runtime); + if (animation != nullptr) { + // Now we have a value animation - let us connect and start + subscribe(animation); + } + } else if (value.isUndefined() || value.isNull()) { + // Do nothing - we've already unsubscribed + } else { + throw jsi::JSError(runtime, "Animation expected."); + } + } + + JSI_PROPERTY_GET(animation) { + if (_animation != nullptr) { + return jsi::Object::createFromHostObject(runtime, _animation); + } + return jsi::Value::undefined(); + } + + JSI_EXPORT_PROPERTY_SETTERS(JSI_EXPORT_PROP_SET(RNSkValue, current), + JSI_EXPORT_PROP_SET(RNSkValue, animation)) + + JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(RNSkReadonlyValue, + __typename__), + JSI_EXPORT_PROP_GET(RNSkValue, current), + JSI_EXPORT_PROP_GET(RNSkValue, animation)) + + JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkValue, addListener), + JSI_EXPORT_FUNC(RNSkReadonlyValue, dispose)) + +private: + void subscribe(std::shared_ptr animation) { + if (animation != nullptr) { + _animation = animation; + _unsubscribe = + std::make_shared>(_animation->addListener( + [weakSelf = weak_from_this()](jsi::Runtime &runtime) { + auto self = weakSelf.lock(); + if (self) { + auto selfAsThis = std::dynamic_pointer_cast(self); + selfAsThis->animationDidUpdate(runtime); + } + })); + // Start the animation + _animation->startClock(); + } + } + + void animationDidUpdate(jsi::Runtime &runtime) { + if (_animation != nullptr) { + // Update ourselves from the current animation value + update(runtime, _animation->get_current(runtime)); + } + } + + void unsubscribe() { + if (_unsubscribe != nullptr) { + (*_unsubscribe)(); + _unsubscribe = nullptr; + } + + if (_animation != nullptr) { + _animation->stopClock(); + _animation = nullptr; + } + } + + std::shared_ptr _animation; + std::shared_ptr> _unsubscribe; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkAndroidFrameworkUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkAndroidFrameworkUtils.h new file mode 100644 index 00000000000000..3407cfd02c00de --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkAndroidFrameworkUtils.h @@ -0,0 +1,89 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAndroidFrameworkUtils_DEFINED +#define SkAndroidFrameworkUtils_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTileMode.h" + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + +class SkCanvas; +struct SkIRect; +struct SkRect; +class SkSurface; +class SkShader; + +/** + * SkAndroidFrameworkUtils expose private APIs used only by Android framework. + */ +class SkAndroidFrameworkUtils { +public: + +#if defined(SK_GANESH) + /** + * clipWithStencil draws the current clip into a stencil buffer with reference value and mask + * set to 0x1. This function works only on a GPU canvas. + * + * @param canvas A GPU canvas that has a non-empty clip. + * + * @return true on success or false if clip is empty or not a GPU canvas. + */ + static bool clipWithStencil(SkCanvas* canvas); +#endif //defined(SK_GANESH) + + static void SafetyNetLog(const char*); + + static sk_sp getSurfaceFromCanvas(SkCanvas* canvas); + + static int SaveBehind(SkCanvas* canvas, const SkRect* subset); + + // Operating within the canvas' clip stack, this resets the geometry of the clip to be wide + // open modula any device clip restriction that was set outside of the clip stack. + static void ResetClip(SkCanvas* canvas); + + /** + * Unrolls a chain of nested SkPaintFilterCanvas to return the base wrapped canvas. + * + * @param canvas A SkPaintFilterCanvas or any other SkCanvas subclass. + * + * @return SkCanvas that was found in the innermost SkPaintFilterCanvas. + */ + static SkCanvas* getBaseWrappedCanvas(SkCanvas* canvas); + + /** + * If the shader represents a linear gradient ShaderAsALinearGradient + * returns true and if info is not null, ShaderAsALinearGradient populates + * info with the parameters for the gradient. fColorCount is both an input + * and output parameter. On input, it indicates how many entries in + * fColors and fColorOffsets can be used, if they are not nullptr. After + * asAGradient has run, fColorCount indicates how many color-offset pairs + * there are in the gradient. fColorOffsets specifies where on the range of + * 0 to 1 to transition to the given color. fPoints represent the endpoints + * of the gradient. + */ + struct LinearGradientInfo { + int fColorCount = 0; //!< In-out parameter, specifies passed size + // of fColors/fColorOffsets on input, and + // actual number of colors/offsets on + // output. + SkColor* fColors = nullptr; //!< The colors in the gradient. + SkScalar* fColorOffsets = nullptr; //!< The unit offset for color transitions. + SkPoint fPoints[2]; //!< Type specific, see above. + SkTileMode fTileMode; + uint32_t fGradientFlags = 0; //!< see SkGradientShader::Flags + }; + + static bool ShaderAsALinearGradient(SkShader* shader, LinearGradientInfo*); +}; + +#endif // SK_BUILD_FOR_ANDROID_ANDROID + +#endif // SkAndroidFrameworkUtils_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkAnimatedImage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkAnimatedImage.h new file mode 100644 index 00000000000000..8143c1722bec0d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkAnimatedImage.h @@ -0,0 +1,179 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAnimatedImage_DEFINED +#define SkAnimatedImage_DEFINED + +#include "include/codec/SkCodecAnimation.h" +#include "include/core/SkBitmap.h" +#include "include/core/SkDrawable.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkRect.h" + +class SkAndroidCodec; +class SkImage; +class SkPicture; + +/** + * Thread unsafe drawable for drawing animated images (e.g. GIF). + */ +class SK_API SkAnimatedImage : public SkDrawable { +public: + /** + * Create an SkAnimatedImage from the SkAndroidCodec. + * + * Returns null on failure to allocate pixels. On success, this will + * decode the first frame. + * + * @param info Width and height may require scaling. + * @param cropRect Rectangle to crop to after scaling. + * @param postProcess Picture to apply after scaling and cropping. + */ + static sk_sp Make(std::unique_ptr, + const SkImageInfo& info, SkIRect cropRect, sk_sp postProcess); + + /** + * Simpler version that uses the default size, no cropping, and no postProcess. + */ + static sk_sp Make(std::unique_ptr); + + ~SkAnimatedImage() override; + + /** + * Reset the animation to the beginning. + */ + void reset(); + + /** + * Whether the animation completed. + * + * Returns true after all repetitions are complete, or an error stops the + * animation. Gets reset to false if the animation is restarted. + */ + bool isFinished() const { return fFinished; } + + /** + * Returned by decodeNextFrame and currentFrameDuration if the animation + * is not running. + */ + static constexpr int kFinished = -1; + + /** + * Decode the next frame. + * + * If the animation is on the last frame or has hit an error, returns + * kFinished. + */ + int decodeNextFrame(); + + /** + * Returns the current frame as an SkImage. The SkImage will not change + * after it has been returned. + * If there is no current frame, nullptr will be returned. + */ + sk_sp getCurrentFrame(); + + /** + * How long to display the current frame. + * + * Useful for the first frame, for which decodeNextFrame is called + * internally. + */ + int currentFrameDuration() { + return fCurrentFrameDuration; + } + + /** + * Change the repetition count. + * + * By default, the image will repeat the number of times indicated in the + * encoded data. + * + * Use SkCodec::kRepetitionCountInfinite for infinite, and 0 to show all + * frames once and then stop. + */ + void setRepetitionCount(int count); + + /** + * Return the currently set repetition count. + */ + int getRepetitionCount() const { + return fRepetitionCount; + } + + /** + * Return the total number of frames in the animation. + */ + int getFrameCount() const { return fFrameCount; } + +protected: + SkRect onGetBounds() override; + void onDraw(SkCanvas*) override; + +private: + struct Frame { + SkBitmap fBitmap; + int fIndex; + SkCodecAnimation::DisposalMethod fDisposalMethod; + + // init() may have to create a new SkPixelRef, if the + // current one is already in use by another owner (e.g. + // an SkPicture). This determines whether to copy the + // existing one to the new one. + enum class OnInit { + // Restore the image from the old SkPixelRef to the + // new one. + kRestoreIfNecessary, + // No need to restore. + kNoRestore, + }; + + Frame(); + bool init(const SkImageInfo& info, OnInit); + bool copyTo(Frame*) const; + }; + + std::unique_ptr fCodec; + SkImageInfo fDecodeInfo; + const SkIRect fCropRect; + const sk_sp fPostProcess; + const int fFrameCount; + SkMatrix fMatrix; + int fSampleSize; + + bool fFinished; + int fCurrentFrameDuration; + Frame fDisplayFrame; + Frame fDecodingFrame; + Frame fRestoreFrame; + int fRepetitionCount; + int fRepetitionsCompleted; + + SkAnimatedImage(std::unique_ptr, const SkImageInfo& requestedInfo, + SkIRect cropRect, sk_sp postProcess); + + int computeNextFrame(int current, bool* animationEnded); + double finish(); + + /** + * True if there is no crop, orientation, or post decoding scaling. + */ + bool simple() const { return fMatrix.isIdentity() && !fPostProcess + && fCropRect == fDecodeInfo.bounds(); } + + /** + * Returns the current frame as an SkImage. + * + * Like getCurrentFrame, but only returns the raw data from the internal SkBitmap. (i.e. no + * scaling, orientation-correction or cropping.) If simple(), this is the final output. + */ + sk_sp getCurrentFrameSimple(); + + using INHERITED = SkDrawable; +}; + +#endif // SkAnimatedImage_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkImageAndroid.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkImageAndroid.h new file mode 100644 index 00000000000000..14ed009f8c400d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/android/SkImageAndroid.h @@ -0,0 +1,101 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageAndroid_DEFINED +#define SkImageAndroid_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrTypes.h" + +class SkColorSpace; +class GrDirectContext; +class SkPixmap; +struct AHardwareBuffer; + +namespace SkImages { + +/** (See Skia bug 7447) + Creates SkImage from Android hardware buffer. + Returned SkImage takes a reference on the buffer. + Only available on Android, when __ANDROID_API__ is defined to be 26 or greater. + @param hardwareBuffer AHardwareBuffer Android hardware buffer + @param colorSpace range of colors; may be nullptr + @return created SkImage, or nullptr +*/ +SK_API sk_sp DeferredFromAHardwareBuffer(AHardwareBuffer* hardwareBuffer, + SkAlphaType alphaType = kPremul_SkAlphaType); +SK_API sk_sp DeferredFromAHardwareBuffer( + AHardwareBuffer* hardwareBuffer, + SkAlphaType alphaType, + sk_sp colorSpace, + GrSurfaceOrigin surfaceOrigin = kTopLeft_GrSurfaceOrigin); + +/** Creates SkImage from Android hardware buffer and uploads the data from the SkPixmap to it. + Returned SkImage takes a reference on the buffer. + Only available on Android, when __ANDROID_API__ is defined to be 26 or greater. + @param context GPU context + @param pixmap SkPixmap that contains data to be uploaded to the AHardwareBuffer + @param hardwareBuffer AHardwareBuffer Android hardware buffer + @param surfaceOrigin surface origin for resulting image + @return created SkImage, or nullptr +*/ +SK_API sk_sp TextureFromAHardwareBufferWithData( + GrDirectContext* context, + const SkPixmap& pixmap, + AHardwareBuffer* hardwareBuffer, + GrSurfaceOrigin surfaceOrigin = kTopLeft_GrSurfaceOrigin); + +/** + * Like SkImagePriv::SkMakeImageFromRasterBitmap, except this can be pinned using + * skgpu::ganesh::PinAsTexture and CopyPixelMode is never. + */ +SK_API sk_sp PinnableRasterFromBitmap(const SkBitmap&); + +} // namespace SkImages + +// TODO(kjlubick) remove this after Android has been ported. +namespace sk_image_factory { +inline sk_sp MakePinnableFromRasterBitmap(const SkBitmap& b) { + return SkImages::PinnableRasterFromBitmap(b); +} +} // namespace sk_image_factory + +namespace skgpu::ganesh { +/** + * Will attempt to upload and lock the contents of the image as a texture, so that subsequent + * draws to a gpu-target will come from that texture (and not by looking at the original image + * src). In particular this is intended to use the texture even if the image's original content + * changes subsequent to this call (i.e. the src is mutable!). + * + * Only compatible with SkImages created from SkImages::PinnableRasterFromBitmap. + * + * All successful calls must be balanced by an equal number of calls to UnpinTexture(). + * + * Once in this "pinned" state, the image has all of the same thread restrictions that exist + * for a natively created gpu image (e.g. SkImage::MakeFromTexture) + * - all drawing, pinning, unpinning must happen in the same thread as the GrContext. + * + * @return true if the image was successfully uploaded and locked into a texture + */ +bool PinAsTexture(GrRecordingContext*, SkImage*); + +/** + * The balancing call to a successful invocation of PinAsTexture. When a balanced + * number of calls have been made, then the "pinned" texture is free to be purged, etc. This + * also means that a subsequent "pin" call will look at the original content again, and if + * its uniqueID/generationID has changed, then a newer texture will be uploaded/pinned. + * + * Only compatible with SkImages created from SkImages::PinnableRasterFromBitmap. + * + * The context passed to unpin must match the one passed to pin. + */ +void UnpinTexture(GrRecordingContext*, SkImage*); + +} // namespace skgpu::ganesh + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkAndroidCodec.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkAndroidCodec.h new file mode 100644 index 00000000000000..2b8a79751cfd9f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkAndroidCodec.h @@ -0,0 +1,297 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAndroidCodec_DEFINED +#define SkAndroidCodec_DEFINED + +#include "include/codec/SkCodec.h" +#include "include/core/SkColorSpace.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/SkEncodedInfo.h" +#include "include/private/base/SkNoncopyable.h" +#include "modules/skcms/skcms.h" + +// TODO(kjlubick, bungeman) Replace these includes with forward declares +#include "include/codec/SkEncodedImageFormat.h" // IWYU pragma: keep +#include "include/core/SkAlphaType.h" // IWYU pragma: keep +#include "include/core/SkColorType.h" // IWYU pragma: keep + +#include +#include + +class SkData; +class SkPngChunkReader; +class SkStream; +struct SkGainmapInfo; +struct SkIRect; + +/** + * Abstract interface defining image codec functionality that is necessary for + * Android. + */ +class SK_API SkAndroidCodec : SkNoncopyable { +public: + /** + * Deprecated. + * + * Now that SkAndroidCodec supports multiframe images, there are multiple + * ways to handle compositing an oriented frame on top of an oriented frame + * with different tradeoffs. SkAndroidCodec now ignores the orientation and + * forces the client to handle it. + */ + enum class ExifOrientationBehavior { + kIgnore, + kRespect, + }; + + /** + * Pass ownership of an SkCodec to a newly-created SkAndroidCodec. + */ + static std::unique_ptr MakeFromCodec(std::unique_ptr); + + /** + * If this stream represents an encoded image that we know how to decode, + * return an SkAndroidCodec that can decode it. Otherwise return NULL. + * + * The SkPngChunkReader handles unknown chunks in PNGs. + * See SkCodec.h for more details. + * + * If NULL is returned, the stream is deleted immediately. Otherwise, the + * SkCodec takes ownership of it, and will delete it when done with it. + */ + static std::unique_ptr MakeFromStream(std::unique_ptr, + SkPngChunkReader* = nullptr); + + /** + * If this data represents an encoded image that we know how to decode, + * return an SkAndroidCodec that can decode it. Otherwise return NULL. + * + * The SkPngChunkReader handles unknown chunks in PNGs. + * See SkCodec.h for more details. + */ + static std::unique_ptr MakeFromData(sk_sp, SkPngChunkReader* = nullptr); + + virtual ~SkAndroidCodec(); + + // TODO: fInfo is now just a cache of SkCodec's SkImageInfo. No need to + // cache and return a reference here, once Android call-sites are updated. + const SkImageInfo& getInfo() const { return fInfo; } + + /** + * Return the ICC profile of the encoded data. + */ + const skcms_ICCProfile* getICCProfile() const { + return fCodec->getEncodedInfo().profile(); + } + + /** + * Format of the encoded data. + */ + SkEncodedImageFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); } + + /** + * @param requestedColorType Color type requested by the client + * + * |requestedColorType| may be overriden. We will default to kF16 + * for high precision images. + * + * In the general case, if it is possible to decode to + * |requestedColorType|, this returns |requestedColorType|. + * Otherwise, this returns a color type that is an appropriate + * match for the the encoded data. + */ + SkColorType computeOutputColorType(SkColorType requestedColorType); + + /** + * @param requestedUnpremul Indicates if the client requested + * unpremultiplied output + * + * Returns the appropriate alpha type to decode to. If the image + * has alpha, the value of requestedUnpremul will be honored. + */ + SkAlphaType computeOutputAlphaType(bool requestedUnpremul); + + /** + * @param outputColorType Color type that the client will decode to. + * @param prefColorSpace Preferred color space to decode to. + * This may not return |prefColorSpace| for + * specific color types. + * + * Returns the appropriate color space to decode to. + */ + sk_sp computeOutputColorSpace(SkColorType outputColorType, + sk_sp prefColorSpace = nullptr); + + /** + * Compute the appropriate sample size to get to |size|. + * + * @param size As an input parameter, the desired output size of + * the decode. As an output parameter, the smallest sampled size + * larger than the input. + * @return the sample size to set AndroidOptions::fSampleSize to decode + * to the output |size|. + */ + int computeSampleSize(SkISize* size) const; + + /** + * Returns the dimensions of the scaled output image, for an input + * sampleSize. + * + * When the sample size divides evenly into the original dimensions, the + * scaled output dimensions will simply be equal to the original + * dimensions divided by the sample size. + * + * When the sample size does not divide even into the original + * dimensions, the codec may round up or down, depending on what is most + * efficient to decode. + * + * Finally, the codec will always recommend a non-zero output, so the output + * dimension will always be one if the sampleSize is greater than the + * original dimension. + */ + SkISize getSampledDimensions(int sampleSize) const; + + /** + * Return (via desiredSubset) a subset which can decoded from this codec, + * or false if the input subset is invalid. + * + * @param desiredSubset in/out parameter + * As input, a desired subset of the original bounds + * (as specified by getInfo). + * As output, if true is returned, desiredSubset may + * have been modified to a subset which is + * supported. Although a particular change may have + * been made to desiredSubset to create something + * supported, it is possible other changes could + * result in a valid subset. If false is returned, + * desiredSubset's value is undefined. + * @return true If the input desiredSubset is valid. + * desiredSubset may be modified to a subset + * supported by the codec. + * false If desiredSubset is invalid (NULL or not fully + * contained within the image). + */ + bool getSupportedSubset(SkIRect* desiredSubset) const; + // TODO: Rename SkCodec::getValidSubset() to getSupportedSubset() + + /** + * Returns the dimensions of the scaled, partial output image, for an + * input sampleSize and subset. + * + * @param sampleSize Factor to scale down by. + * @param subset Must be a valid subset of the original image + * dimensions and a subset supported by SkAndroidCodec. + * getSubset() can be used to obtain a subset supported + * by SkAndroidCodec. + * @return Size of the scaled partial image. Or zero size + * if either of the inputs is invalid. + */ + SkISize getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const; + + /** + * Additional options to pass to getAndroidPixels(). + */ + // FIXME: It's a bit redundant to name these AndroidOptions when this class is already + // called SkAndroidCodec. On the other hand, it's may be a bit confusing to call + // these Options when SkCodec has a slightly different set of Options. Maybe these + // should be DecodeOptions or SamplingOptions? + struct AndroidOptions : public SkCodec::Options { + AndroidOptions() + : SkCodec::Options() + , fSampleSize(1) + {} + + /** + * The client may provide an integer downscale factor for the decode. + * The codec may implement this downscaling by sampling or another + * method if it is more efficient. + * + * The default is 1, representing no downscaling. + */ + int fSampleSize; + }; + + /** + * Decode into the given pixels, a block of memory of size at + * least (info.fHeight - 1) * rowBytes + (info.fWidth * + * bytesPerPixel) + * + * Repeated calls to this function should give the same results, + * allowing the PixelRef to be immutable. + * + * @param info A description of the format (config, size) + * expected by the caller. This can simply be identical + * to the info returned by getInfo(). + * + * This contract also allows the caller to specify + * different output-configs, which the implementation can + * decide to support or not. + * + * A size that does not match getInfo() implies a request + * to scale or subset. If the codec cannot perform this + * scaling or subsetting, it will return an error code. + * + * The AndroidOptions object is also used to specify any requested scaling or subsetting + * using options->fSampleSize and options->fSubset. If NULL, the defaults (as specified above + * for AndroidOptions) are used. + * + * @return Result kSuccess, or another value explaining the type of failure. + */ + // FIXME: It's a bit redundant to name this getAndroidPixels() when this class is already + // called SkAndroidCodec. On the other hand, it's may be a bit confusing to call + // this getPixels() when it is a slightly different API than SkCodec's getPixels(). + // Maybe this should be decode() or decodeSubset()? + SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const AndroidOptions* options); + + /** + * Simplified version of getAndroidPixels() where we supply the default AndroidOptions as + * specified above for AndroidOptions. It will not perform any scaling or subsetting. + */ + SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes); + + SkCodec::Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { + return this->getAndroidPixels(info, pixels, rowBytes); + } + + SkCodec* codec() const { return fCodec.get(); } + + /** + * Retrieve the gainmap for an image. + * + * @param outInfo On success, this is populated with the parameters for + * rendering this gainmap. This parameter must be non-nullptr. + * + * @param outGainmapImageStream On success, this is populated with a stream from which the + * gainmap image may be decoded. This parameter is optional, and + * may be set to nullptr. + * + * @return If this has a gainmap image and that gainmap image was + * successfully extracted then return true. Otherwise return + * false. + */ + bool getAndroidGainmap(SkGainmapInfo* outInfo, + std::unique_ptr* outGainmapImageStream); + +protected: + SkAndroidCodec(SkCodec*); + + virtual SkISize onGetSampledDimensions(int sampleSize) const = 0; + + virtual bool onGetSupportedSubset(SkIRect* desiredSubset) const = 0; + + virtual SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels, + size_t rowBytes, const AndroidOptions& options) = 0; + +private: + const SkImageInfo fInfo; + std::unique_ptr fCodec; +}; +#endif // SkAndroidCodec_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkCodec.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkCodec.h new file mode 100644 index 00000000000000..3ed1a95a800c99 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkCodec.h @@ -0,0 +1,1015 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCodec_DEFINED +#define SkCodec_DEFINED + +#include "include/codec/SkEncodedOrigin.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/core/SkYUVAPixmaps.h" +#include "include/private/SkEncodedInfo.h" +#include "include/private/base/SkNoncopyable.h" +#include "modules/skcms/skcms.h" + +#include +#include +#include +#include +#include + +class SkData; +class SkFrameHolder; +class SkImage; +class SkPngChunkReader; +class SkSampler; +class SkStream; +struct SkGainmapInfo; +enum SkAlphaType : int; +enum class SkEncodedImageFormat; + +namespace SkCodecAnimation { +enum class Blend; +enum class DisposalMethod; +} + + +namespace DM { +class CodecSrc; +} // namespace DM + +/** + * Abstraction layer directly on top of an image codec. + */ +class SK_API SkCodec : SkNoncopyable { +public: + /** + * Minimum number of bytes that must be buffered in SkStream input. + * + * An SkStream passed to NewFromStream must be able to use this many + * bytes to determine the image type. Then the same SkStream must be + * passed to the correct decoder to read from the beginning. + * + * This can be accomplished by implementing peek() to support peeking + * this many bytes, or by implementing rewind() to be able to rewind() + * after reading this many bytes. + */ + static constexpr size_t MinBufferedBytesNeeded() { return 32; } + + /** + * Error codes for various SkCodec methods. + */ + enum Result { + /** + * General return value for success. + */ + kSuccess, + /** + * The input is incomplete. A partial image was generated. + */ + kIncompleteInput, + /** + * Like kIncompleteInput, except the input had an error. + * + * If returned from an incremental decode, decoding cannot continue, + * even with more data. + */ + kErrorInInput, + /** + * The generator cannot convert to match the request, ignoring + * dimensions. + */ + kInvalidConversion, + /** + * The generator cannot scale to requested size. + */ + kInvalidScale, + /** + * Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes + * too small, etc. + */ + kInvalidParameters, + /** + * The input did not contain a valid image. + */ + kInvalidInput, + /** + * Fulfilling this request requires rewinding the input, which is not + * supported for this input. + */ + kCouldNotRewind, + /** + * An internal error, such as OOM. + */ + kInternalError, + /** + * This method is not implemented by this codec. + * FIXME: Perhaps this should be kUnsupported? + */ + kUnimplemented, + }; + + /** + * Readable string representing the error code. + */ + static const char* ResultToString(Result); + + /** + * For container formats that contain both still images and image sequences, + * instruct the decoder how the output should be selected. (Refer to comments + * for each value for more details.) + */ + enum class SelectionPolicy { + /** + * If the container format contains both still images and image sequences, + * SkCodec should choose one of the still images. This is the default. + */ + kPreferStillImage, + /** + * If the container format contains both still images and image sequences, + * SkCodec should choose one of the image sequences for animation. + */ + kPreferAnimation, + }; + + /** + * If this stream represents an encoded image that we know how to decode, + * return an SkCodec that can decode it. Otherwise return NULL. + * + * As stated above, this call must be able to peek or read + * MinBufferedBytesNeeded to determine the correct format, and then start + * reading from the beginning. First it will attempt to peek, and it + * assumes that if less than MinBufferedBytesNeeded bytes (but more than + * zero) are returned, this is because the stream is shorter than this, + * so falling back to reading would not provide more data. If peek() + * returns zero bytes, this call will instead attempt to read(). This + * will require that the stream can be rewind()ed. + * + * If Result is not NULL, it will be set to either kSuccess if an SkCodec + * is returned or a reason for the failure if NULL is returned. + * + * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if + * the image is a png. + * + * If the SkPngChunkReader is not NULL then: + * If the image is not a PNG, the SkPngChunkReader will be ignored. + * If the image is a PNG, the SkPngChunkReader will be reffed. + * If the PNG has unknown chunks, the SkPngChunkReader will be used + * to handle these chunks. SkPngChunkReader will be called to read + * any unknown chunk at any point during the creation of the codec + * or the decode. Note that if SkPngChunkReader fails to read a + * chunk, this could result in a failure to create the codec or a + * failure to decode the image. + * If the PNG does not contain unknown chunks, the SkPngChunkReader + * will not be used or modified. + * + * If NULL is returned, the stream is deleted immediately. Otherwise, the + * SkCodec takes ownership of it, and will delete it when done with it. + */ + static std::unique_ptr MakeFromStream( + std::unique_ptr, Result* = nullptr, + SkPngChunkReader* = nullptr, + SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage); + + /** + * If this data represents an encoded image that we know how to decode, + * return an SkCodec that can decode it. Otherwise return NULL. + * + * If the SkPngChunkReader is not NULL then: + * If the image is not a PNG, the SkPngChunkReader will be ignored. + * If the image is a PNG, the SkPngChunkReader will be reffed. + * If the PNG has unknown chunks, the SkPngChunkReader will be used + * to handle these chunks. SkPngChunkReader will be called to read + * any unknown chunk at any point during the creation of the codec + * or the decode. Note that if SkPngChunkReader fails to read a + * chunk, this could result in a failure to create the codec or a + * failure to decode the image. + * If the PNG does not contain unknown chunks, the SkPngChunkReader + * will not be used or modified. + */ + static std::unique_ptr MakeFromData(sk_sp, SkPngChunkReader* = nullptr); + + virtual ~SkCodec(); + + /** + * Return a reasonable SkImageInfo to decode into. + * + * If the image has an ICC profile that does not map to an SkColorSpace, + * the returned SkImageInfo will use SRGB. + */ + SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); } + + SkISize dimensions() const { return {fEncodedInfo.width(), fEncodedInfo.height()}; } + SkIRect bounds() const { + return SkIRect::MakeWH(fEncodedInfo.width(), fEncodedInfo.height()); + } + + /** + * Return the ICC profile of the encoded data. + */ + const skcms_ICCProfile* getICCProfile() const { + return this->getEncodedInfo().profile(); + } + + /** + * Returns the image orientation stored in the EXIF data. + * If there is no EXIF data, or if we cannot read the EXIF data, returns kTopLeft. + */ + SkEncodedOrigin getOrigin() const { return fOrigin; } + + /** + * Return a size that approximately supports the desired scale factor. + * The codec may not be able to scale efficiently to the exact scale + * factor requested, so return a size that approximates that scale. + * The returned value is the codec's suggestion for the closest valid + * scale that it can natively support + */ + SkISize getScaledDimensions(float desiredScale) const { + // Negative and zero scales are errors. + SkASSERT(desiredScale > 0.0f); + if (desiredScale <= 0.0f) { + return SkISize::Make(0, 0); + } + + // Upscaling is not supported. Return the original size if the client + // requests an upscale. + if (desiredScale >= 1.0f) { + return this->dimensions(); + } + return this->onGetScaledDimensions(desiredScale); + } + + /** + * Return (via desiredSubset) a subset which can decoded from this codec, + * or false if this codec cannot decode subsets or anything similar to + * desiredSubset. + * + * @param desiredSubset In/out parameter. As input, a desired subset of + * the original bounds (as specified by getInfo). If true is returned, + * desiredSubset may have been modified to a subset which is + * supported. Although a particular change may have been made to + * desiredSubset to create something supported, it is possible other + * changes could result in a valid subset. + * If false is returned, desiredSubset's value is undefined. + * @return true if this codec supports decoding desiredSubset (as + * returned, potentially modified) + */ + bool getValidSubset(SkIRect* desiredSubset) const { + return this->onGetValidSubset(desiredSubset); + } + + /** + * Format of the encoded data. + */ + SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } + + /** + * Whether or not the memory passed to getPixels is zero initialized. + */ + enum ZeroInitialized { + /** + * The memory passed to getPixels is zero initialized. The SkCodec + * may take advantage of this by skipping writing zeroes. + */ + kYes_ZeroInitialized, + /** + * The memory passed to getPixels has not been initialized to zero, + * so the SkCodec must write all zeroes to memory. + * + * This is the default. It will be used if no Options struct is used. + */ + kNo_ZeroInitialized, + }; + + /** + * Additional options to pass to getPixels. + */ + struct Options { + Options() + : fZeroInitialized(kNo_ZeroInitialized) + , fSubset(nullptr) + , fFrameIndex(0) + , fPriorFrame(kNoFrame) + {} + + ZeroInitialized fZeroInitialized; + /** + * If not NULL, represents a subset of the original image to decode. + * Must be within the bounds returned by getInfo(). + * If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which + * currently supports subsets), the top and left values must be even. + * + * In getPixels and incremental decode, we will attempt to decode the + * exact rectangular subset specified by fSubset. + * + * In a scanline decode, it does not make sense to specify a subset + * top or subset height, since the client already controls which rows + * to get and which rows to skip. During scanline decodes, we will + * require that the subset top be zero and the subset height be equal + * to the full height. We will, however, use the values of + * subset left and subset width to decode partial scanlines on calls + * to getScanlines(). + */ + const SkIRect* fSubset; + + /** + * The frame to decode. + * + * Only meaningful for multi-frame images. + */ + int fFrameIndex; + + /** + * If not kNoFrame, the dst already contains the prior frame at this index. + * + * Only meaningful for multi-frame images. + * + * If fFrameIndex needs to be blended with a prior frame (as reported by + * getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to + * any non-kRestorePrevious frame in [fRequiredFrame, fFrameIndex) to + * indicate that that frame is already in the dst. Options.fZeroInitialized + * is ignored in this case. + * + * If set to kNoFrame, the codec will decode any necessary required frame(s) first. + */ + int fPriorFrame; + }; + + /** + * Decode into the given pixels, a block of memory of size at + * least (info.fHeight - 1) * rowBytes + (info.fWidth * + * bytesPerPixel) + * + * Repeated calls to this function should give the same results, + * allowing the PixelRef to be immutable. + * + * @param info A description of the format (config, size) + * expected by the caller. This can simply be identical + * to the info returned by getInfo(). + * + * This contract also allows the caller to specify + * different output-configs, which the implementation can + * decide to support or not. + * + * A size that does not match getInfo() implies a request + * to scale. If the generator cannot perform this scale, + * it will return kInvalidScale. + * + * If the info contains a non-null SkColorSpace, the codec + * will perform the appropriate color space transformation. + * + * If the caller passes in the SkColorSpace that maps to the + * ICC profile reported by getICCProfile(), the color space + * transformation is a no-op. + * + * If the caller passes a null SkColorSpace, no color space + * transformation will be done. + * + * If a scanline decode is in progress, scanline mode will end, requiring the client to call + * startScanlineDecode() in order to return to decoding scanlines. + * + * @return Result kSuccess, or another value explaining the type of failure. + */ + Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*); + + /** + * Simplified version of getPixels() that uses the default Options. + */ + Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { + return this->getPixels(info, pixels, rowBytes, nullptr); + } + + Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) { + return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), opts); + } + + /** + * Return an image containing the pixels. + */ + std::tuple, SkCodec::Result> getImage(const SkImageInfo& info, + const Options* opts = nullptr); + std::tuple, SkCodec::Result> getImage(); + + /** + * If decoding to YUV is supported, this returns true. Otherwise, this + * returns false and the caller will ignore output parameter yuvaPixmapInfo. + * + * @param supportedDataTypes Indicates the data type/planar config combinations that are + * supported by the caller. If the generator supports decoding to + * YUV(A), but not as a type in supportedDataTypes, this method + * returns false. + * @param yuvaPixmapInfo Output parameter that specifies the planar configuration, subsampling, + * orientation, chroma siting, plane color types, and row bytes. + */ + bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const; + + /** + * Returns kSuccess, or another value explaining the type of failure. + * This always attempts to perform a full decode. To get the planar + * configuration without decoding use queryYUVAInfo(). + * + * @param yuvaPixmaps Contains preallocated pixmaps configured according to a successful call + * to queryYUVAInfo(). + */ + Result getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps); + + /** + * Prepare for an incremental decode with the specified options. + * + * This may require a rewind. + * + * If kIncompleteInput is returned, may be called again after more data has + * been provided to the source SkStream. + * + * @param dstInfo Info of the destination. If the dimensions do not match + * those of getInfo, this implies a scale. + * @param dst Memory to write to. Needs to be large enough to hold the subset, + * if present, or the full image as described in dstInfo. + * @param options Contains decoding options, including if memory is zero + * initialized and whether to decode a subset. + * @return Enum representing success or reason for failure. + */ + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, + const Options*); + + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) { + return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr); + } + + /** + * Start/continue the incremental decode. + * + * Not valid to call before a call to startIncrementalDecode() returns + * kSuccess. + * + * If kIncompleteInput is returned, may be called again after more data has + * been provided to the source SkStream. + * + * Unlike getPixels and getScanlines, this does not do any filling. This is + * left up to the caller, since they may be skipping lines or continuing the + * decode later. In the latter case, they may choose to initialize all lines + * first, or only initialize the remaining lines after the first call. + * + * @param rowsDecoded Optional output variable returning the total number of + * lines initialized. Only meaningful if this method returns kIncompleteInput. + * Otherwise the implementation may not set it. + * Note that some implementations may have initialized this many rows, but + * not necessarily finished those rows (e.g. interlaced PNG). This may be + * useful for determining what rows the client needs to initialize. + * @return kSuccess if all lines requested in startIncrementalDecode have + * been completely decoded. kIncompleteInput otherwise. + */ + Result incrementalDecode(int* rowsDecoded = nullptr) { + if (!fStartedIncrementalDecode) { + return kInvalidParameters; + } + return this->onIncrementalDecode(rowsDecoded); + } + + /** + * The remaining functions revolve around decoding scanlines. + */ + + /** + * Prepare for a scanline decode with the specified options. + * + * After this call, this class will be ready to decode the first scanline. + * + * This must be called in order to call getScanlines or skipScanlines. + * + * This may require rewinding the stream. + * + * Not all SkCodecs support this. + * + * @param dstInfo Info of the destination. If the dimensions do not match + * those of getInfo, this implies a scale. + * @param options Contains decoding options, including if memory is zero + * initialized. + * @return Enum representing success or reason for failure. + */ + Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options); + + /** + * Simplified version of startScanlineDecode() that uses the default Options. + */ + Result startScanlineDecode(const SkImageInfo& dstInfo) { + return this->startScanlineDecode(dstInfo, nullptr); + } + + /** + * Write the next countLines scanlines into dst. + * + * Not valid to call before calling startScanlineDecode(). + * + * @param dst Must be non-null, and large enough to hold countLines + * scanlines of size rowBytes. + * @param countLines Number of lines to write. + * @param rowBytes Number of bytes per row. Must be large enough to hold + * a scanline based on the SkImageInfo used to create this object. + * @return the number of lines successfully decoded. If this value is + * less than countLines, this will fill the remaining lines with a + * default value. + */ + int getScanlines(void* dst, int countLines, size_t rowBytes); + + /** + * Skip count scanlines. + * + * Not valid to call before calling startScanlineDecode(). + * + * The default version just calls onGetScanlines and discards the dst. + * NOTE: If skipped lines are the only lines with alpha, this default + * will make reallyHasAlpha return true, when it could have returned + * false. + * + * @return true if the scanlines were successfully skipped + * false on failure, possible reasons for failure include: + * An incomplete input image stream. + * Calling this function before calling startScanlineDecode(). + * If countLines is less than zero or so large that it moves + * the current scanline past the end of the image. + */ + bool skipScanlines(int countLines); + + /** + * The order in which rows are output from the scanline decoder is not the + * same for all variations of all image types. This explains the possible + * output row orderings. + */ + enum SkScanlineOrder { + /* + * By far the most common, this indicates that the image can be decoded + * reliably using the scanline decoder, and that rows will be output in + * the logical order. + */ + kTopDown_SkScanlineOrder, + + /* + * This indicates that the scanline decoder reliably outputs rows, but + * they will be returned in reverse order. If the scanline format is + * kBottomUp, the nextScanline() API can be used to determine the actual + * y-coordinate of the next output row, but the client is not forced + * to take advantage of this, given that it's not too tough to keep + * track independently. + * + * For full image decodes, it is safe to get all of the scanlines at + * once, since the decoder will handle inverting the rows as it + * decodes. + * + * For subset decodes and sampling, it is simplest to get and skip + * scanlines one at a time, using the nextScanline() API. It is + * possible to ask for larger chunks at a time, but this should be used + * with caution. As with full image decodes, the decoder will handle + * inverting the requested rows, but rows will still be delivered + * starting from the bottom of the image. + * + * Upside down bmps are an example. + */ + kBottomUp_SkScanlineOrder, + }; + + /** + * An enum representing the order in which scanlines will be returned by + * the scanline decoder. + * + * This is undefined before startScanlineDecode() is called. + */ + SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); } + + /** + * Returns the y-coordinate of the next row to be returned by the scanline + * decoder. + * + * This will equal fCurrScanline, except in the case of strangely + * encoded image types (bottom-up bmps). + * + * Results are undefined when not in scanline decoding mode. + */ + int nextScanline() const { return this->outputScanline(fCurrScanline); } + + /** + * Returns the output y-coordinate of the row that corresponds to an input + * y-coordinate. The input y-coordinate represents where the scanline + * is located in the encoded data. + * + * This will equal inputScanline, except in the case of strangely + * encoded image types (bottom-up bmps, interlaced gifs). + */ + int outputScanline(int inputScanline) const; + + /** + * Return the number of frames in the image. + * + * May require reading through the stream. + */ + int getFrameCount() { + return this->onGetFrameCount(); + } + + // Sentinel value used when a frame index implies "no frame": + // - FrameInfo::fRequiredFrame set to this value means the frame + // is independent. + // - Options::fPriorFrame set to this value means no (relevant) prior frame + // is residing in dst's memory. + static constexpr int kNoFrame = -1; + + // This transitional definition was added in August 2018, and will eventually be removed. +#ifdef SK_LEGACY_SKCODEC_NONE_ENUM + static constexpr int kNone = kNoFrame; +#endif + + /** + * Information about individual frames in a multi-framed image. + */ + struct FrameInfo { + /** + * The frame that this frame needs to be blended with, or + * kNoFrame if this frame is independent (so it can be + * drawn over an uninitialized buffer). + * + * Note that this is the *earliest* frame that can be used + * for blending. Any frame from [fRequiredFrame, i) can be + * used, unless its fDisposalMethod is kRestorePrevious. + */ + int fRequiredFrame; + + /** + * Number of milliseconds to show this frame. + */ + int fDuration; + + /** + * Whether the end marker for this frame is contained in the stream. + * + * Note: this does not guarantee that an attempt to decode will be complete. + * There could be an error in the stream. + */ + bool fFullyReceived; + + /** + * This is conservative; it will still return non-opaque if e.g. a + * color index-based frame has a color with alpha but does not use it. + */ + SkAlphaType fAlphaType; + + /** + * Whether the updated rectangle contains alpha. + * + * This is conservative; it will still be set to true if e.g. a color + * index-based frame has a color with alpha but does not use it. In + * addition, it may be set to true, even if the final frame, after + * blending, is opaque. + */ + bool fHasAlphaWithinBounds; + + /** + * How this frame should be modified before decoding the next one. + */ + SkCodecAnimation::DisposalMethod fDisposalMethod; + + /** + * How this frame should blend with the prior frame. + */ + SkCodecAnimation::Blend fBlend; + + /** + * The rectangle updated by this frame. + * + * It may be empty, if the frame does not change the image. It will + * always be contained by SkCodec::dimensions(). + */ + SkIRect fFrameRect; + }; + + /** + * Return info about a single frame. + * + * Does not read through the stream, so it should be called after + * getFrameCount() to parse any frames that have not already been parsed. + * + * Only supported by animated (multi-frame) codecs. Note that this is a + * property of the codec (the SkCodec subclass), not the image. + * + * To elaborate, some codecs support animation (e.g. GIF). Others do not + * (e.g. BMP). Animated codecs can still represent single frame images. + * Calling getFrameInfo(0, etc) will return true for a single frame GIF + * even if the overall image is not animated (in that the pixels on screen + * do not change over time). When incrementally decoding a GIF image, we + * might only know that there's a single frame *so far*. + * + * For non-animated SkCodec subclasses, it's sufficient but not necessary + * for this method to always return false. + */ + bool getFrameInfo(int index, FrameInfo* info) const { + if (index < 0) { + return false; + } + return this->onGetFrameInfo(index, info); + } + + /** + * Return info about all the frames in the image. + * + * May require reading through the stream to determine info about the + * frames (including the count). + * + * As such, future decoding calls may require a rewind. + * + * This may return an empty vector for non-animated codecs. See the + * getFrameInfo(int, FrameInfo*) comment. + */ + std::vector getFrameInfo(); + + static constexpr int kRepetitionCountInfinite = -1; + + /** + * Return the number of times to repeat, if this image is animated. This number does not + * include the first play through of each frame. For example, a repetition count of 4 means + * that each frame is played 5 times and then the animation stops. + * + * It can return kRepetitionCountInfinite, a negative number, meaning that the animation + * should loop forever. + * + * May require reading the stream to find the repetition count. + * + * As such, future decoding calls may require a rewind. + * + * For still (non-animated) image codecs, this will return 0. + */ + int getRepetitionCount() { + return this->onGetRepetitionCount(); + } + + // Register a decoder at runtime by passing two function pointers: + // - peek() to return true if the span of bytes appears to be your encoded format; + // - make() to attempt to create an SkCodec from the given stream. + // Not thread safe. + static void Register( + bool (*peek)(const void*, size_t), + std::unique_ptr (*make)(std::unique_ptr, SkCodec::Result*)); + +protected: + const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; } + + using XformFormat = skcms_PixelFormat; + + SkCodec(SkEncodedInfo&&, + XformFormat srcFormat, + std::unique_ptr, + SkEncodedOrigin = kTopLeft_SkEncodedOrigin); + + void setSrcXformFormat(XformFormat pixelFormat); + + XformFormat getSrcXformFormat() const { + return fSrcXformFormat; + } + + virtual bool onGetGainmapInfo(SkGainmapInfo*, std::unique_ptr*) { return false; } + + virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const { + // By default, scaling is not supported. + return this->dimensions(); + } + + // FIXME: What to do about subsets?? + /** + * Subclasses should override if they support dimensions other than the + * srcInfo's. + */ + virtual bool onDimensionsSupported(const SkISize&) { + return false; + } + + virtual SkEncodedImageFormat onGetEncodedFormat() const = 0; + + /** + * @param rowsDecoded When the encoded image stream is incomplete, this function + * will return kIncompleteInput and rowsDecoded will be set to + * the number of scanlines that were successfully decoded. + * This will allow getPixels() to fill the uninitialized memory. + */ + virtual Result onGetPixels(const SkImageInfo& info, + void* pixels, size_t rowBytes, const Options&, + int* rowsDecoded) = 0; + + virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const { return false; } + + virtual Result onGetYUVAPlanes(const SkYUVAPixmaps&) { return kUnimplemented; } + + virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const { + // By default, subsets are not supported. + return false; + } + + /** + * If the stream was previously read, attempt to rewind. + * + * If the stream needed to be rewound, call onRewind. + * @returns true if the codec is at the right position and can be used. + * false if there was a failure to rewind. + * + * This is called by getPixels(), getYUV8Planes(), startIncrementalDecode() and + * startScanlineDecode(). Subclasses may call if they need to rewind at another time. + */ + bool SK_WARN_UNUSED_RESULT rewindIfNeeded(); + + /** + * Called by rewindIfNeeded, if the stream needed to be rewound. + * + * Subclasses should do any set up needed after a rewind. + */ + virtual bool onRewind() { + return true; + } + + /** + * Get method for the input stream + */ + SkStream* stream() { + return fStream.get(); + } + + /** + * The remaining functions revolve around decoding scanlines. + */ + + /** + * Most images types will be kTopDown and will not need to override this function. + */ + virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; } + + const SkImageInfo& dstInfo() const { return fDstInfo; } + + const Options& options() const { return fOptions; } + + /** + * Returns the number of scanlines that have been decoded so far. + * This is unaffected by the SkScanlineOrder. + * + * Returns -1 if we have not started a scanline decode. + */ + int currScanline() const { return fCurrScanline; } + + virtual int onOutputScanline(int inputScanline) const; + + /** + * Return whether we can convert to dst. + * + * Will be called for the appropriate frame, prior to initializing the colorXform. + */ + virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, + bool needsColorXform); + + // Some classes never need a colorXform e.g. + // - ICO uses its embedded codec's colorXform + // - WBMP is just Black/White + virtual bool usesColorXform() const { return true; } + void applyColorXform(void* dst, const void* src, int count) const; + + bool colorXform() const { return fXformTime != kNo_XformTime; } + bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; } + + virtual int onGetFrameCount() { + return 1; + } + + virtual bool onGetFrameInfo(int, FrameInfo*) const { + return false; + } + + virtual int onGetRepetitionCount() { + return 0; + } + +private: + const SkEncodedInfo fEncodedInfo; + XformFormat fSrcXformFormat; + std::unique_ptr fStream; + bool fNeedsRewind = false; + const SkEncodedOrigin fOrigin; + + SkImageInfo fDstInfo; + Options fOptions; + + enum XformTime { + kNo_XformTime, + kPalette_XformTime, + kDecodeRow_XformTime, + }; + XformTime fXformTime; + XformFormat fDstXformFormat; // Based on fDstInfo. + skcms_ICCProfile fDstProfile; + skcms_AlphaFormat fDstXformAlphaFormat; + + // Only meaningful during scanline decodes. + int fCurrScanline = -1; + + bool fStartedIncrementalDecode = false; + + // Allows SkAndroidCodec to call handleFrameIndex (potentially decoding a prior frame and + // clearing to transparent) without SkCodec itself calling it, too. + bool fUsingCallbackForHandleFrameIndex = false; + + bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque); + + /** + * Return whether these dimensions are supported as a scale. + * + * The codec may choose to cache the information about scale and subset. + * Either way, the same information will be passed to onGetPixels/onStart + * on success. + * + * This must return true for a size returned from getScaledDimensions. + */ + bool dimensionsSupported(const SkISize& dim) { + return dim == this->dimensions() || this->onDimensionsSupported(dim); + } + + /** + * For multi-framed images, return the object with information about the frames. + */ + virtual const SkFrameHolder* getFrameHolder() const { + return nullptr; + } + + // Callback for decoding a prior frame. The `Options::fFrameIndex` is ignored, + // being replaced by frameIndex. This allows opts to actually be a subclass of + // SkCodec::Options which SkCodec itself does not know how to copy or modify, + // but just passes through to the caller (where it can be reinterpret_cast'd). + using GetPixelsCallback = std::function; + + /** + * Check for a valid Options.fFrameIndex, and decode prior frames if necessary. + * + * If GetPixelsCallback is not null, it will be used to decode a prior frame instead + * of using this SkCodec directly. It may also be used recursively, if that in turn + * depends on a prior frame. This is used by SkAndroidCodec. + */ + Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&, + GetPixelsCallback = nullptr); + + // Methods for scanline decoding. + virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/, + const Options& /*options*/) { + return kUnimplemented; + } + + virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, + const Options&) { + return kUnimplemented; + } + + virtual Result onIncrementalDecode(int*) { + return kUnimplemented; + } + + + virtual bool onSkipScanlines(int /*countLines*/) { return false; } + + virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; } + + /** + * On an incomplete decode, getPixels() and getScanlines() will call this function + * to fill any uinitialized memory. + * + * @param dstInfo Contains the destination color type + * Contains the destination alpha type + * Contains the destination width + * The height stored in this info is unused + * @param dst Pointer to the start of destination pixel memory + * @param rowBytes Stride length in destination pixel memory + * @param zeroInit Indicates if memory is zero initialized + * @param linesRequested Number of lines that the client requested + * @param linesDecoded Number of lines that were successfully decoded + */ + void fillIncompleteImage(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, + ZeroInitialized zeroInit, int linesRequested, int linesDecoded); + + /** + * Return an object which will allow forcing scanline decodes to sample in X. + * + * May create a sampler, if one is not currently being used. Otherwise, does + * not affect ownership. + * + * Only valid during scanline decoding or incremental decoding. + */ + virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } + + friend class DM::CodecSrc; // for fillIncompleteImage + friend class SkSampledCodec; + friend class SkIcoCodec; + friend class SkAndroidCodec; // for fEncodedInfo +}; +#endif // SkCodec_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkCodecAnimation.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkCodecAnimation.h new file mode 100644 index 00000000000000..c5883e2af2c094 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkCodecAnimation.h @@ -0,0 +1,61 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCodecAnimation_DEFINED +#define SkCodecAnimation_DEFINED + +namespace SkCodecAnimation { + /** + * This specifies how the next frame is based on this frame. + * + * Names are based on the GIF 89a spec. + * + * The numbers correspond to values in a GIF. + */ + enum class DisposalMethod { + /** + * The next frame should be drawn on top of this one. + * + * In a GIF, a value of 0 (not specified) is also treated as Keep. + */ + kKeep = 1, + + /** + * Similar to Keep, except the area inside this frame's rectangle + * should be cleared to the BackGround color (transparent) before + * drawing the next frame. + */ + kRestoreBGColor = 2, + + /** + * The next frame should be drawn on top of the previous frame - i.e. + * disregarding this one. + * + * In a GIF, a value of 4 is also treated as RestorePrevious. + */ + kRestorePrevious = 3, + }; + + /** + * How to blend the current frame. + */ + enum class Blend { + /** + * Blend with the prior frame as if using SkBlendMode::kSrcOver. + */ + kSrcOver, + + /** + * Blend with the prior frame as if using SkBlendMode::kSrc. + * + * This frame's pixels replace the destination pixels. + */ + kSrc, + }; + +} // namespace SkCodecAnimation +#endif // SkCodecAnimation_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkEncodedImageFormat.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkEncodedImageFormat.h new file mode 100644 index 00000000000000..99ca44e765c53c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkEncodedImageFormat.h @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEncodedImageFormat_DEFINED +#define SkEncodedImageFormat_DEFINED + +#include + +/** + * Enum describing format of encoded data. + */ +enum class SkEncodedImageFormat { +#ifdef SK_BUILD_FOR_GOOGLE3 + kUnknown, +#endif + kBMP, + kGIF, + kICO, + kJPEG, + kPNG, + kWBMP, + kWEBP, + kPKM, + kKTX, + kASTC, + kDNG, + kHEIF, + kAVIF, + kJPEGXL, +}; + +#endif // SkEncodedImageFormat_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkEncodedOrigin.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkEncodedOrigin.h new file mode 100644 index 00000000000000..19d083672f6b97 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkEncodedOrigin.h @@ -0,0 +1,54 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEncodedOrigin_DEFINED +#define SkEncodedOrigin_DEFINED + +#include "include/core/SkMatrix.h" + +// These values match the orientation www.exif.org/Exif2-2.PDF. +enum SkEncodedOrigin { + kTopLeft_SkEncodedOrigin = 1, // Default + kTopRight_SkEncodedOrigin = 2, // Reflected across y-axis + kBottomRight_SkEncodedOrigin = 3, // Rotated 180 + kBottomLeft_SkEncodedOrigin = 4, // Reflected across x-axis + kLeftTop_SkEncodedOrigin = 5, // Reflected across x-axis, Rotated 90 CCW + kRightTop_SkEncodedOrigin = 6, // Rotated 90 CW + kRightBottom_SkEncodedOrigin = 7, // Reflected across x-axis, Rotated 90 CW + kLeftBottom_SkEncodedOrigin = 8, // Rotated 90 CCW + kDefault_SkEncodedOrigin = kTopLeft_SkEncodedOrigin, + kLast_SkEncodedOrigin = kLeftBottom_SkEncodedOrigin, +}; + +/** + * Given an encoded origin and the width and height of the source data, returns a matrix + * that transforms the source rectangle with upper left corner at [0, 0] and origin to a correctly + * oriented destination rectangle of [0, 0, w, h]. + */ +static inline SkMatrix SkEncodedOriginToMatrix(SkEncodedOrigin origin, int w, int h) { + switch (origin) { + case kTopLeft_SkEncodedOrigin: return SkMatrix::I(); + case kTopRight_SkEncodedOrigin: return SkMatrix::MakeAll(-1, 0, w, 0, 1, 0, 0, 0, 1); + case kBottomRight_SkEncodedOrigin: return SkMatrix::MakeAll(-1, 0, w, 0, -1, h, 0, 0, 1); + case kBottomLeft_SkEncodedOrigin: return SkMatrix::MakeAll( 1, 0, 0, 0, -1, h, 0, 0, 1); + case kLeftTop_SkEncodedOrigin: return SkMatrix::MakeAll( 0, 1, 0, 1, 0, 0, 0, 0, 1); + case kRightTop_SkEncodedOrigin: return SkMatrix::MakeAll( 0, -1, w, 1, 0, 0, 0, 0, 1); + case kRightBottom_SkEncodedOrigin: return SkMatrix::MakeAll( 0, -1, w, -1, 0, h, 0, 0, 1); + case kLeftBottom_SkEncodedOrigin: return SkMatrix::MakeAll( 0, 1, 0, -1, 0, h, 0, 0, 1); + } + SK_ABORT("Unexpected origin"); +} + +/** + * Return true if the encoded origin includes a 90 degree rotation, in which case the width + * and height of the source data are swapped relative to a correctly oriented destination. + */ +static inline bool SkEncodedOriginSwapsWidthHeight(SkEncodedOrigin origin) { + return origin >= kLeftTop_SkEncodedOrigin; +} + +#endif // SkEncodedOrigin_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkPixmapUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkPixmapUtils.h new file mode 100644 index 00000000000000..0df4a36f0c2476 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkPixmapUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPixmapUtils_DEFINED +#define SkPixmapUtils_DEFINED + +#include "include/codec/SkEncodedOrigin.h" +#include "include/core/SkImageInfo.h" +#include "include/private/base/SkAPI.h" + +class SkPixmap; + +namespace SkPixmapUtils { +/** + * Copy the pixels in src into dst, applying the orientation transformations specified + * by origin. If the inputs are invalid, this returns false and no copy is made. + */ +SK_API bool Orient(const SkPixmap& dst, const SkPixmap& src, SkEncodedOrigin origin); + +/** + * Return a copy of the provided ImageInfo with the width and height swapped. + */ +SK_API SkImageInfo SwapWidthHeight(const SkImageInfo& info); + +} // namespace SkPixmapUtils + +#endif // SkPixmapUtils_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkPngChunkReader.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkPngChunkReader.h new file mode 100644 index 00000000000000..0ee8a9ecc7275b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/codec/SkPngChunkReader.h @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPngChunkReader_DEFINED +#define SkPngChunkReader_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +/** + * SkPngChunkReader + * + * Base class for optional callbacks to retrieve meta/chunk data out of a PNG + * encoded image as it is being decoded. + * Used by SkCodec. + */ +class SkPngChunkReader : public SkRefCnt { +public: + /** + * This will be called by the decoder when it sees an unknown chunk. + * + * Use by SkCodec: + * Depending on the location of the unknown chunks, this callback may be + * called by + * - the factory (NewFromStream/NewFromData) + * - getPixels + * - startScanlineDecode + * - the first call to getScanlines/skipScanlines + * The callback may be called from a different thread (e.g. if the SkCodec + * is passed to another thread), and it may be called multiple times, if + * the SkCodec is used multiple times. + * + * @param tag Name for this type of chunk. + * @param data Data to be interpreted by the subclass. + * @param length Number of bytes of data in the chunk. + * @return true to continue decoding, or false to indicate an error, which + * will cause the decoder to not return the image. + */ + virtual bool readChunk(const char tag[], const void* data, size_t length) = 0; +}; +#endif // SkPngChunkReader_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/config/SkUserConfig.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/config/SkUserConfig.h new file mode 100644 index 00000000000000..74c21f9438b9ec --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/config/SkUserConfig.h @@ -0,0 +1,121 @@ +/* + * 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 SkUserConfig_DEFINED +#define SkUserConfig_DEFINED + +/* SkTypes.h, the root of the public header files, includes this file + SkUserConfig.h after first initializing certain Skia defines, letting + this file change or augment those flags. + + Below are optional defines that add, subtract, or change default behavior + in Skia. Your port can locally edit this file to enable/disable flags as + you choose, or these can be declared on your command line (i.e. -Dfoo). + + By default, this #include file will always default to having all the flags + commented out, so including it will have no effect. +*/ + +/////////////////////////////////////////////////////////////////////////////// + +/* Skia has lots of debug-only code. Often this is just null checks or other + parameter checking, but sometimes it can be quite intrusive (e.g. check that + each 32bit pixel is in premultiplied form). This code can be very useful + during development, but will slow things down in a shipping product. + + By default, these mutually exclusive flags are defined in SkTypes.h, + based on the presence or absence of NDEBUG, but that decision can be changed + here. +*/ +//#define SK_DEBUG +//#define SK_RELEASE + +/* To write debug messages to a console, skia will call SkDebugf(...) following + printf conventions (e.g. const char* format, ...). If you want to redirect + this to something other than printf, define yours here +*/ +//#define SkDebugf(...) MyFunction(__VA_ARGS__) + +/* Skia has both debug and release asserts. When an assert fails SK_ABORT will + be used to report an abort message. SK_ABORT is expected not to return. Skia + provides a default implementation which will print the message with SkDebugf + and then call sk_abort_no_print. +*/ +//#define SK_ABORT(message, ...) + +/* To specify a different default font strike cache memory limit, define this. If this is + undefined, skia will use a built-in value. +*/ +//#define SK_DEFAULT_FONT_CACHE_LIMIT (1024 * 1024) + +/* To specify a different default font strike cache count limit, define this. If this is + undefined, skia will use a built-in value. +*/ +// #define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048 + +/* To specify the default size of the image cache, undefine this and set it to + the desired value (in bytes). SkGraphics.h as a runtime API to set this + value as well. If this is undefined, a built-in value will be used. +*/ +//#define SK_DEFAULT_IMAGE_CACHE_LIMIT (1024 * 1024) + +/* Define this to set the upper limit for text to support LCD. Values that + are very large increase the cost in the font cache and draw slower, without + improving readability. If this is undefined, Skia will use its default + value (e.g. 48) +*/ +//#define SK_MAX_SIZE_FOR_LCDTEXT 48 + +/* Change the kN32_SkColorType ordering to BGRA to work in X windows. +*/ +//#define SK_R32_SHIFT 16 + +/* Determines whether to build code that supports the Ganesh GPU backend. Some classes + that are not GPU-specific, such as SkShader subclasses, have optional code + that is used allows them to interact with this GPU backend. If you'd like to + include this code, include -DSK_GANESH in your cflags or uncomment below. + Defaults to not set (No Ganesh GPU backend). + This define affects the ABI of Skia, so make sure it matches the client which uses + the compiled version of Skia. +*/ +//#define SK_GANESH + +/* Skia makes use of histogram logging macros to trace the frequency of + events. By default, Skia provides no-op versions of these macros. + Skia consumers can provide their own definitions of these macros to + integrate with their histogram collection backend. +*/ +//#define SK_HISTOGRAM_BOOLEAN(name, sample) +//#define SK_HISTOGRAM_ENUMERATION(name, sample, enum_size) +//#define SK_HISTOGRAM_EXACT_LINEAR(name, sample, value_max) +//#define SK_HISTOGRAM_MEMORY_KB(name, sample) + +/* Skia tries to make use of some non-standard C++ language extensions. + By default, Skia provides msvc and clang/gcc versions of these macros. + Skia consumers can provide their own definitions of these macros to + integrate with their own compilers and build system. +*/ +//#define SK_UNUSED [[maybe_unused]] +//#define SK_WARN_UNUSED_RESULT [[nodiscard]] +//#define SK_ALWAYS_INLINE inline __attribute__((always_inline)) +//#define SK_NEVER_INLINE __attribute__((noinline)) +//#define SK_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B)))) +//#define SK_NO_SANITIZE(A) __attribute__((no_sanitize(A))) +//#define SK_TRIVIAL_ABI [[clang::trivial_abi]] + +/* + * If compiling Skia as a DLL, public APIs should be exported. Skia will set + * SK_API to something sensible for Clang and MSVC, but if clients need to + * customize it for their build system or compiler, they may. + * If a client needs to use SK_API (e.g. overriding SK_ABORT), then they + * *must* define their own, the default will not be defined prior to loading + * this file. + */ +//#define SK_API __declspec(dllexport) + + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkAlphaType.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkAlphaType.h new file mode 100644 index 00000000000000..0c99906dfd54bc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkAlphaType.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAlphaType_DEFINED +#define SkAlphaType_DEFINED + +/** \enum SkAlphaType + Describes how to interpret the alpha component of a pixel. A pixel may + be opaque, or alpha, describing multiple levels of transparency. + + In simple blending, alpha weights the draw color and the destination + color to create a new color. If alpha describes a weight from zero to one: + + new color = draw color * alpha + destination color * (1 - alpha) + + In practice alpha is encoded in two or more bits, where 1.0 equals all bits set. + + RGB may have alpha included in each component value; the stored + value is the original RGB multiplied by alpha. Premultiplied color + components improve performance. +*/ +enum SkAlphaType : int { + kUnknown_SkAlphaType, //!< uninitialized + kOpaque_SkAlphaType, //!< pixel is opaque + kPremul_SkAlphaType, //!< pixel components are premultiplied by alpha + kUnpremul_SkAlphaType, //!< pixel components are independent of alpha + kLastEnum_SkAlphaType = kUnpremul_SkAlphaType, //!< last valid value +}; + +/** Returns true if SkAlphaType equals kOpaque_SkAlphaType. + + kOpaque_SkAlphaType is a hint that the SkColorType is opaque, or that all + alpha values are set to their 1.0 equivalent. If SkAlphaType is + kOpaque_SkAlphaType, and SkColorType is not opaque, then the result of + drawing any pixel with a alpha value less than 1.0 is undefined. +*/ +static inline bool SkAlphaTypeIsOpaque(SkAlphaType at) { + return kOpaque_SkAlphaType == at; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkAnnotation.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkAnnotation.h new file mode 100644 index 00000000000000..2006f309e9428d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkAnnotation.h @@ -0,0 +1,52 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAnnotation_DEFINED +#define SkAnnotation_DEFINED + +#include "include/core/SkTypes.h" + +class SkData; +struct SkPoint; +struct SkRect; +class SkCanvas; + +/** + * Annotate the canvas by associating the specified URL with the + * specified rectangle (in local coordinates, just like drawRect). + * + * The URL is expected to be escaped and be valid 7-bit ASCII. + * + * If the backend of this canvas does not support annotations, this call is + * safely ignored. + * + * The caller is responsible for managing its ownership of the SkData. + */ +SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*); + +/** + * Annotate the canvas by associating a name with the specified point. + * + * If the backend of this canvas does not support annotations, this call is + * safely ignored. + * + * The caller is responsible for managing its ownership of the SkData. + */ +SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*); + +/** + * Annotate the canvas by making the specified rectangle link to a named + * destination. + * + * If the backend of this canvas does not support annotations, this call is + * safely ignored. + * + * The caller is responsible for managing its ownership of the SkData. + */ +SK_API void SkAnnotateLinkToDestination(SkCanvas*, const SkRect&, SkData*); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBBHFactory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBBHFactory.h new file mode 100644 index 00000000000000..2507d0f15073ab --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBBHFactory.h @@ -0,0 +1,63 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBBHFactory_DEFINED +#define SkBBHFactory_DEFINED + +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include + +class SkBBoxHierarchy : public SkRefCnt { +public: + struct Metadata { + bool isDraw; // The corresponding SkRect bounds a draw command, not a pure state change. + }; + + /** + * Insert N bounding boxes into the hierarchy. + */ + virtual void insert(const SkRect[], int N) = 0; + virtual void insert(const SkRect[], const Metadata[], int N); + + /** + * Populate results with the indices of bounding boxes intersecting that query. + */ + virtual void search(const SkRect& query, std::vector* results) const = 0; + + /** + * Return approximate size in memory of *this. + */ + virtual size_t bytesUsed() const = 0; + +protected: + SkBBoxHierarchy() = default; + SkBBoxHierarchy(const SkBBoxHierarchy&) = delete; + SkBBoxHierarchy& operator=(const SkBBoxHierarchy&) = delete; +}; + +class SK_API SkBBHFactory { +public: + /** + * Allocate a new SkBBoxHierarchy. Return NULL on failure. + */ + virtual sk_sp operator()() const = 0; + virtual ~SkBBHFactory() {} + +protected: + SkBBHFactory() = default; + SkBBHFactory(const SkBBHFactory&) = delete; + SkBBHFactory& operator=(const SkBBHFactory&) = delete; +}; + +class SK_API SkRTreeFactory : public SkBBHFactory { +public: + sk_sp operator()() const override; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBitmap.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBitmap.h new file mode 100644 index 00000000000000..d4ed7a6000b7a1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBitmap.h @@ -0,0 +1,1265 @@ +/* + * 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 SkBitmap_DEFINED +#define SkBitmap_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkColor.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" +#include "include/private/base/SkDebug.h" + +#include +#include + +class SkColorSpace; +class SkImage; +class SkMatrix; +class SkMipmap; +class SkPaint; +class SkPixelRef; +class SkShader; +enum SkColorType : int; +enum class SkTileMode; +struct SkMask; + +/** \class SkBitmap + SkBitmap describes a two-dimensional raster pixel array. SkBitmap is built on + SkImageInfo, containing integer width and height, SkColorType and SkAlphaType + describing the pixel format, and SkColorSpace describing the range of colors. + SkBitmap points to SkPixelRef, which describes the physical array of pixels. + SkImageInfo bounds may be located anywhere fully inside SkPixelRef bounds. + + SkBitmap can be drawn using SkCanvas. SkBitmap can be a drawing destination for SkCanvas + draw member functions. SkBitmap flexibility as a pixel container limits some + optimizations available to the target platform. + + If pixel array is primarily read-only, use SkImage for better performance. + If pixel array is primarily written to, use SkSurface for better performance. + + Declaring SkBitmap const prevents altering SkImageInfo: the SkBitmap height, width, + and so on cannot change. It does not affect SkPixelRef: a caller may write its + pixels. Declaring SkBitmap const affects SkBitmap configuration, not its contents. + + SkBitmap is not thread safe. Each thread must have its own copy of SkBitmap fields, + although threads may share the underlying pixel array. +*/ +class SK_API SkBitmap { +public: + class SK_API Allocator; + + /** Creates an empty SkBitmap without pixels, with kUnknown_SkColorType, + kUnknown_SkAlphaType, and with a width and height of zero. SkPixelRef origin is + set to (0, 0). + + Use setInfo() to associate SkColorType, SkAlphaType, width, and height + after SkBitmap has been created. + + @return empty SkBitmap + + example: https://fiddle.skia.org/c/@Bitmap_empty_constructor + */ + SkBitmap(); + + /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels + allocated, so both bitmaps reference the same pixels. + + @param src SkBitmap to copy SkImageInfo, and share SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_copy_const_SkBitmap + */ + SkBitmap(const SkBitmap& src); + + /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to + SkBitmap. + + @param src SkBitmap to copy SkImageInfo, and reassign SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_move_SkBitmap + */ + SkBitmap(SkBitmap&& src); + + /** Decrements SkPixelRef reference count, if SkPixelRef is not nullptr. + */ + ~SkBitmap(); + + /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels + allocated, so both bitmaps reference the same pixels. + + @param src SkBitmap to copy SkImageInfo, and share SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_copy_operator + */ + SkBitmap& operator=(const SkBitmap& src); + + /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to + SkBitmap. + + @param src SkBitmap to copy SkImageInfo, and reassign SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_move_operator + */ + SkBitmap& operator=(SkBitmap&& src); + + /** Swaps the fields of the two bitmaps. + + @param other SkBitmap exchanged with original + + example: https://fiddle.skia.org/c/@Bitmap_swap + */ + void swap(SkBitmap& other); + + /** Returns a constant reference to the SkPixmap holding the SkBitmap pixel + address, row bytes, and SkImageInfo. + + @return reference to SkPixmap describing this SkBitmap + */ + const SkPixmap& pixmap() const { return fPixmap; } + + /** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace. + + @return reference to SkImageInfo + */ + const SkImageInfo& info() const { return fPixmap.info(); } + + /** Returns pixel count in each row. Should be equal or less than + rowBytes() / info().bytesPerPixel(). + + May be less than pixelRef().width(). Will not exceed pixelRef().width() less + pixelRefOrigin().fX. + + @return pixel width in SkImageInfo + */ + int width() const { return fPixmap.width(); } + + /** Returns pixel row count. + + Maybe be less than pixelRef().height(). Will not exceed pixelRef().height() less + pixelRefOrigin().fY. + + @return pixel height in SkImageInfo + */ + int height() const { return fPixmap.height(); } + + SkColorType colorType() const { return fPixmap.colorType(); } + + SkAlphaType alphaType() const { return fPixmap.alphaType(); } + + /** Returns SkColorSpace, the range of colors, associated with SkImageInfo. The + reference count of SkColorSpace is unchanged. The returned SkColorSpace is + immutable. + + @return SkColorSpace in SkImageInfo, or nullptr + */ + SkColorSpace* colorSpace() const; + + /** Returns smart pointer to SkColorSpace, the range of colors, associated with + SkImageInfo. The smart pointer tracks the number of objects sharing this + SkColorSpace reference so the memory is released when the owners destruct. + + The returned SkColorSpace is immutable. + + @return SkColorSpace in SkImageInfo wrapped in a smart pointer + */ + sk_sp refColorSpace() const; + + /** Returns number of bytes per pixel required by SkColorType. + Returns zero if colorType( is kUnknown_SkColorType. + + @return bytes in pixel + */ + int bytesPerPixel() const { return fPixmap.info().bytesPerPixel(); } + + /** Returns number of pixels that fit on row. Should be greater than or equal to + width(). + + @return maximum pixels per row + */ + int rowBytesAsPixels() const { return fPixmap.rowBytesAsPixels(); } + + /** Returns bit shift converting row bytes to row pixels. + Returns zero for kUnknown_SkColorType. + + @return one of: 0, 1, 2, 3; left shift to convert pixels to bytes + */ + int shiftPerPixel() const { return fPixmap.shiftPerPixel(); } + + /** Returns true if either width() or height() are zero. + + Does not check if SkPixelRef is nullptr; call drawsNothing() to check width(), + height(), and SkPixelRef. + + @return true if dimensions do not enclose area + */ + bool empty() const { return fPixmap.info().isEmpty(); } + + /** Returns true if SkPixelRef is nullptr. + + Does not check if width() or height() are zero; call drawsNothing() to check + width(), height(), and SkPixelRef. + + @return true if no SkPixelRef is associated + */ + bool isNull() const { return nullptr == fPixelRef; } + + /** Returns true if width() or height() are zero, or if SkPixelRef is nullptr. + If true, SkBitmap has no effect when drawn or drawn into. + + @return true if drawing has no effect + */ + bool drawsNothing() const { + return this->empty() || this->isNull(); + } + + /** Returns row bytes, the interval from one pixel row to the next. Row bytes + is at least as large as: width() * info().bytesPerPixel(). + + Returns zero if colorType() is kUnknown_SkColorType, or if row bytes supplied to + setInfo() is not large enough to hold a row of pixels. + + @return byte length of pixel row + */ + size_t rowBytes() const { return fPixmap.rowBytes(); } + + /** Sets SkAlphaType, if alphaType is compatible with SkColorType. + Returns true unless alphaType is kUnknown_SkAlphaType and current SkAlphaType + is not kUnknown_SkAlphaType. + + Returns true if SkColorType is kUnknown_SkColorType. alphaType is ignored, and + SkAlphaType remains kUnknown_SkAlphaType. + + Returns true if SkColorType is kRGB_565_SkColorType or kGray_8_SkColorType. + alphaType is ignored, and SkAlphaType remains kOpaque_SkAlphaType. + + If SkColorType is kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: returns true unless + alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType. + If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. + + If SkColorType is kAlpha_8_SkColorType, returns true unless + alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType. + If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. If alphaType is + kUnpremul_SkAlphaType, it is treated as kPremul_SkAlphaType. + + This changes SkAlphaType in SkPixelRef; all bitmaps sharing SkPixelRef + are affected. + + @return true if SkAlphaType is set + + example: https://fiddle.skia.org/c/@Bitmap_setAlphaType + */ + bool setAlphaType(SkAlphaType alphaType); + + /** Returns pixel address, the base address corresponding to the pixel origin. + + @return pixel address + */ + void* getPixels() const { return fPixmap.writable_addr(); } + + /** Returns minimum memory required for pixel storage. + Does not include unused memory on last row when rowBytesAsPixels() exceeds width(). + Returns SIZE_MAX if result does not fit in size_t. + Returns zero if height() or width() is 0. + Returns height() times rowBytes() if colorType() is kUnknown_SkColorType. + + @return size in bytes of image buffer + */ + size_t computeByteSize() const { return fPixmap.computeByteSize(); } + + /** Returns true if pixels can not change. + + Most immutable SkBitmap checks trigger an assert only on debug builds. + + @return true if pixels are immutable + + example: https://fiddle.skia.org/c/@Bitmap_isImmutable + */ + bool isImmutable() const; + + /** Sets internal flag to mark SkBitmap as immutable. Once set, pixels can not change. + Any other bitmap sharing the same SkPixelRef are also marked as immutable. + Once SkPixelRef is marked immutable, the setting cannot be cleared. + + Writing to immutable SkBitmap pixels triggers an assert on debug builds. + + example: https://fiddle.skia.org/c/@Bitmap_setImmutable + */ + void setImmutable(); + + /** Returns true if SkAlphaType is set to hint that all pixels are opaque; their + alpha value is implicitly or explicitly 1.0. If true, and all pixels are + not opaque, Skia may draw incorrectly. + + Does not check if SkColorType allows alpha, or if any pixel value has + transparency. + + @return true if SkImageInfo SkAlphaType is kOpaque_SkAlphaType + */ + bool isOpaque() const { + return SkAlphaTypeIsOpaque(this->alphaType()); + } + + /** Resets to its initial state; all fields are set to zero, as if SkBitmap had + been initialized by SkBitmap(). + + Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to + kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType. + + If SkPixelRef is allocated, its reference count is decreased by one, releasing + its memory if SkBitmap is the sole owner. + + example: https://fiddle.skia.org/c/@Bitmap_reset + */ + void reset(); + + /** Returns true if all pixels are opaque. SkColorType determines how pixels + are encoded, and whether pixel describes alpha. Returns true for SkColorType + without alpha in each pixel; for other SkColorType, returns true if all + pixels have alpha values equivalent to 1.0 or greater. + + For SkColorType kRGB_565_SkColorType or kGray_8_SkColorType: always + returns true. For SkColorType kAlpha_8_SkColorType, kBGRA_8888_SkColorType, + kRGBA_8888_SkColorType: returns true if all pixel alpha values are 255. + For SkColorType kARGB_4444_SkColorType: returns true if all pixel alpha values are 15. + For kRGBA_F16_SkColorType: returns true if all pixel alpha values are 1.0 or + greater. + + Returns false for kUnknown_SkColorType. + + @param bm SkBitmap to check + @return true if all pixels have opaque values or SkColorType is opaque + */ + static bool ComputeIsOpaque(const SkBitmap& bm) { + return bm.pixmap().computeIsOpaque(); + } + + /** Returns SkRect { 0, 0, width(), height() }. + + @param bounds container for floating point rectangle + + example: https://fiddle.skia.org/c/@Bitmap_getBounds + */ + void getBounds(SkRect* bounds) const; + + /** Returns SkIRect { 0, 0, width(), height() }. + + @param bounds container for integral rectangle + + example: https://fiddle.skia.org/c/@Bitmap_getBounds_2 + */ + void getBounds(SkIRect* bounds) const; + + /** Returns SkIRect { 0, 0, width(), height() }. + + @return integral rectangle from origin to width() and height() + */ + SkIRect bounds() const { return fPixmap.info().bounds(); } + + /** Returns SkISize { width(), height() }. + + @return integral size of width() and height() + */ + SkISize dimensions() const { return fPixmap.info().dimensions(); } + + /** Returns the bounds of this bitmap, offset by its SkPixelRef origin. + + @return bounds within SkPixelRef bounds + */ + SkIRect getSubset() const { + SkIPoint origin = this->pixelRefOrigin(); + return SkIRect::MakeXYWH(origin.x(), origin.y(), this->width(), this->height()); + } + + /** Sets width, height, SkAlphaType, SkColorType, SkColorSpace, and optional + rowBytes. Frees pixels, and returns true if successful. + + imageInfo.alphaType() may be altered to a value permitted by imageInfo.colorSpace(). + If imageInfo.colorType() is kUnknown_SkColorType, imageInfo.alphaType() is + set to kUnknown_SkAlphaType. + If imageInfo.colorType() is kAlpha_8_SkColorType and imageInfo.alphaType() is + kUnpremul_SkAlphaType, imageInfo.alphaType() is replaced by kPremul_SkAlphaType. + If imageInfo.colorType() is kRGB_565_SkColorType or kGray_8_SkColorType, + imageInfo.alphaType() is set to kOpaque_SkAlphaType. + If imageInfo.colorType() is kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: imageInfo.alphaType() remains + unchanged. + + rowBytes must equal or exceed imageInfo.minRowBytes(). If imageInfo.colorSpace() is + kUnknown_SkColorType, rowBytes is ignored and treated as zero; for all other + SkColorSpace values, rowBytes of zero is treated as imageInfo.minRowBytes(). + + Calls reset() and returns false if: + - rowBytes exceeds 31 bits + - imageInfo.width() is negative + - imageInfo.height() is negative + - rowBytes is positive and less than imageInfo.width() times imageInfo.bytesPerPixel() + + @param imageInfo contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes imageInfo.minRowBytes() or larger; or zero + @return true if SkImageInfo set successfully + + example: https://fiddle.skia.org/c/@Bitmap_setInfo + */ + bool setInfo(const SkImageInfo& imageInfo, size_t rowBytes = 0); + + /** \enum SkBitmap::AllocFlags + AllocFlags is obsolete. We always zero pixel memory when allocated. + */ + enum AllocFlags { + kZeroPixels_AllocFlag = 1 << 0, //!< zero pixel memory. No effect. This is the default. + }; + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. Memory is zeroed. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated, or memory could not optionally be zeroed. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of calloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param flags kZeroPixels_AllocFlag, or zero + @return true if pixels allocation is successful + */ + bool SK_WARN_UNUSED_RESULT tryAllocPixelsFlags(const SkImageInfo& info, uint32_t flags); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. Memory is zeroed. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated, or memory could not optionally + be zeroed. Abort steps may be provided by the user at compile time by defining + SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of calloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param flags kZeroPixels_AllocFlag, or zero + + example: https://fiddle.skia.org/c/@Bitmap_allocPixelsFlags + */ + void allocPixelsFlags(const SkImageInfo& info, uint32_t flags); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(), + or equal zero. Pass in zero for rowBytes to compute the minimum valid value. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes size of pixel row or larger; may be zero + @return true if pixel storage is allocated + */ + bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info, size_t rowBytes); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(), + or equal zero. Pass in zero for rowBytes to compute the minimum valid value. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes size of pixel row or larger; may be zero + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels + */ + void allocPixels(const SkImageInfo& info, size_t rowBytes); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @return true if pixel storage is allocated + */ + bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info) { + return this->tryAllocPixels(info, info.minRowBytes()); + } + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels_2 + */ + void allocPixels(const SkImageInfo& info); + + /** Sets SkImageInfo to width, height, and native color type; and allocates + pixel memory. If isOpaque is true, sets SkImageInfo to kOpaque_SkAlphaType; + otherwise, sets to kPremul_SkAlphaType. + + Calls reset() and returns false if width exceeds 29 bits or is negative, + or height is negative. + + Returns false if allocation fails. + + Use to create SkBitmap that matches SkPMColor, the native pixel arrangement on + the platform. SkBitmap drawn to output device skips converting its pixel format. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param isOpaque true if pixels do not have transparency + @return true if pixel storage is allocated + */ + bool SK_WARN_UNUSED_RESULT tryAllocN32Pixels(int width, int height, bool isOpaque = false); + + /** Sets SkImageInfo to width, height, and the native color type; and allocates + pixel memory. If isOpaque is true, sets SkImageInfo to kOpaque_SkAlphaType; + otherwise, sets to kPremul_SkAlphaType. + + Aborts if width exceeds 29 bits or is negative, or height is negative, or + allocation fails. Abort steps may be provided by the user at compile time by + defining SK_ABORT. + + Use to create SkBitmap that matches SkPMColor, the native pixel arrangement on + the platform. SkBitmap drawn to output device skips converting its pixel format. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param isOpaque true if pixels do not have transparency + + example: https://fiddle.skia.org/c/@Bitmap_allocN32Pixels + */ + void allocN32Pixels(int width, int height, bool isOpaque = false); + + /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef + containing pixels and rowBytes. releaseProc, if not nullptr, is called + immediately on failure or when pixels are no longer referenced. context may be + nullptr. + + If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes(): + calls releaseProc if present, calls reset(), and returns false. + + Otherwise, if pixels equals nullptr: sets SkImageInfo, calls releaseProc if + present, returns true. + + If SkImageInfo is set, pixels is not nullptr, and releaseProc is not nullptr: + when pixels are no longer referenced, calls releaseProc with pixels and context + as parameters. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage; may be nullptr + @param rowBytes size of pixel row or larger + @param releaseProc function called when pixels can be deleted; may be nullptr + @param context caller state passed to releaseProc; may be nullptr + @return true if SkImageInfo is set to info + */ + bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + void (*releaseProc)(void* addr, void* context), void* context); + + /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef + containing pixels and rowBytes. + + If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes(): + calls reset(), and returns false. + + Otherwise, if pixels equals nullptr: sets SkImageInfo, returns true. + + Caller must ensure that pixels are valid for the lifetime of SkBitmap and SkPixelRef. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage; may be nullptr + @param rowBytes size of pixel row or larger + @return true if SkImageInfo is set to info + */ + bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { + return this->installPixels(info, pixels, rowBytes, nullptr, nullptr); + } + + /** Sets SkImageInfo to pixmap.info() following the rules in setInfo(), and creates + SkPixelRef containing pixmap.addr() and pixmap.rowBytes(). + + If SkImageInfo could not be set, or pixmap.rowBytes() is less than + SkImageInfo::minRowBytes(): calls reset(), and returns false. + + Otherwise, if pixmap.addr() equals nullptr: sets SkImageInfo, returns true. + + Caller must ensure that pixmap is valid for the lifetime of SkBitmap and SkPixelRef. + + @param pixmap SkImageInfo, pixel address, and rowBytes() + @return true if SkImageInfo was set to pixmap.info() + + example: https://fiddle.skia.org/c/@Bitmap_installPixels_3 + */ + bool installPixels(const SkPixmap& pixmap); + + /** Deprecated. + */ + bool installMaskPixels(const SkMask& mask); + + /** Replaces SkPixelRef with pixels, preserving SkImageInfo and rowBytes(). + Sets SkPixelRef origin to (0, 0). + + If pixels is nullptr, or if info().colorType() equals kUnknown_SkColorType; + release reference to SkPixelRef, and set SkPixelRef to nullptr. + + Caller is responsible for handling ownership pixel memory for the lifetime + of SkBitmap and SkPixelRef. + + @param pixels address of pixel storage, managed by caller + + example: https://fiddle.skia.org/c/@Bitmap_setPixels + */ + void setPixels(void* pixels); + + /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + + Returns false if info().colorType() is kUnknown_SkColorType, or allocation fails. + + @return true if the allocation succeeds + */ + bool SK_WARN_UNUSED_RESULT tryAllocPixels() { + return this->tryAllocPixels((Allocator*)nullptr); + } + + /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + + Aborts if info().colorType() is kUnknown_SkColorType, or allocation fails. + Abort steps may be provided by the user at compile + time by defining SK_ABORT. + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels_3 + */ + void allocPixels(); + + /** Allocates pixel memory with allocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + If allocator is nullptr, use HeapAllocator instead. + + Returns false if Allocator::allocPixelRef return false. + + @param allocator instance of SkBitmap::Allocator instantiation + @return true if custom allocator reports success + */ + bool SK_WARN_UNUSED_RESULT tryAllocPixels(Allocator* allocator); + + /** Allocates pixel memory with allocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + If allocator is nullptr, use HeapAllocator instead. + + Aborts if Allocator::allocPixelRef return false. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + @param allocator instance of SkBitmap::Allocator instantiation + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels_4 + */ + void allocPixels(Allocator* allocator); + + /** Returns SkPixelRef, which contains: pixel base address; its dimensions; and + rowBytes(), the interval from one row to the next. Does not change SkPixelRef + reference count. SkPixelRef may be shared by multiple bitmaps. + If SkPixelRef has not been set, returns nullptr. + + @return SkPixelRef, or nullptr + */ + SkPixelRef* pixelRef() const { return fPixelRef.get(); } + + /** Returns origin of pixels within SkPixelRef. SkBitmap bounds is always contained + by SkPixelRef bounds, which may be the same size or larger. Multiple SkBitmap + can share the same SkPixelRef, where each SkBitmap has different bounds. + + The returned origin added to SkBitmap dimensions equals or is smaller than the + SkPixelRef dimensions. + + Returns (0, 0) if SkPixelRef is nullptr. + + @return pixel origin within SkPixelRef + + example: https://fiddle.skia.org/c/@Bitmap_pixelRefOrigin + */ + SkIPoint pixelRefOrigin() const; + + /** Replaces pixelRef and origin in SkBitmap. dx and dy specify the offset + within the SkPixelRef pixels for the top-left corner of the bitmap. + + Asserts in debug builds if dx or dy are out of range. Pins dx and dy + to legal range in release builds. + + The caller is responsible for ensuring that the pixels match the + SkColorType and SkAlphaType in SkImageInfo. + + @param pixelRef SkPixelRef describing pixel address and rowBytes() + @param dx column offset in SkPixelRef for bitmap origin + @param dy row offset in SkPixelRef for bitmap origin + + example: https://fiddle.skia.org/c/@Bitmap_setPixelRef + */ + void setPixelRef(sk_sp pixelRef, int dx, int dy); + + /** Returns true if SkBitmap is can be drawn. + + @return true if getPixels() is not nullptr + */ + bool readyToDraw() const { + return this->getPixels() != nullptr; + } + + /** Returns a unique value corresponding to the pixels in SkPixelRef. + Returns a different value after notifyPixelsChanged() has been called. + Returns zero if SkPixelRef is nullptr. + + Determines if pixels have changed since last examined. + + @return unique value for pixels in SkPixelRef + + example: https://fiddle.skia.org/c/@Bitmap_getGenerationID + */ + uint32_t getGenerationID() const; + + /** Marks that pixels in SkPixelRef have changed. Subsequent calls to + getGenerationID() return a different value. + + example: https://fiddle.skia.org/c/@Bitmap_notifyPixelsChanged + */ + void notifyPixelsChanged() const; + + /** Replaces pixel values with c, interpreted as being in the sRGB SkColorSpace. + All pixels contained by bounds() are affected. If the colorType() is + kGray_8_SkColorType or kRGB_565_SkColorType, then alpha is ignored; RGB is + treated as opaque. If colorType() is kAlpha_8_SkColorType, then RGB is ignored. + + @param c unpremultiplied color + + example: https://fiddle.skia.org/c/@Bitmap_eraseColor + */ + void eraseColor(SkColor4f) const; + + /** Replaces pixel values with c, interpreted as being in the sRGB SkColorSpace. + All pixels contained by bounds() are affected. If the colorType() is + kGray_8_SkColorType or kRGB_565_SkColorType, then alpha is ignored; RGB is + treated as opaque. If colorType() is kAlpha_8_SkColorType, then RGB is ignored. + + Input color is ultimately converted to an SkColor4f, so eraseColor(SkColor4f c) + will have higher color resolution. + + @param c unpremultiplied color. + + example: https://fiddle.skia.org/c/@Bitmap_eraseColor + */ + void eraseColor(SkColor c) const; + + /** Replaces pixel values with unpremultiplied color built from a, r, g, and b, + interpreted as being in the sRGB SkColorSpace. All pixels contained by + bounds() are affected. If the colorType() is kGray_8_SkColorType or + kRGB_565_SkColorType, then a is ignored; r, g, and b are treated as opaque. + If colorType() is kAlpha_8_SkColorType, then r, g, and b are ignored. + + @param a amount of alpha, from fully transparent (0) to fully opaque (255) + @param r amount of red, from no red (0) to full red (255) + @param g amount of green, from no green (0) to full green (255) + @param b amount of blue, from no blue (0) to full blue (255) + */ + void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { + this->eraseColor(SkColorSetARGB(a, r, g, b)); + } + + /** Replaces pixel values inside area with c. interpreted as being in the sRGB + SkColorSpace. If area does not intersect bounds(), call has no effect. + + If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then alpha + is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType, + then RGB is ignored. + + @param c unpremultiplied color + @param area rectangle to fill + + example: https://fiddle.skia.org/c/@Bitmap_erase + */ + void erase(SkColor4f c, const SkIRect& area) const; + + /** Replaces pixel values inside area with c. interpreted as being in the sRGB + SkColorSpace. If area does not intersect bounds(), call has no effect. + + If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then alpha + is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType, + then RGB is ignored. + + Input color is ultimately converted to an SkColor4f, so erase(SkColor4f c) + will have higher color resolution. + + @param c unpremultiplied color + @param area rectangle to fill + + example: https://fiddle.skia.org/c/@Bitmap_erase + */ + void erase(SkColor c, const SkIRect& area) const; + + /** Deprecated. + */ + void eraseArea(const SkIRect& area, SkColor c) const { + this->erase(c, area); + } + + /** Returns pixel at (x, y) as unpremultiplied color. + Returns black with alpha if SkColorType is kAlpha_8_SkColorType. + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined; and returns undefined values or may crash if + SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or + pixel address is nullptr. + + SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the + conversion to unpremultiplied color; original pixel data may have additional + precision. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return pixel converted to unpremultiplied color + */ + SkColor getColor(int x, int y) const { + return this->pixmap().getColor(x, y); + } + + /** Returns pixel at (x, y) as unpremultiplied float color. + Returns black with alpha if SkColorType is kAlpha_8_SkColorType. + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined; and returns undefined values or may crash if + SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or + pixel address is nullptr. + + SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the + conversion to unpremultiplied color. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return pixel converted to unpremultiplied color + */ + SkColor4f getColor4f(int x, int y) const { return this->pixmap().getColor4f(x, y); } + + /** Look up the pixel at (x,y) and return its alpha component, normalized to [0..1]. + This is roughly equivalent to SkGetColorA(getColor()), but can be more efficent + (and more precise if the pixels store more than 8 bits per component). + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return alpha converted to normalized float + */ + float getAlphaf(int x, int y) const { + return this->pixmap().getAlphaf(x, y); + } + + /** Returns pixel address at (x, y). + + Input is not validated: out of bounds values of x or y, or kUnknown_SkColorType, + trigger an assert() if built with SK_DEBUG defined. Returns nullptr if + SkColorType is kUnknown_SkColorType, or SkPixelRef is nullptr. + + Performs a lookup of pixel size; for better performance, call + one of: getAddr8(), getAddr16(), or getAddr32(). + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return generic pointer to pixel + + example: https://fiddle.skia.org/c/@Bitmap_getAddr + */ + void* getAddr(int x, int y) const; + + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not four + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 32-bit pointer to pixel at (x, y) + */ + inline uint32_t* getAddr32(int x, int y) const; + + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not two + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 16-bit pointer to pixel at (x, y) + */ + inline uint16_t* getAddr16(int x, int y) const; + + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not one + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 8-bit pointer to pixel at (x, y) + */ + inline uint8_t* getAddr8(int x, int y) const; + + /** Shares SkPixelRef with dst. Pixels are not copied; SkBitmap and dst point + to the same pixels; dst bounds() are set to the intersection of subset + and the original bounds(). + + subset may be larger than bounds(). Any area outside of bounds() is ignored. + + Any contents of dst are discarded. + + Return false if: + - dst is nullptr + - SkPixelRef is nullptr + - subset does not intersect bounds() + + @param dst SkBitmap set to subset + @param subset rectangle of pixels to reference + @return true if dst is replaced by subset + + example: https://fiddle.skia.org/c/@Bitmap_extractSubset + */ + bool extractSubset(SkBitmap* dst, const SkIRect& subset) const; + + /** Copies a SkRect of pixels from SkBitmap to dstPixels. Copy starts at (srcX, srcY), + and does not exceed SkBitmap (width(), height()). + + dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of + destination. dstRowBytes specifics the gap from one destination row to the next. + Returns true if pixels are copied. Returns false if: + - dstInfo has no address + - dstRowBytes is less than dstInfo.minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If SkBitmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If SkBitmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= Bitmap width(), or if abs(srcY) >= Bitmap height(). + + @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace + @param dstPixels destination pixel storage + @param dstRowBytes destination row length + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @return true if pixels are copied to dstPixels + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY) const; + + /** Copies a SkRect of pixels from SkBitmap to dst. Copy starts at (srcX, srcY), and + does not exceed SkBitmap (width(), height()). + + dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of destination. dst.rowBytes() specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dst pixel storage equals nullptr + - dst.rowBytes is less than SkImageInfo::minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= Bitmap width(), or if abs(srcY) >= Bitmap height(). + + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @return true if pixels are copied to dst + + example: https://fiddle.skia.org/c/@Bitmap_readPixels_2 + */ + bool readPixels(const SkPixmap& dst, int srcX, int srcY) const; + + /** Copies a SkRect of pixels from SkBitmap to dst. Copy starts at (0, 0), and + does not exceed SkBitmap (width(), height()). + + dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of destination. dst.rowBytes() specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dst pixel storage equals nullptr + - dst.rowBytes is less than SkImageInfo::minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @return true if pixels are copied to dst + */ + bool readPixels(const SkPixmap& dst) const { + return this->readPixels(dst, 0, 0); + } + + /** Copies a SkRect of pixels from src. Copy starts at (dstX, dstY), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. + + dstX and dstY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(dstX) >= Bitmap width(), or if abs(dstY) >= Bitmap height(). + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @param dstX column index whose absolute value is less than width() + @param dstY row index whose absolute value is less than height() + @return true if src pixels are copied to SkBitmap + + example: https://fiddle.skia.org/c/@Bitmap_writePixels + */ + bool writePixels(const SkPixmap& src, int dstX, int dstY); + + /** Copies a SkRect of pixels from src. Copy starts at (0, 0), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @return true if src pixels are copied to SkBitmap + */ + bool writePixels(const SkPixmap& src) { + return this->writePixels(src, 0, 0); + } + + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + Uses HeapAllocator to reserve memory for dst SkPixelRef. + + @param dst holds SkPixelRef to fill with alpha layer + @return true if alpha layer was constructed in dst SkPixelRef + */ + bool extractAlpha(SkBitmap* dst) const { + return this->extractAlpha(dst, nullptr, nullptr, nullptr); + } + + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + If paint is not nullptr and contains SkMaskFilter, SkMaskFilter + generates mask alpha from SkBitmap. Uses HeapAllocator to reserve memory for dst + SkPixelRef. Sets offset to top-left position for dst for alignment with SkBitmap; + (0, 0) unless SkMaskFilter generates mask. + + @param dst holds SkPixelRef to fill with alpha layer + @param paint holds optional SkMaskFilter; may be nullptr + @param offset top-left position for dst; may be nullptr + @return true if alpha layer was constructed in dst SkPixelRef + */ + bool extractAlpha(SkBitmap* dst, const SkPaint* paint, + SkIPoint* offset) const { + return this->extractAlpha(dst, paint, nullptr, offset); + } + + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + If paint is not nullptr and contains SkMaskFilter, SkMaskFilter + generates mask alpha from SkBitmap. allocator may reference a custom allocation + class or be set to nullptr to use HeapAllocator. Sets offset to top-left + position for dst for alignment with SkBitmap; (0, 0) unless SkMaskFilter generates + mask. + + @param dst holds SkPixelRef to fill with alpha layer + @param paint holds optional SkMaskFilter; may be nullptr + @param allocator function to reserve memory for SkPixelRef; may be nullptr + @param offset top-left position for dst; may be nullptr + @return true if alpha layer was constructed in dst SkPixelRef + */ + bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator, + SkIPoint* offset) const; + + /** Copies SkBitmap pixel address, row bytes, and SkImageInfo to pixmap, if address + is available, and returns true. If pixel address is not available, return + false and leave pixmap unchanged. + + pixmap contents become invalid on any future change to SkBitmap. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkBitmap has direct access to pixels + + example: https://fiddle.skia.org/c/@Bitmap_peekPixels + */ + bool peekPixels(SkPixmap* pixmap) const; + + /** + * Make a shader with the specified tiling, matrix and sampling. + */ + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling, + const SkMatrix& lm) const; + /** Defaults to clamp in both X and Y. */ + sk_sp makeShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const; + sk_sp makeShader(const SkSamplingOptions& sampling, + const SkMatrix* lm = nullptr) const; + + /** + * Returns a new image from the bitmap. If the bitmap is marked immutable, this will + * share the pixel buffer. If not, it will make a copy of the pixels for the image. + */ + sk_sp asImage() const; + + /** Asserts if internal values are illegal or inconsistent. Only available if + SK_DEBUG is defined at compile time. + */ + SkDEBUGCODE(void validate() const;) + + /** \class SkBitmap::Allocator + Abstract subclass of HeapAllocator. + */ + class Allocator : public SkRefCnt { + public: + + /** Allocates the pixel memory for the bitmap, given its dimensions and + SkColorType. Returns true on success, where success means either setPixels() + or setPixelRef() was called. + + @param bitmap SkBitmap containing SkImageInfo as input, and SkPixelRef as output + @return true if SkPixelRef was allocated + */ + virtual bool allocPixelRef(SkBitmap* bitmap) = 0; + private: + using INHERITED = SkRefCnt; + }; + + /** \class SkBitmap::HeapAllocator + Subclass of SkBitmap::Allocator that returns a SkPixelRef that allocates its pixel + memory from the heap. This is the default SkBitmap::Allocator invoked by + allocPixels(). + */ + class HeapAllocator : public Allocator { + public: + + /** Allocates the pixel memory for the bitmap, given its dimensions and + SkColorType. Returns true on success, where success means either setPixels() + or setPixelRef() was called. + + @param bitmap SkBitmap containing SkImageInfo as input, and SkPixelRef as output + @return true if pixels are allocated + + example: https://fiddle.skia.org/c/@Bitmap_HeapAllocator_allocPixelRef + */ + bool allocPixelRef(SkBitmap* bitmap) override; + }; + +private: + sk_sp fPixelRef; + SkPixmap fPixmap; + sk_sp fMips; + + friend class SkImage_Raster; + friend class SkReadBuffer; // unflatten + friend class GrProxyProvider; // fMips +}; + +/////////////////////////////////////////////////////////////////////////////// + +inline uint32_t* SkBitmap::getAddr32(int x, int y) const { + SkASSERT(fPixmap.addr()); + return fPixmap.writable_addr32(x, y); +} + +inline uint16_t* SkBitmap::getAddr16(int x, int y) const { + SkASSERT(fPixmap.addr()); + return fPixmap.writable_addr16(x, y); +} + +inline uint8_t* SkBitmap::getAddr8(int x, int y) const { + SkASSERT(fPixmap.addr()); + return fPixmap.writable_addr8(x, y); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlendMode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlendMode.h new file mode 100644 index 00000000000000..4abe9157620f93 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlendMode.h @@ -0,0 +1,112 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlendMode_DEFINED +#define SkBlendMode_DEFINED + +#include "include/core/SkTypes.h" + +/** + * Blends are operators that take in two colors (source, destination) and return a new color. + * Many of these operate the same on all 4 components: red, green, blue, alpha. For these, + * we just document what happens to one component, rather than naming each one separately. + * + * Different SkColorTypes have different representations for color components: + * 8-bit: 0..255 + * 6-bit: 0..63 + * 5-bit: 0..31 + * 4-bit: 0..15 + * floats: 0...1 + * + * The documentation is expressed as if the component values are always 0..1 (floats). + * + * For brevity, the documentation uses the following abbreviations + * s : source + * d : destination + * sa : source alpha + * da : destination alpha + * + * Results are abbreviated + * r : if all 4 components are computed in the same manner + * ra : result alpha component + * rc : result "color": red, green, blue components + */ +enum class SkBlendMode { + kClear, //!< r = 0 + kSrc, //!< r = s + kDst, //!< r = d + kSrcOver, //!< r = s + (1-sa)*d + kDstOver, //!< r = d + (1-da)*s + kSrcIn, //!< r = s * da + kDstIn, //!< r = d * sa + kSrcOut, //!< r = s * (1-da) + kDstOut, //!< r = d * (1-sa) + kSrcATop, //!< r = s*da + d*(1-sa) + kDstATop, //!< r = d*sa + s*(1-da) + kXor, //!< r = s*(1-da) + d*(1-sa) + kPlus, //!< r = min(s + d, 1) + kModulate, //!< r = s*d + kScreen, //!< r = s + d - s*d + + kOverlay, //!< multiply or screen, depending on destination + kDarken, //!< rc = s + d - max(s*da, d*sa), ra = kSrcOver + kLighten, //!< rc = s + d - min(s*da, d*sa), ra = kSrcOver + kColorDodge, //!< brighten destination to reflect source + kColorBurn, //!< darken destination to reflect source + kHardLight, //!< multiply or screen, depending on source + kSoftLight, //!< lighten or darken, depending on source + kDifference, //!< rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver + kExclusion, //!< rc = s + d - two(s*d), ra = kSrcOver + kMultiply, //!< r = s*(1-da) + d*(1-sa) + s*d + + kHue, //!< hue of source with saturation and luminosity of destination + kSaturation, //!< saturation of source with hue and luminosity of destination + kColor, //!< hue and saturation of source with luminosity of destination + kLuminosity, //!< luminosity of source with hue and saturation of destination + + kLastCoeffMode = kScreen, //!< last porter duff blend mode + kLastSeparableMode = kMultiply, //!< last blend mode operating separately on components + kLastMode = kLuminosity, //!< last valid value +}; + +static constexpr int kSkBlendModeCount = static_cast(SkBlendMode::kLastMode) + 1; + +/** + * For Porter-Duff SkBlendModes (those <= kLastCoeffMode), these coefficients describe the blend + * equation used. Coefficient-based blend modes specify an equation: + * ('dstCoeff' * dst + 'srcCoeff' * src), where the coefficient values are constants, functions of + * the src or dst alpha, or functions of the src or dst color. + */ +enum class SkBlendModeCoeff { + kZero, /** 0 */ + kOne, /** 1 */ + kSC, /** src color */ + kISC, /** inverse src color (i.e. 1 - sc) */ + kDC, /** dst color */ + kIDC, /** inverse dst color (i.e. 1 - dc) */ + kSA, /** src alpha */ + kISA, /** inverse src alpha (i.e. 1 - sa) */ + kDA, /** dst alpha */ + kIDA, /** inverse dst alpha (i.e. 1 - da) */ + + kCoeffCount +}; + +/** + * Returns true if 'mode' is a coefficient-based blend mode (<= kLastCoeffMode). If true is + * returned, the mode's src and dst coefficient functions are set in 'src' and 'dst'. + */ +SK_API bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst); + + +/** Returns name of blendMode as null-terminated C string. + + @return C string +*/ +SK_API const char* SkBlendMode_Name(SkBlendMode blendMode); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlender.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlender.h new file mode 100644 index 00000000000000..7acba87f52adea --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlender.h @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlender_DEFINED +#define SkBlender_DEFINED + +#include "include/core/SkBlendMode.h" +#include "include/core/SkFlattenable.h" + +/** + * SkBlender represents a custom blend function in the Skia pipeline. When an SkBlender is + * present in a paint, the SkBlendMode is ignored. A blender combines a source color (the + * result of our paint) and destination color (from the canvas) into a final color. + */ +class SK_API SkBlender : public SkFlattenable { +public: + /** + * Create a blender that implements the specified BlendMode. + */ + static sk_sp Mode(SkBlendMode mode); + +private: + SkBlender() = default; + friend class SkBlenderBase; + + using INHERITED = SkFlattenable; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlurTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlurTypes.h new file mode 100644 index 00000000000000..f0dde10f25c6b1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkBlurTypes.h @@ -0,0 +1,20 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlurTypes_DEFINED +#define SkBlurTypes_DEFINED + +enum SkBlurStyle : int { + kNormal_SkBlurStyle, //!< fuzzy inside and outside + kSolid_SkBlurStyle, //!< solid inside, fuzzy outside + kOuter_SkBlurStyle, //!< nothing inside, fuzzy outside + kInner_SkBlurStyle, //!< fuzzy inside, nothing outside + + kLastEnum_SkBlurStyle = kInner_SkBlurStyle, +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCanvas.h new file mode 100644 index 00000000000000..225b733a6b7179 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCanvas.h @@ -0,0 +1,2632 @@ +/* + * 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 SkCanvas_DEFINED +#define SkCanvas_DEFINED + +#include "include/core/SkBlendMode.h" +#include "include/core/SkClipOp.h" +#include "include/core/SkColor.h" +#include "include/core/SkFontTypes.h" +#include "include/core/SkImageFilter.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkM44.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPaint.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRasterHandleAllocator.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSize.h" +#include "include/core/SkString.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" +#include "include/private/base/SkDeque.h" + +#include +#include +#include +#include + +#ifndef SK_SUPPORT_LEGACY_GETTOTALMATRIX +#define SK_SUPPORT_LEGACY_GETTOTALMATRIX +#endif + +namespace sktext { +class GlyphRunBuilder; +class GlyphRunList; +} + +class AutoLayerForImageFilter; +class GrRecordingContext; + +class SkBaseDevice; +class SkBitmap; +class SkBlender; +class SkData; +class SkDrawable; +class SkFont; +class SkImage; +class SkMesh; +class SkPaintFilterCanvas; +class SkPath; +class SkPicture; +class SkPixmap; +class SkRRect; +class SkRegion; +class SkShader; +class SkSpecialImage; +class SkSurface; +class SkSurface_Base; +class SkTextBlob; +class SkVertices; +struct SkDrawShadowRec; +struct SkRSXform; + +namespace skgpu::graphite { class Recorder; } +namespace sktext::gpu { class Slug; } +namespace SkRecords { class Draw; } + +#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_GANESH) +class GrBackendRenderTarget; +#endif + +// TODO: +// This is not ideal but Chrome is depending on a forward decl of GrSlug here. +// It should be removed once Chrome has migrated to sktext::gpu::Slug. +using GrSlug = sktext::gpu::Slug; + +/** \class SkCanvas + SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed. + SkCanvas contains a stack of SkMatrix and clip values. + + SkCanvas and SkPaint together provide the state to draw into SkSurface or SkBaseDevice. + Each SkCanvas draw call transforms the geometry of the object by the concatenation of all + SkMatrix values in the stack. The transformed geometry is clipped by the intersection + of all of clip values in the stack. The SkCanvas draw calls use SkPaint to supply drawing + state such as color, SkTypeface, text size, stroke width, SkShader and so on. + + To draw to a pixel-based destination, create raster surface or GPU surface. + Request SkCanvas from SkSurface to obtain the interface to draw. + SkCanvas generated by raster surface draws to memory visible to the CPU. + SkCanvas generated by GPU surface uses Vulkan or OpenGL to draw to the GPU. + + To draw to a document, obtain SkCanvas from SVG canvas, document PDF, or SkPictureRecorder. + SkDocument based SkCanvas and other SkCanvas subclasses reference SkBaseDevice describing the + destination. + + SkCanvas can be constructed to draw to SkBitmap without first creating raster surface. + This approach may be deprecated in the future. +*/ +class SK_API SkCanvas { +public: + + /** Allocates raster SkCanvas that will draw directly into pixels. + + SkCanvas is returned if all parameters are valid. + Valid parameters include: + info dimensions are zero or positive; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is zero or large enough to contain info width pixels of SkColorType. + + Pass zero for rowBytes to compute rowBytes from info width and size of pixel. + If rowBytes is greater than zero, it must be equal to or greater than + info width times bytes required for SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + Pixels are not initialized. + To access pixels after drawing, call flush() or peekPixels(). + + @param info width, height, SkColorType, SkAlphaType, SkColorSpace, of raster surface; + width, or height, or both, may be zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next, or zero + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkCanvas if all parameters are valid; otherwise, nullptr + */ + static std::unique_ptr MakeRasterDirect(const SkImageInfo& info, void* pixels, + size_t rowBytes, + const SkSurfaceProps* props = nullptr); + + /** Allocates raster SkCanvas specified by inline image specification. Subsequent SkCanvas + calls draw into pixels. + SkColorType is set to kN32_SkColorType. + SkAlphaType is set to kPremul_SkAlphaType. + To access pixels after drawing, call flush() or peekPixels(). + + SkCanvas is returned if all parameters are valid. + Valid parameters include: + width and height are zero or positive; + pixels is not nullptr; + rowBytes is zero or large enough to contain width pixels of kN32_SkColorType. + + Pass zero for rowBytes to compute rowBytes from width and size of pixel. + If rowBytes is greater than zero, it must be equal to or greater than + width times bytes required for SkColorType. + + Pixel buffer size should be height times rowBytes. + + @param width pixel column count on raster surface created; must be zero or greater + @param height pixel row count on raster surface created; must be zero or greater + @param pixels pointer to destination pixels buffer; buffer size should be height + times rowBytes + @param rowBytes interval from one SkSurface row to the next, or zero + @return SkCanvas if all parameters are valid; otherwise, nullptr + */ + static std::unique_ptr MakeRasterDirectN32(int width, int height, SkPMColor* pixels, + size_t rowBytes) { + return MakeRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); + } + + /** Creates an empty SkCanvas with no backing device or pixels, with + a width and height of zero. + + @return empty SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_empty_constructor + */ + SkCanvas(); + + /** Creates SkCanvas of the specified dimensions without a SkSurface. + Used by subclasses with custom implementations for draw member functions. + + If props equals nullptr, SkSurfaceProps are created with + SkSurfaceProps::InitType settings, which choose the pixel striping + direction and order. Since a platform may dynamically change its direction when + the device is rotated, and since a platform may have multiple monitors with + different characteristics, it is best not to rely on this legacy behavior. + + @param width zero or greater + @param height zero or greater + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkCanvas placeholder with dimensions + + example: https://fiddle.skia.org/c/@Canvas_int_int_const_SkSurfaceProps_star + */ + SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr); + + /** Private. For internal use only. + */ + explicit SkCanvas(sk_sp device); + + /** Constructs a canvas that draws into bitmap. + Sets kUnknown_SkPixelGeometry in constructed SkSurface. + + SkBitmap is copied so that subsequently editing bitmap will not affect + constructed SkCanvas. + + May be deprecated in the future. + + @param bitmap width, height, SkColorType, SkAlphaType, and pixel + storage of raster surface + @return SkCanvas that can be used to draw into bitmap + + example: https://fiddle.skia.org/c/@Canvas_copy_const_SkBitmap + */ + explicit SkCanvas(const SkBitmap& bitmap); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + /** Private. + */ + enum class ColorBehavior { + kLegacy, //!< placeholder + }; + + /** Private. For use by Android framework only. + + @param bitmap specifies a bitmap for the canvas to draw into + @param behavior specializes this constructor; value is unused + @return SkCanvas that can be used to draw into bitmap + */ + SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior); +#endif + + /** Constructs a canvas that draws into bitmap. + Use props to match the device characteristics, like LCD striping. + + bitmap is copied so that subsequently editing bitmap will not affect + constructed SkCanvas. + + @param bitmap width, height, SkColorType, SkAlphaType, + and pixel storage of raster surface + @param props order and orientation of RGB striping; and whether to use + device independent fonts + @return SkCanvas that can be used to draw into bitmap + + example: https://fiddle.skia.org/c/@Canvas_const_SkBitmap_const_SkSurfaceProps + */ + SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props); + + /** Draws saved layers, if any. + Frees up resources used by SkCanvas. + + example: https://fiddle.skia.org/c/@Canvas_destructor + */ + virtual ~SkCanvas(); + + /** Returns SkImageInfo for SkCanvas. If SkCanvas is not associated with raster surface or + GPU surface, returned SkColorType is set to kUnknown_SkColorType. + + @return dimensions and SkColorType of SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_imageInfo + */ + SkImageInfo imageInfo() const; + + /** Copies SkSurfaceProps, if SkCanvas is associated with raster surface or + GPU surface, and returns true. Otherwise, returns false and leave props unchanged. + + @param props storage for writable SkSurfaceProps + @return true if SkSurfaceProps was copied + + DEPRECATED: Replace usage with getBaseProps() or getTopProps() + + example: https://fiddle.skia.org/c/@Canvas_getProps + */ + bool getProps(SkSurfaceProps* props) const; + + /** Returns the SkSurfaceProps associated with the canvas (i.e., at the base of the layer + stack). + + @return base SkSurfaceProps + */ + SkSurfaceProps getBaseProps() const; + + /** Returns the SkSurfaceProps associated with the canvas that are currently active (i.e., at + the top of the layer stack). This can differ from getBaseProps depending on the flags + passed to saveLayer (see SaveLayerFlagsSet). + + @return SkSurfaceProps active in the current/top layer + */ + SkSurfaceProps getTopProps() const; + + /** Triggers the immediate execution of all pending draw operations. + If SkCanvas is associated with GPU surface, resolves all pending GPU operations. + If SkCanvas is associated with raster surface, has no effect; raster draw + operations are never deferred. + + DEPRECATED: Replace usage with GrDirectContext::flush() + */ + void flush(); + + /** Gets the size of the base or root layer in global canvas coordinates. The + origin of the base layer is always (0,0). The area available for drawing may be + smaller (due to clipping or saveLayer). + + @return integral width and height of base layer + + example: https://fiddle.skia.org/c/@Canvas_getBaseLayerSize + */ + virtual SkISize getBaseLayerSize() const; + + /** Creates SkSurface matching info and props, and associates it with SkCanvas. + Returns nullptr if no match found. + + If props is nullptr, matches SkSurfaceProps in SkCanvas. If props is nullptr and SkCanvas + does not have SkSurfaceProps, creates SkSurface with default SkSurfaceProps. + + @param info width, height, SkColorType, SkAlphaType, and SkColorSpace + @param props SkSurfaceProps to match; may be nullptr to match SkCanvas + @return SkSurface matching info and props, or nullptr if no match is available + + example: https://fiddle.skia.org/c/@Canvas_makeSurface + */ + sk_sp makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr); + + /** Returns GPU context of the GPU surface associated with SkCanvas. + + @return GPU context, if available; nullptr otherwise + + example: https://fiddle.skia.org/c/@Canvas_recordingContext + */ + virtual GrRecordingContext* recordingContext(); + + /** Returns Recorder for the GPU surface associated with SkCanvas. + + @return Recorder, if available; nullptr otherwise + */ + virtual skgpu::graphite::Recorder* recorder(); + + /** Sometimes a canvas is owned by a surface. If it is, getSurface() will return a bare + * pointer to that surface, else this will return nullptr. + */ + SkSurface* getSurface() const; + + /** Returns the pixel base address, SkImageInfo, rowBytes, and origin if the pixels + can be read directly. The returned address is only valid + while SkCanvas is in scope and unchanged. Any SkCanvas call or SkSurface call + may invalidate the returned address and other returned values. + + If pixels are inaccessible, info, rowBytes, and origin are unchanged. + + @param info storage for writable pixels' SkImageInfo; may be nullptr + @param rowBytes storage for writable pixels' row bytes; may be nullptr + @param origin storage for SkCanvas top layer origin, its top-left corner; + may be nullptr + @return address of pixels, or nullptr if inaccessible + + example: https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_a + example: https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_b + */ + void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr); + + /** Returns custom context that tracks the SkMatrix and clip. + + Use SkRasterHandleAllocator to blend Skia drawing with custom drawing, typically performed + by the host platform user interface. The custom context returned is generated by + SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for + the drawing destination. + + @return context of custom allocation + + example: https://fiddle.skia.org/c/@Canvas_accessTopRasterHandle + */ + SkRasterHandleAllocator::Handle accessTopRasterHandle() const; + + /** Returns true if SkCanvas has direct access to its pixels. + + Pixels are readable when SkBaseDevice is raster. Pixels are not readable when SkCanvas + is returned from GPU surface, returned by SkDocument::beginPage, returned by + SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility class + like DebugCanvas. + + pixmap is valid only while SkCanvas is in scope and unchanged. Any + SkCanvas or SkSurface call may invalidate the pixmap values. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkCanvas has direct access to pixels + + example: https://fiddle.skia.org/c/@Canvas_peekPixels + */ + bool peekPixels(SkPixmap* pixmap); + + /** Copies SkRect of pixels from SkCanvas into dstPixels. SkMatrix and clip are + ignored. + + Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). + Destination SkRect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dstInfo.colorType() and dstInfo.alphaType() if required. + + Pixels are readable when SkBaseDevice is raster, or backed by a GPU. + Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dstPixels contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkCanvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). + - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. + - dstRowBytes is too small to contain one row of pixels. + + @param dstInfo width, height, SkColorType, and SkAlphaType of dstPixels + @param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger + @param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into pixmap. SkMatrix and clip are + ignored. + + Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). + Destination SkRect corners are (0, 0) and (pixmap.width(), pixmap.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to pixmap.colorType() and pixmap.alphaType() if required. + + Pixels are readable when SkBaseDevice is raster, or backed by a GPU. + Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Caller must allocate pixel storage in pixmap if needed. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination SkRect + are copied. pixmap pixels contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down pixmap. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkCanvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). + - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. + - SkPixmap pixels could not be allocated. + - pixmap.rowBytes() is too small to contain one row of pixels. + + @param pixmap storage for pixels copied from SkCanvas + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Canvas_readPixels_2 + */ + bool readPixels(const SkPixmap& pixmap, int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into bitmap. SkMatrix and clip are + ignored. + + Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to bitmap.colorType() and bitmap.alphaType() if required. + + Pixels are readable when SkBaseDevice is raster, or backed by a GPU. + Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Caller must allocate pixel storage in bitmap if needed. + + SkBitmap values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. SkBitmap pixels outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down bitmap. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkCanvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). + - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. + - bitmap pixels could not be allocated. + - bitmap.rowBytes() is too small to contain one row of pixels. + + @param bitmap storage for pixels copied from SkCanvas + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Canvas_readPixels_3 + */ + bool readPixels(const SkBitmap& bitmap, int srcX, int srcY); + + /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. + Source SkRect corners are (0, 0) and (info.width(), info.height()). + Destination SkRect corners are (x, y) and + (imageInfo().width(), imageInfo().height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to imageInfo().colorType() and imageInfo().alphaType() if required. + + Pixels are writable when SkBaseDevice is raster, or backed by a GPU. + Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. SkCanvas pixels outside SkRect intersection are unchanged. + + Pass negative values for x or y to offset pixels to the left or + above SkCanvas pixels. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - pixels could not be converted to SkCanvas imageInfo().colorType() or + imageInfo().alphaType(). + - SkCanvas pixels are not writable; for instance, SkCanvas is document-based. + - rowBytes is too small to contain one row of pixels. + + @param info width, height, SkColorType, and SkAlphaType of pixels + @param pixels pixels to copy, of size info.height() times rowBytes, or larger + @param rowBytes size of one row of pixels; info.width() times pixel size, or larger + @param x offset into SkCanvas writable pixels on x-axis; may be negative + @param y offset into SkCanvas writable pixels on y-axis; may be negative + @return true if pixels were written to SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_writePixels + */ + bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y); + + /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. + Source SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). + + Destination SkRect corners are (x, y) and + (imageInfo().width(), imageInfo().height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to imageInfo().colorType() and imageInfo().alphaType() if required. + + Pixels are writable when SkBaseDevice is raster, or backed by a GPU. + Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. SkCanvas pixels outside SkRect intersection are unchanged. + + Pass negative values for x or y to offset pixels to the left or + above SkCanvas pixels. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - bitmap does not have allocated pixels. + - bitmap pixels could not be converted to SkCanvas imageInfo().colorType() or + imageInfo().alphaType(). + - SkCanvas pixels are not writable; for instance, SkCanvas is document based. + - bitmap pixels are inaccessible; for instance, bitmap wraps a texture. + + @param bitmap contains pixels copied to SkCanvas + @param x offset into SkCanvas writable pixels on x-axis; may be negative + @param y offset into SkCanvas writable pixels on y-axis; may be negative + @return true if pixels were written to SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_writePixels_2 + example: https://fiddle.skia.org/c/@State_Stack_a + example: https://fiddle.skia.org/c/@State_Stack_b + */ + bool writePixels(const SkBitmap& bitmap, int x, int y); + + /** Saves SkMatrix and clip. + Calling restore() discards changes to SkMatrix and clip, + restoring the SkMatrix and clip to their state when save() was called. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix(), + and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), clipPath(), clipRegion(). + + Saved SkCanvas state is put on a stack; multiple calls to save() should be balance + by an equal number of calls to restore(). + + Call restoreToCount() with result to restore this and subsequent saves. + + @return depth of saved stack + + example: https://fiddle.skia.org/c/@Canvas_save + */ + int save(); + + /** Saves SkMatrix and clip, and allocates a SkSurface for subsequent drawing. + Calling restore() discards changes to SkMatrix and clip, and draws the SkSurface. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the SkSurface size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of the layer; may be nullptr + @param paint graphics state for layer; may be nullptr + @return depth of saved stack + + example: https://fiddle.skia.org/c/@Canvas_saveLayer + example: https://fiddle.skia.org/c/@Canvas_saveLayer_4 + */ + int saveLayer(const SkRect* bounds, const SkPaint* paint); + + /** Saves SkMatrix and clip, and allocates a SkSurface for subsequent drawing. + Calling restore() discards changes to SkMatrix and clip, and draws the SkSurface. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the layer size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of layer; may be nullptr + @param paint graphics state for layer; may be nullptr + @return depth of saved stack + */ + int saveLayer(const SkRect& bounds, const SkPaint* paint) { + return this->saveLayer(&bounds, paint); + } + + /** Saves SkMatrix and clip, and allocates SkSurface for subsequent drawing. + + Calling restore() discards changes to SkMatrix and clip, + and blends layer with alpha opacity onto prior layer. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define layer size. To clip drawing to + a specific rectangle, use clipRect(). + + alpha of zero is fully transparent, 1.0f is fully opaque. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of layer; may be nullptr + @param alpha opacity of layer + @return depth of saved stack + + example: https://fiddle.skia.org/c/@Canvas_saveLayerAlpha + */ + int saveLayerAlphaf(const SkRect* bounds, float alpha); + // Helper that accepts an int between 0 and 255, and divides it by 255.0 + int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { + return this->saveLayerAlphaf(bounds, alpha * (1.0f / 255)); + } + + /** \enum SkCanvas::SaveLayerFlagsSet + SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, + defining how layer allocated by saveLayer() operates. It may be set to zero, + kPreserveLCDText_SaveLayerFlag, kInitWithPrevious_SaveLayerFlag, or both flags. + */ + enum SaveLayerFlagsSet { + kPreserveLCDText_SaveLayerFlag = 1 << 1, + kInitWithPrevious_SaveLayerFlag = 1 << 2, //!< initializes with previous contents + // instead of matching previous layer's colortype, use F16 + kF16ColorType = 1 << 4, + }; + + typedef uint32_t SaveLayerFlags; + + /** \struct SkCanvas::SaveLayerRec + SaveLayerRec contains the state used to create the layer. + */ + struct SaveLayerRec { + /** Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags. + + @return empty SaveLayerRec + */ + SaveLayerRec() {} + + /** Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr. + + @param bounds layer dimensions; may be nullptr + @param paint applied to layer when overlaying prior layer; may be nullptr + @param saveLayerFlags SaveLayerRec options to modify layer + @return SaveLayerRec with empty fBackdrop + */ + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) + : SaveLayerRec(bounds, paint, nullptr, 1.f, saveLayerFlags) {} + + /** Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags. + + @param bounds layer dimensions; may be nullptr + @param paint applied to layer when overlaying prior layer; + may be nullptr + @param backdrop If not null, this causes the current layer to be filtered by + backdrop, and then drawn into the new layer + (respecting the current clip). + If null, the new layer is initialized with transparent-black. + @param saveLayerFlags SaveLayerRec options to modify layer + @return SaveLayerRec fully specified + */ + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + SaveLayerFlags saveLayerFlags) + : SaveLayerRec(bounds, paint, backdrop, 1.f, saveLayerFlags) {} + + /** hints at layer size limit */ + const SkRect* fBounds = nullptr; + + /** modifies overlay */ + const SkPaint* fPaint = nullptr; + + /** + * If not null, this triggers the same initialization behavior as setting + * kInitWithPrevious_SaveLayerFlag on fSaveLayerFlags: the current layer is copied into + * the new layer, rather than initializing the new layer with transparent-black. + * This is then filtered by fBackdrop (respecting the current clip). + */ + const SkImageFilter* fBackdrop = nullptr; + + /** preserves LCD text, creates with prior layer contents */ + SaveLayerFlags fSaveLayerFlags = 0; + + private: + friend class SkCanvas; + friend class SkCanvasPriv; + + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + SkScalar backdropScale, SaveLayerFlags saveLayerFlags) + : fBounds(bounds) + , fPaint(paint) + , fBackdrop(backdrop) + , fSaveLayerFlags(saveLayerFlags) + , fExperimentalBackdropScale(backdropScale) {} + + // Relative scale factor that the image content used to initialize the layer when the + // kInitFromPrevious flag or a backdrop filter is used. + SkScalar fExperimentalBackdropScale = 1.f; + }; + + /** Saves SkMatrix and clip, and allocates SkSurface for subsequent drawing. + + Calling restore() discards changes to SkMatrix and clip, + and blends SkSurface with alpha opacity onto the prior layer. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SaveLayerRec contains the state used to create the layer. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param layerRec layer state + @return depth of save state stack before this call was made. + + example: https://fiddle.skia.org/c/@Canvas_saveLayer_3 + */ + int saveLayer(const SaveLayerRec& layerRec); + + /** Removes changes to SkMatrix and clip since SkCanvas state was + last saved. The state is removed from the stack. + + Does nothing if the stack is empty. + + example: https://fiddle.skia.org/c/@AutoCanvasRestore_restore + + example: https://fiddle.skia.org/c/@Canvas_restore + */ + void restore(); + + /** Returns the number of saved states, each containing: SkMatrix and clip. + Equals the number of save() calls less the number of restore() calls plus one. + The save count of a new canvas is one. + + @return depth of save state stack + + example: https://fiddle.skia.org/c/@Canvas_getSaveCount + */ + int getSaveCount() const; + + /** Restores state to SkMatrix and clip values when save(), saveLayer(), + saveLayerPreserveLCDTextRequests(), or saveLayerAlpha() returned saveCount. + + Does nothing if saveCount is greater than state stack count. + Restores state to initial values if saveCount is less than or equal to one. + + @param saveCount depth of state stack to restore + + example: https://fiddle.skia.org/c/@Canvas_restoreToCount + */ + void restoreToCount(int saveCount); + + /** Translates SkMatrix by dx along the x-axis and dy along the y-axis. + + Mathematically, replaces SkMatrix with a translation matrix + premultiplied with SkMatrix. + + This has the effect of moving the drawing by (dx, dy) before transforming + the result with SkMatrix. + + @param dx distance to translate on x-axis + @param dy distance to translate on y-axis + + example: https://fiddle.skia.org/c/@Canvas_translate + */ + void translate(SkScalar dx, SkScalar dy); + + /** Scales SkMatrix by sx on the x-axis and sy on the y-axis. + + Mathematically, replaces SkMatrix with a scale matrix + premultiplied with SkMatrix. + + This has the effect of scaling the drawing by (sx, sy) before transforming + the result with SkMatrix. + + @param sx amount to scale on x-axis + @param sy amount to scale on y-axis + + example: https://fiddle.skia.org/c/@Canvas_scale + */ + void scale(SkScalar sx, SkScalar sy); + + /** Rotates SkMatrix by degrees. Positive degrees rotates clockwise. + + Mathematically, replaces SkMatrix with a rotation matrix + premultiplied with SkMatrix. + + This has the effect of rotating the drawing by degrees before transforming + the result with SkMatrix. + + @param degrees amount to rotate, in degrees + + example: https://fiddle.skia.org/c/@Canvas_rotate + */ + void rotate(SkScalar degrees); + + /** Rotates SkMatrix by degrees about a point at (px, py). Positive degrees rotates + clockwise. + + Mathematically, constructs a rotation matrix; premultiplies the rotation matrix by + a translation matrix; then replaces SkMatrix with the resulting matrix + premultiplied with SkMatrix. + + This has the effect of rotating the drawing about a given point before + transforming the result with SkMatrix. + + @param degrees amount to rotate, in degrees + @param px x-axis value of the point to rotate about + @param py y-axis value of the point to rotate about + + example: https://fiddle.skia.org/c/@Canvas_rotate_2 + */ + void rotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Skews SkMatrix by sx on the x-axis and sy on the y-axis. A positive value of sx + skews the drawing right as y-axis values increase; a positive value of sy skews + the drawing down as x-axis values increase. + + Mathematically, replaces SkMatrix with a skew matrix premultiplied with SkMatrix. + + This has the effect of skewing the drawing by (sx, sy) before transforming + the result with SkMatrix. + + @param sx amount to skew on x-axis + @param sy amount to skew on y-axis + + example: https://fiddle.skia.org/c/@Canvas_skew + */ + void skew(SkScalar sx, SkScalar sy); + + /** Replaces SkMatrix with matrix premultiplied with existing SkMatrix. + + This has the effect of transforming the drawn geometry by matrix, before + transforming the result with existing SkMatrix. + + @param matrix matrix to premultiply with existing SkMatrix + + example: https://fiddle.skia.org/c/@Canvas_concat + */ + void concat(const SkMatrix& matrix); + void concat(const SkM44&); + + /** Replaces SkMatrix with matrix. + Unlike concat(), any prior matrix state is overwritten. + + @param matrix matrix to copy, replacing existing SkMatrix + + example: https://fiddle.skia.org/c/@Canvas_setMatrix + */ + void setMatrix(const SkM44& matrix); + + // DEPRECATED -- use SkM44 version + void setMatrix(const SkMatrix& matrix); + + /** Sets SkMatrix to the identity matrix. + Any prior matrix state is overwritten. + + example: https://fiddle.skia.org/c/@Canvas_resetMatrix + */ + void resetMatrix(); + + /** Replaces clip with the intersection or difference of clip and rect, + with an aliased or anti-aliased clip edge. rect is transformed by SkMatrix + before it is combined with clip. + + @param rect SkRect to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + + example: https://fiddle.skia.org/c/@Canvas_clipRect + */ + void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias); + + /** Replaces clip with the intersection or difference of clip and rect. + Resulting clip is aliased; pixels are fully contained by the clip. + rect is transformed by SkMatrix before it is combined with clip. + + @param rect SkRect to combine with clip + @param op SkClipOp to apply to clip + */ + void clipRect(const SkRect& rect, SkClipOp op) { + this->clipRect(rect, op, false); + } + + /** Replaces clip with the intersection of clip and rect. + Resulting clip is aliased; pixels are fully contained by the clip. + rect is transformed by SkMatrix + before it is combined with clip. + + @param rect SkRect to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ + void clipRect(const SkRect& rect, bool doAntiAlias = false) { + this->clipRect(rect, SkClipOp::kIntersect, doAntiAlias); + } + + void clipIRect(const SkIRect& irect, SkClipOp op = SkClipOp::kIntersect) { + this->clipRect(SkRect::Make(irect), op, false); + } + + /** Sets the maximum clip rectangle, which can be set by clipRect(), clipRRect() and + clipPath() and intersect the current clip with the specified rect. + The maximum clip affects only future clipping operations; it is not retroactive. + The clip restriction is not recorded in pictures. + + Pass an empty rect to disable maximum clip. + This private API is for use by Android framework only. + + DEPRECATED: Replace usage with SkAndroidFrameworkUtils::replaceClip() + + @param rect maximum allowed clip in device coordinates + */ + void androidFramework_setDeviceClipRestriction(const SkIRect& rect); + + /** Replaces clip with the intersection or difference of clip and rrect, + with an aliased or anti-aliased clip edge. + rrect is transformed by SkMatrix + before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + + example: https://fiddle.skia.org/c/@Canvas_clipRRect + */ + void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias); + + /** Replaces clip with the intersection or difference of clip and rrect. + Resulting clip is aliased; pixels are fully contained by the clip. + rrect is transformed by SkMatrix before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param op SkClipOp to apply to clip + */ + void clipRRect(const SkRRect& rrect, SkClipOp op) { + this->clipRRect(rrect, op, false); + } + + /** Replaces clip with the intersection of clip and rrect, + with an aliased or anti-aliased clip edge. + rrect is transformed by SkMatrix before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ + void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) { + this->clipRRect(rrect, SkClipOp::kIntersect, doAntiAlias); + } + + /** Replaces clip with the intersection or difference of clip and path, + with an aliased or anti-aliased clip edge. SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix before it is combined with clip. + + @param path SkPath to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + + example: https://fiddle.skia.org/c/@Canvas_clipPath + */ + void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias); + + /** Replaces clip with the intersection or difference of clip and path. + Resulting clip is aliased; pixels are fully contained by the clip. + SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix + before it is combined with clip. + + @param path SkPath to combine with clip + @param op SkClipOp to apply to clip + */ + void clipPath(const SkPath& path, SkClipOp op) { + this->clipPath(path, op, false); + } + + /** Replaces clip with the intersection of clip and path. + Resulting clip is aliased; pixels are fully contained by the clip. + SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix before it is combined with clip. + + @param path SkPath to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ + void clipPath(const SkPath& path, bool doAntiAlias = false) { + this->clipPath(path, SkClipOp::kIntersect, doAntiAlias); + } + + void clipShader(sk_sp, SkClipOp = SkClipOp::kIntersect); + + /** Replaces clip with the intersection or difference of clip and SkRegion deviceRgn. + Resulting clip is aliased; pixels are fully contained by the clip. + deviceRgn is unaffected by SkMatrix. + + @param deviceRgn SkRegion to combine with clip + @param op SkClipOp to apply to clip + + example: https://fiddle.skia.org/c/@Canvas_clipRegion + */ + void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect); + + /** Returns true if SkRect rect, transformed by SkMatrix, can be quickly determined to be + outside of clip. May return false even though rect is outside of clip. + + Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. + + @param rect SkRect to compare with clip + @return true if rect, transformed by SkMatrix, does not intersect clip + + example: https://fiddle.skia.org/c/@Canvas_quickReject + */ + bool quickReject(const SkRect& rect) const; + + /** Returns true if path, transformed by SkMatrix, can be quickly determined to be + outside of clip. May return false even though path is outside of clip. + + Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. + + @param path SkPath to compare with clip + @return true if path, transformed by SkMatrix, does not intersect clip + + example: https://fiddle.skia.org/c/@Canvas_quickReject_2 + */ + bool quickReject(const SkPath& path) const; + + /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty, + return SkRect::MakeEmpty, where all SkRect sides equal zero. + + SkRect returned is outset by one to account for partial pixel coverage if clip + is anti-aliased. + + @return bounds of clip in local coordinates + + example: https://fiddle.skia.org/c/@Canvas_getLocalClipBounds + */ + SkRect getLocalClipBounds() const; + + /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty, + return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. + + bounds is outset by one to account for partial pixel coverage if clip + is anti-aliased. + + @param bounds SkRect of clip in local coordinates + @return true if clip bounds is not empty + */ + bool getLocalClipBounds(SkRect* bounds) const { + *bounds = this->getLocalClipBounds(); + return !bounds->isEmpty(); + } + + /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, + return SkRect::MakeEmpty, where all SkRect sides equal zero. + + Unlike getLocalClipBounds(), returned SkIRect is not outset. + + @return bounds of clip in SkBaseDevice coordinates + + example: https://fiddle.skia.org/c/@Canvas_getDeviceClipBounds + */ + SkIRect getDeviceClipBounds() const; + + /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, + return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. + + Unlike getLocalClipBounds(), bounds is not outset. + + @param bounds SkRect of clip in device coordinates + @return true if clip bounds is not empty + */ + bool getDeviceClipBounds(SkIRect* bounds) const { + *bounds = this->getDeviceClipBounds(); + return !bounds->isEmpty(); + } + + /** Fills clip with color color. + mode determines how ARGB is combined with destination. + + @param color unpremultiplied ARGB + @param mode SkBlendMode used to combine source color and destination + + example: https://fiddle.skia.org/c/@Canvas_drawColor + */ + void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver) { + this->drawColor(SkColor4f::FromColor(color), mode); + } + + /** Fills clip with color color. + mode determines how ARGB is combined with destination. + + @param color SkColor4f representing unpremultiplied color. + @param mode SkBlendMode used to combine source color and destination + */ + void drawColor(const SkColor4f& color, SkBlendMode mode = SkBlendMode::kSrcOver); + + /** Fills clip with color color using SkBlendMode::kSrc. + This has the effect of replacing all pixels contained by clip with color. + + @param color unpremultiplied ARGB + */ + void clear(SkColor color) { + this->clear(SkColor4f::FromColor(color)); + } + + /** Fills clip with color color using SkBlendMode::kSrc. + This has the effect of replacing all pixels contained by clip with color. + + @param color SkColor4f representing unpremultiplied color. + */ + void clear(const SkColor4f& color) { + this->drawColor(color, SkBlendMode::kSrc); + } + + /** Makes SkCanvas contents undefined. Subsequent calls that read SkCanvas pixels, + such as drawing with SkBlendMode, return undefined results. discard() does + not change clip or SkMatrix. + + discard() may do nothing, depending on the implementation of SkSurface or SkBaseDevice + that created SkCanvas. + + discard() allows optimized performance on subsequent draws by removing + cached data associated with SkSurface or SkBaseDevice. + It is not necessary to call discard() once done with SkCanvas; + any cached data is deleted when owning SkSurface or SkBaseDevice is deleted. + */ + void discard() { this->onDiscard(); } + + /** Fills clip with SkPaint paint. SkPaint components, SkShader, + SkColorFilter, SkImageFilter, and SkBlendMode affect drawing; + SkMaskFilter and SkPathEffect in paint are ignored. + + @param paint graphics state used to fill SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_drawPaint + */ + void drawPaint(const SkPaint& paint); + + /** \enum SkCanvas::PointMode + Selects if an array of points are drawn as discrete points, as lines, or as + an open polygon. + */ + enum PointMode { + kPoints_PointMode, //!< draw each point separately + kLines_PointMode, //!< draw each pair of points as a line segment + kPolygon_PointMode, //!< draw the array of points as a open polygon + }; + + /** Draws pts using clip, SkMatrix and SkPaint paint. + count is the number of points; if count is less than one, has no effect. + mode may be one of: kPoints_PointMode, kLines_PointMode, or kPolygon_PointMode. + + If mode is kPoints_PointMode, the shape of point drawn depends on paint + SkPaint::Cap. If paint is set to SkPaint::kRound_Cap, each point draws a + circle of diameter SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap + or SkPaint::kButt_Cap, each point draws a square of width and height + SkPaint stroke width. + + If mode is kLines_PointMode, each pair of points draws a line segment. + One line is drawn for every two points; each point is used once. If count is odd, + the final point is ignored. + + If mode is kPolygon_PointMode, each adjacent pair of points draws a line segment. + count minus one lines are drawn; the first and last point are used once. + + Each line segment respects paint SkPaint::Cap and SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + Always draws each element one at a time; is not affected by + SkPaint::Join, and unlike drawPath(), does not create a mask from all points + and lines before drawing. + + @param mode whether pts draws points or lines + @param count number of points in the array + @param pts array of points to draw + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawPoints + */ + void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint); + + /** Draws point at (x, y) using clip, SkMatrix and SkPaint paint. + + The shape of point drawn depends on paint SkPaint::Cap. + If paint is set to SkPaint::kRound_Cap, draw a circle of diameter + SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, + draw a square of width and height SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param x left edge of circle or square + @param y top edge of circle or square + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawPoint + */ + void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draws point p using clip, SkMatrix and SkPaint paint. + + The shape of point drawn depends on paint SkPaint::Cap. + If paint is set to SkPaint::kRound_Cap, draw a circle of diameter + SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, + draw a square of width and height SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param p top-left edge of circle or square + @param paint stroke, blend, color, and so on, used to draw + */ + void drawPoint(SkPoint p, const SkPaint& paint) { + this->drawPoint(p.x(), p.y(), paint); + } + + /** Draws line segment from (x0, y0) to (x1, y1) using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint stroke width describes the line thickness; + SkPaint::Cap draws the end rounded or square; + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param x0 start of line segment on x-axis + @param y0 start of line segment on y-axis + @param x1 end of line segment on x-axis + @param y1 end of line segment on y-axis + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawLine + */ + void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint); + + /** Draws line segment from p0 to p1 using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint stroke width describes the line thickness; + SkPaint::Cap draws the end rounded or square; + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param p0 start of line segment + @param p1 end of line segment + @param paint stroke, blend, color, and so on, used to draw + */ + void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) { + this->drawLine(p0.x(), p0.y(), p1.x(), p1.y(), paint); + } + + /** Draws SkRect rect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param rect rectangle to draw + @param paint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRect + */ + void drawRect(const SkRect& rect, const SkPaint& paint); + + /** Draws SkIRect rect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param rect rectangle to draw + @param paint stroke or fill, blend, color, and so on, used to draw + */ + void drawIRect(const SkIRect& rect, const SkPaint& paint) { + SkRect r; + r.set(rect); // promotes the ints to scalars + this->drawRect(r, paint); + } + + /** Draws SkRegion region using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param region region to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRegion + */ + void drawRegion(const SkRegion& region, const SkPaint& paint); + + /** Draws oval oval using clip, SkMatrix, and SkPaint. + In paint: SkPaint::Style determines if oval is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param oval SkRect bounds of oval + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawOval + */ + void drawOval(const SkRect& oval, const SkPaint& paint); + + /** Draws SkRRect rrect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rrect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + rrect may represent a rectangle, circle, oval, uniformly rounded rectangle, or + may have any combination of positive non-square radii for the four corners. + + @param rrect SkRRect with up to eight corner radii to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRRect + */ + void drawRRect(const SkRRect& rrect, const SkPaint& paint); + + /** Draws SkRRect outer and inner + using clip, SkMatrix, and SkPaint paint. + outer must contain inner or the drawing is undefined. + In paint: SkPaint::Style determines if SkRRect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + If stroked and SkRRect corner has zero length radii, SkPaint::Join can + draw corners rounded or square. + + GPU-backed platforms optimize drawing when both outer and inner are + concave and outer contains inner. These platforms may not be able to draw + SkPath built with identical data as fast. + + @param outer SkRRect outer bounds to draw + @param inner SkRRect inner bounds to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawDRRect_a + example: https://fiddle.skia.org/c/@Canvas_drawDRRect_b + */ + void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); + + /** Draws circle at (cx, cy) with radius using clip, SkMatrix, and SkPaint paint. + If radius is zero or less, nothing is drawn. + In paint: SkPaint::Style determines if circle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param cx circle center on the x-axis + @param cy circle center on the y-axis + @param radius half the diameter of circle + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawCircle + */ + void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint); + + /** Draws circle at center with radius using clip, SkMatrix, and SkPaint paint. + If radius is zero or less, nothing is drawn. + In paint: SkPaint::Style determines if circle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param center circle center + @param radius half the diameter of circle + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ + void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) { + this->drawCircle(center.x(), center.y(), radius, paint); + } + + /** Draws arc using clip, SkMatrix, and SkPaint paint. + + Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus + sweepAngle. startAngle and sweepAngle are in degrees. + + startAngle of zero places start point at the right middle edge of oval. + A positive sweepAngle places arc end point clockwise from start point; + a negative sweepAngle places arc end point counterclockwise from start point. + sweepAngle may exceed 360 degrees, a full circle. + If useCenter is true, draw a wedge that includes lines from oval + center to arc end points. If useCenter is false, draw arc between end points. + + If SkRect oval is empty or sweepAngle is zero, nothing is drawn. + + @param oval SkRect bounds of oval containing arc to draw + @param startAngle angle in degrees where arc begins + @param sweepAngle sweep angle in degrees; positive is clockwise + @param useCenter if true, include the center of the oval + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ + void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint); + + /** Draws SkRRect bounded by SkRect rect, with corner radii (rx, ry) using clip, + SkMatrix, and SkPaint paint. + + In paint: SkPaint::Style determines if SkRRect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + If rx or ry are less than zero, they are treated as if they are zero. + If rx plus ry exceeds rect width or rect height, radii are scaled down to fit. + If rx and ry are zero, SkRRect is drawn as SkRect and if stroked is affected by + SkPaint::Join. + + @param rect SkRect bounds of SkRRect to draw + @param rx axis length on x-axis of oval describing rounded corners + @param ry axis length on y-axis of oval describing rounded corners + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRoundRect + */ + void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint); + + /** Draws SkPath path using clip, SkMatrix, and SkPaint paint. + SkPath contains an array of path contour, each of which may be open or closed. + + In paint: SkPaint::Style determines if SkRRect is stroked or filled: + if filled, SkPath::FillType determines whether path contour describes inside or + outside of fill; if stroked, SkPaint stroke width describes the line thickness, + SkPaint::Cap describes line ends, and SkPaint::Join describes how + corners are drawn. + + @param path SkPath to draw + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawPath + */ + void drawPath(const SkPath& path, const SkPaint& paint); + + void drawImage(const SkImage* image, SkScalar left, SkScalar top) { + this->drawImage(image, left, top, SkSamplingOptions(), nullptr); + } + void drawImage(const sk_sp& image, SkScalar left, SkScalar top) { + this->drawImage(image.get(), left, top, SkSamplingOptions(), nullptr); + } + + /** \enum SkCanvas::SrcRectConstraint + SrcRectConstraint controls the behavior at the edge of source SkRect, + provided to drawImageRect() when there is any filtering. If kStrict is set, + then extra code is used to ensure it never samples outside of the src-rect. + kStrict_SrcRectConstraint disables the use of mipmaps and anisotropic filtering. + */ + enum SrcRectConstraint { + kStrict_SrcRectConstraint, //!< sample only inside bounds; slower + kFast_SrcRectConstraint, //!< sample outside bounds; faster + }; + + void drawImage(const SkImage*, SkScalar x, SkScalar y, const SkSamplingOptions&, + const SkPaint* = nullptr); + void drawImage(const sk_sp& image, SkScalar x, SkScalar y, + const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) { + this->drawImage(image.get(), x, y, sampling, paint); + } + void drawImageRect(const SkImage*, const SkRect& src, const SkRect& dst, + const SkSamplingOptions&, const SkPaint*, SrcRectConstraint); + void drawImageRect(const SkImage*, const SkRect& dst, const SkSamplingOptions&, + const SkPaint* = nullptr); + void drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, + const SkSamplingOptions& sampling, const SkPaint* paint, + SrcRectConstraint constraint) { + this->drawImageRect(image.get(), src, dst, sampling, paint, constraint); + } + void drawImageRect(const sk_sp& image, const SkRect& dst, + const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) { + this->drawImageRect(image.get(), dst, sampling, paint); + } + + /** Draws SkImage image stretched proportionally to fit into SkRect dst. + SkIRect center divides the image into nine sections: four sides, four corners, and + the center. Corners are unmodified or scaled down proportionately if their sides + are larger than dst; center and four sides are scaled to fit remaining space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter, and + SkBlendMode. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + Any SkMaskFilter on paint is ignored as is paint anti-aliasing state. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image edge color when it samples outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param center SkIRect edge of image corners and sides + @param dst destination SkRect of image to draw to + @param filter what technique to use when sampling the image + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ + void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, + SkFilterMode filter, const SkPaint* paint = nullptr); + + /** \struct SkCanvas::Lattice + SkCanvas::Lattice divides SkBitmap or SkImage into a rectangular grid. + Grid entries on even columns and even rows are fixed; these entries are + always drawn at their original size if the destination is large enough. + If the destination side is too small to hold the fixed entries, all fixed + entries are proportionately scaled down to fit. + The grid entries not on even columns and rows are scaled to fit the + remaining space, if any. + */ + struct Lattice { + + /** \enum SkCanvas::Lattice::RectType + Optional setting per rectangular grid entry to make it transparent, + or to fill the grid entry with a color. + */ + enum RectType : uint8_t { + kDefault = 0, //!< draws SkBitmap into lattice rectangle + kTransparent, //!< skips lattice rectangle by making it transparent + kFixedColor, //!< draws one of fColors into lattice rectangle + }; + + const int* fXDivs; //!< x-axis values dividing bitmap + const int* fYDivs; //!< y-axis values dividing bitmap + const RectType* fRectTypes; //!< array of fill types + int fXCount; //!< number of x-coordinates + int fYCount; //!< number of y-coordinates + const SkIRect* fBounds; //!< source bounds to draw from + const SkColor* fColors; //!< array of colors + }; + + /** Draws SkImage image stretched proportionally to fit into SkRect dst. + + SkCanvas::Lattice lattice divides image into a rectangular grid. + Each intersection of an even-numbered row and column is fixed; + fixed lattice elements never scale larger than their initial + size and shrink proportionately when all fixed elements exceed the bitmap + dimension. All other grid elements scale to fill the available space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter, and + SkBlendMode. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + Any SkMaskFilter on paint is ignored as is paint anti-aliasing state. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples + outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param lattice division of bitmap into fixed and variable rectangles + @param dst destination SkRect of image to draw to + @param filter what technique to use when sampling the image + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ + void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, + SkFilterMode filter, const SkPaint* paint = nullptr); + void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst) { + this->drawImageLattice(image, lattice, dst, SkFilterMode::kNearest, nullptr); + } + + /** + * Experimental. Controls anti-aliasing of each edge of images in an image-set. + */ + enum QuadAAFlags : unsigned { + kLeft_QuadAAFlag = 0b0001, + kTop_QuadAAFlag = 0b0010, + kRight_QuadAAFlag = 0b0100, + kBottom_QuadAAFlag = 0b1000, + + kNone_QuadAAFlags = 0b0000, + kAll_QuadAAFlags = 0b1111, + }; + + /** This is used by the experimental API below. */ + struct SK_API ImageSetEntry { + ImageSetEntry(sk_sp image, const SkRect& srcRect, const SkRect& dstRect, + int matrixIndex, float alpha, unsigned aaFlags, bool hasClip); + + ImageSetEntry(sk_sp image, const SkRect& srcRect, const SkRect& dstRect, + float alpha, unsigned aaFlags); + + ImageSetEntry(); + ~ImageSetEntry(); + ImageSetEntry(const ImageSetEntry&); + ImageSetEntry& operator=(const ImageSetEntry&); + + sk_sp fImage; + SkRect fSrcRect; + SkRect fDstRect; + int fMatrixIndex = -1; // Index into the preViewMatrices arg, or < 0 + float fAlpha = 1.f; + unsigned fAAFlags = kNone_QuadAAFlags; // QuadAAFlags + bool fHasClip = false; // True to use next 4 points in dstClip arg as quad + }; + + /** + * This is an experimental API for the SkiaRenderer Chromium project, and its API will surely + * evolve if it is not removed outright. + * + * This behaves very similarly to drawRect() combined with a clipPath() formed by clip + * quadrilateral. 'rect' and 'clip' are in the same coordinate space. If 'clip' is null, then it + * is as if the rectangle was not clipped (or, alternatively, clipped to itself). If not null, + * then it must provide 4 points. + * + * In addition to combining the draw and clipping into one operation, this function adds the + * additional capability of controlling each of the rectangle's edges anti-aliasing + * independently. The edges of the clip will respect the per-edge AA flags. It is required that + * 'clip' be contained inside 'rect'. In terms of mapping to edge labels, the 'clip' points + * should be ordered top-left, top-right, bottom-right, bottom-left so that the edge between [0] + * and [1] is "top", [1] and [2] is "right", [2] and [3] is "bottom", and [3] and [0] is "left". + * This ordering matches SkRect::toQuad(). + * + * This API only draws solid color, filled rectangles so it does not accept a full SkPaint. + */ + void experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, + const SkColor4f& color, SkBlendMode mode); + void experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, + SkColor color, SkBlendMode mode) { + this->experimental_DrawEdgeAAQuad(rect, clip, aaFlags, SkColor4f::FromColor(color), mode); + } + + /** + * This is an bulk variant of experimental_DrawEdgeAAQuad() that renders 'cnt' textured quads. + * For each entry, 'fDstRect' is rendered with its clip (determined by entry's 'fHasClip' and + * the current index in 'dstClip'). The entry's fImage is applied to the destination rectangle + * by sampling from 'fSrcRect' sub-image. The corners of 'fSrcRect' map to the corners of + * 'fDstRect', just like in drawImageRect(), and they will be properly interpolated when + * applying a clip. + * + * Like experimental_DrawEdgeAAQuad(), each entry can specify edge AA flags that apply to both + * the destination rect and its clip. + * + * If provided, the 'dstClips' array must have length equal 4 * the number of entries with + * fHasClip true. If 'dstClips' is null, every entry must have 'fHasClip' set to false. The + * destination clip coordinates will be read consecutively with the image set entries, advancing + * by 4 points every time an entry with fHasClip is passed. + * + * This entry point supports per-entry manipulations to the canvas's current matrix. If an + * entry provides 'fMatrixIndex' >= 0, it will be drawn as if the canvas's CTM was + * canvas->getTotalMatrix() * preViewMatrices[fMatrixIndex]. If 'fMatrixIndex' is less than 0, + * the pre-view matrix transform is implicitly the identity, so it will be drawn using just the + * current canvas matrix. The pre-view matrix modifies the canvas's view matrix, it does not + * affect the local coordinates of each entry. + * + * An optional paint may be provided, which supports the same subset of features usable with + * drawImageRect (i.e. assumed to be filled and no path effects). When a paint is provided, the + * image set is drawn as if each image used the applied paint independently, so each is affected + * by the image, color, and/or mask filter. + */ + void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, + const SkPoint dstClips[], const SkMatrix preViewMatrices[], + const SkSamplingOptions&, const SkPaint* paint = nullptr, + SrcRectConstraint constraint = kStrict_SrcRectConstraint); + + /** Draws text, with origin at (x, y), using clip, SkMatrix, SkFont font, + and SkPaint paint. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32, this function uses the default + character-to-glyph mapping from the SkTypeface in font. It does not + perform typeface fallback for characters not found in the SkTypeface. + It does not perform kerning or other complex shaping; glyphs are + positioned based on their default advances. + + Text meaning depends on SkTextEncoding. + + Text size is affected by SkMatrix and SkFont text size. Default text + size is 12 point. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param encoding text encoding used in the text array + @param x start of text on x-axis + @param y start of text on y-axis + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding, + SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint); + + /** Draws null terminated string, with origin at (x, y), using clip, SkMatrix, + SkFont font, and SkPaint paint. + + This function uses the default character-to-glyph mapping from the + SkTypeface in font. It does not perform typeface fallback for + characters not found in the SkTypeface. It does not perform kerning; + glyphs are positioned based on their default advances. + + String str is encoded as UTF-8. + + Text size is affected by SkMatrix and font text size. Default text + size is 12 point. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param str character code points drawn, + ending with a char value of zero + @param x start of string on x-axis + @param y start of string on y-axis + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawString(const char str[], SkScalar x, SkScalar y, const SkFont& font, + const SkPaint& paint) { + this->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint); + } + + /** Draws SkString, with origin at (x, y), using clip, SkMatrix, SkFont font, + and SkPaint paint. + + This function uses the default character-to-glyph mapping from the + SkTypeface in font. It does not perform typeface fallback for + characters not found in the SkTypeface. It does not perform kerning; + glyphs are positioned based on their default advances. + + SkString str is encoded as UTF-8. + + Text size is affected by SkMatrix and SkFont text size. Default text + size is 12 point. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param str character code points drawn, + ending with a char value of zero + @param x start of string on x-axis + @param y start of string on y-axis + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawString(const SkString& str, SkScalar x, SkScalar y, const SkFont& font, + const SkPaint& paint) { + this->drawSimpleText(str.c_str(), str.size(), SkTextEncoding::kUTF8, x, y, font, paint); + } + + /** Draws count glyphs, at positions relative to origin styled with font and paint with + supporting utf8 and cluster information. + + This function draw glyphs at the given positions relative to the given origin. + It does not perform typeface fallback for glyphs not found in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param positions where to draw each glyph relative to origin + @param clusters array of size count of cluster information + @param textByteCount size of the utf8text + @param utf8text utf8text supporting information for the glyphs + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], + const uint32_t clusters[], int textByteCount, const char utf8text[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + + /** Draws count glyphs, at positions relative to origin styled with font and paint. + + This function draw glyphs at the given positions relative to the given origin. + It does not perform typeface fallback for glyphs not found in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param positions where to draw each glyph relative to origin + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + + /** Draws count glyphs, at positions relative to origin styled with font and paint. + + This function draw glyphs using the given scaling and rotations. They are positioned + relative to the given origin. It does not perform typeface fallback for glyphs not found + in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param xforms where to draw and orient each glyph + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + + /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. + + blob contains glyphs, their positions, and paint attributes specific to text: + SkTypeface, SkPaint text size, SkPaint text scale x, + SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, + SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text, + and SkPaint subpixel text. + + SkTextEncoding must be set to SkTextEncoding::kGlyphID. + + Elements of paint: anti-alias, SkBlendMode, color including alpha, + SkColorFilter, SkPaint dither, SkMaskFilter, SkPathEffect, SkShader, and + SkPaint::Style; apply to blob. If SkPaint contains SkPaint::kStroke_Style: + SkPaint miter limit, SkPaint::Cap, SkPaint::Join, and SkPaint stroke width; + apply to SkPath created from blob. + + @param blob glyphs, positions, and their paints' text size, typeface, and so on + @param x horizontal offset applied to blob + @param y vertical offset applied to blob + @param paint blend, color, stroking, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawTextBlob + */ + void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. + + blob contains glyphs, their positions, and paint attributes specific to text: + SkTypeface, SkPaint text size, SkPaint text scale x, + SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, + SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text, + and SkPaint subpixel text. + + SkTextEncoding must be set to SkTextEncoding::kGlyphID. + + Elements of paint: SkPathEffect, SkMaskFilter, SkShader, SkColorFilter, + and SkImageFilter; apply to blob. + + @param blob glyphs, positions, and their paints' text size, typeface, and so on + @param x horizontal offset applied to blob + @param y vertical offset applied to blob + @param paint blend, color, stroking, and so on, used to draw + */ + void drawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y, const SkPaint& paint) { + this->drawTextBlob(blob.get(), x, y, paint); + } + + /** Draws SkPicture picture, using clip and SkMatrix. + Clip and SkMatrix are unchanged by picture contents, as if + save() was called before and restore() was called after drawPicture(). + + SkPicture records a series of draw commands for later playback. + + @param picture recorded drawing commands to play + */ + void drawPicture(const SkPicture* picture) { + this->drawPicture(picture, nullptr, nullptr); + } + + /** Draws SkPicture picture, using clip and SkMatrix. + Clip and SkMatrix are unchanged by picture contents, as if + save() was called before and restore() was called after drawPicture(). + + SkPicture records a series of draw commands for later playback. + + @param picture recorded drawing commands to play + */ + void drawPicture(const sk_sp& picture) { + this->drawPicture(picture.get()); + } + + /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with + SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter, + SkImageFilter, and SkBlendMode, if provided. + + If paint is non-null, then the picture is always drawn into a temporary layer before + actually landing on the canvas. Note that drawing into a layer can also change its + appearance if there are any non-associative blendModes inside any of the pictures elements. + + @param picture recorded drawing commands to play + @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr + @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr + + example: https://fiddle.skia.org/c/@Canvas_drawPicture_3 + */ + void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint); + + /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with + SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter, + SkImageFilter, and SkBlendMode, if provided. + + If paint is non-null, then the picture is always drawn into a temporary layer before + actually landing on the canvas. Note that drawing into a layer can also change its + appearance if there are any non-associative blendModes inside any of the pictures elements. + + @param picture recorded drawing commands to play + @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr + @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr + */ + void drawPicture(const sk_sp& picture, const SkMatrix* matrix, + const SkPaint* paint) { + this->drawPicture(picture.get(), matrix, paint); + } + + /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. + If paint contains an SkShader and vertices does not contain texCoords, the shader + is mapped using the vertices' positions. + + SkBlendMode is ignored if SkVertices does not have colors. Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the interpolated vertex colors as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param vertices triangle mesh to draw + @param mode combines vertices' colors with SkShader if present or SkPaint opaque color + if not. Ignored if the vertices do not contain color. + @param paint specifies the SkShader, used as SkVertices texture, and SkColorFilter. + + example: https://fiddle.skia.org/c/@Canvas_drawVertices + */ + void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint); + + /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. + If paint contains an SkShader and vertices does not contain texCoords, the shader + is mapped using the vertices' positions. + + SkBlendMode is ignored if SkVertices does not have colors. Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the interpolated vertex colors as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param vertices triangle mesh to draw + @param mode combines vertices' colors with SkShader if present or SkPaint opaque color + if not. Ignored if the vertices do not contain color. + @param paint specifies the SkShader, used as SkVertices texture, may be nullptr + + example: https://fiddle.skia.org/c/@Canvas_drawVertices_2 + */ + void drawVertices(const sk_sp& vertices, SkBlendMode mode, const SkPaint& paint); + +#if defined(SK_ENABLE_SKSL) + /** + Experimental, under active development, and subject to change without notice. + + Draws a mesh using a user-defined specification (see SkMeshSpecification). + + SkBlender is ignored if SkMesh's specification does not output fragment shader color. + Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the mesh's fragment color as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param mesh the mesh vertices and compatible specification. + @param blender combines vertices colors with SkShader if present or SkPaint opaque color + if not. Ignored if the custom mesh does not output color. Defaults to + SkBlendMode::kModulate if nullptr. + @param paint specifies the SkShader, used as SkVertices texture, may be nullptr + */ + void drawMesh(const SkMesh& mesh, sk_sp blender, const SkPaint& paint); +#endif + + /** Draws a Coons patch: the interpolation of four cubics with shared corners, + associating a color, and optionally a texture SkPoint, with each corner. + + SkPoint array cubics specifies four SkPath cubic starting at the top-left corner, + in clockwise order, sharing every fourth point. The last SkPath cubic ends at the + first point. + + Color array color associates colors with corners in top-left, top-right, + bottom-right, bottom-left order. + + If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to + corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is + nullptr, SkShader is mapped using positions (derived from cubics). + + SkBlendMode is ignored if colors is null. Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the interpolated patch colors as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param cubics SkPath cubic array, sharing common points + @param colors color array, one for each corner + @param texCoords SkPoint array of texture coordinates, mapping SkShader to corners; + may be nullptr + @param mode combines patch's colors with SkShader if present or SkPaint opaque color + if not. Ignored if colors is null. + @param paint SkShader, SkColorFilter, SkBlendMode, used to draw + */ + void drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); + + /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. + paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode + to draw, if present. For each entry in the array, SkRect tex locates sprite in + atlas, and SkRSXform xform transforms it into destination space. + + SkMaskFilter and SkPathEffect on paint are ignored. + + xform, tex, and colors if present, must contain count entries. + Optional colors are applied for each sprite using SkBlendMode mode, treating + sprite as source and colors as destination. + Optional cullRect is a conservative bounds of all transformed sprites. + If cullRect is outside of clip, canvas can skip drawing. + + If atlas is nullptr, this draws nothing. + + @param atlas SkImage containing sprites + @param xform SkRSXform mappings for sprites in atlas + @param tex SkRect locations of sprites in atlas + @param colors one per sprite, blended with sprite using SkBlendMode; may be nullptr + @param count number of sprites to draw + @param mode SkBlendMode combining colors and sprites + @param sampling SkSamplingOptions used when sampling from the atlas image + @param cullRect bounds of transformed sprites for efficient clipping; may be nullptr + @param paint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr + */ + void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], + const SkColor colors[], int count, SkBlendMode mode, + const SkSamplingOptions& sampling, const SkRect* cullRect, const SkPaint* paint); + + /** Draws SkDrawable drawable using clip and SkMatrix, concatenated with + optional matrix. + + If SkCanvas has an asynchronous implementation, as is the case + when it is recording into SkPicture, then drawable will be referenced, + so that SkDrawable::draw() can be called when the operation is finalized. To force + immediate drawing, call SkDrawable::draw() instead. + + @param drawable custom struct encapsulating drawing commands + @param matrix transformation applied to drawing; may be nullptr + + example: https://fiddle.skia.org/c/@Canvas_drawDrawable + */ + void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr); + + /** Draws SkDrawable drawable using clip and SkMatrix, offset by (x, y). + + If SkCanvas has an asynchronous implementation, as is the case + when it is recording into SkPicture, then drawable will be referenced, + so that SkDrawable::draw() can be called when the operation is finalized. To force + immediate drawing, call SkDrawable::draw() instead. + + @param drawable custom struct encapsulating drawing commands + @param x offset into SkCanvas writable pixels on x-axis + @param y offset into SkCanvas writable pixels on y-axis + + example: https://fiddle.skia.org/c/@Canvas_drawDrawable_2 + */ + void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y); + + /** Associates SkRect on SkCanvas with an annotation; a key-value pair, where the key is + a null-terminated UTF-8 string, and optional value is stored as SkData. + + Only some canvas implementations, such as recording to SkPicture, or drawing to + document PDF, use annotations. + + @param rect SkRect extent of canvas to annotate + @param key string used for lookup + @param value data holding value stored in annotation + + example: https://fiddle.skia.org/c/@Canvas_drawAnnotation_2 + */ + void drawAnnotation(const SkRect& rect, const char key[], SkData* value); + + /** Associates SkRect on SkCanvas when an annotation; a key-value pair, where the key is + a null-terminated UTF-8 string, and optional value is stored as SkData. + + Only some canvas implementations, such as recording to SkPicture, or drawing to + document PDF, use annotations. + + @param rect SkRect extent of canvas to annotate + @param key string used for lookup + @param value data holding value stored in annotation + */ + void drawAnnotation(const SkRect& rect, const char key[], const sk_sp& value) { + this->drawAnnotation(rect, key, value.get()); + } + + /** Returns true if clip is empty; that is, nothing will draw. + + May do work when called; it should not be called + more often than needed. However, once called, subsequent calls perform no + work until clip changes. + + @return true if clip is empty + + example: https://fiddle.skia.org/c/@Canvas_isClipEmpty + */ + virtual bool isClipEmpty() const; + + /** Returns true if clip is SkRect and not empty. + Returns false if the clip is empty, or if it is not SkRect. + + @return true if clip is SkRect and not empty + + example: https://fiddle.skia.org/c/@Canvas_isClipRect + */ + virtual bool isClipRect() const; + + /** Returns the current transform from local coordinates to the 'device', which for most + * purposes means pixels. + * + * @return transformation from local coordinates to device / pixels. + */ + SkM44 getLocalToDevice() const; + + /** + * Throws away the 3rd row and column in the matrix, so be warned. + */ + SkMatrix getLocalToDeviceAs3x3() const { + return this->getLocalToDevice().asM33(); + } + +#ifdef SK_SUPPORT_LEGACY_GETTOTALMATRIX + /** DEPRECATED + * Legacy version of getLocalToDevice(), which strips away any Z information, and + * just returns a 3x3 version. + * + * @return 3x3 version of getLocalToDevice() + * + * example: https://fiddle.skia.org/c/@Canvas_getTotalMatrix + * example: https://fiddle.skia.org/c/@Clip + */ + SkMatrix getTotalMatrix() const; +#endif + + /////////////////////////////////////////////////////////////////////////// + +#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_GANESH) + // These methods exist to support WebView in Android Framework. + SkIRect topLayerBounds() const; + GrBackendRenderTarget topLayerBackendRenderTarget() const; +#endif + + /** + * Returns the global clip as a region. If the clip contains AA, then only the bounds + * of the clip may be returned. + */ + void temporary_internal_getRgnClip(SkRegion* region); + + void private_draw_shadow_rec(const SkPath&, const SkDrawShadowRec&); + + +protected: + // default impl defers to getDevice()->newSurface(info) + virtual sk_sp onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props); + + // default impl defers to its device + virtual bool onPeekPixels(SkPixmap* pixmap); + virtual bool onAccessTopLayerPixels(SkPixmap* pixmap); + virtual SkImageInfo onImageInfo() const; + virtual bool onGetProps(SkSurfaceProps* props, bool top) const; + virtual void onFlush(); + + // Subclass save/restore notifiers. + // Overriders should call the corresponding INHERITED method up the inheritance chain. + // getSaveLayerStrategy()'s return value may suppress full layer allocation. + enum SaveLayerStrategy { + kFullLayer_SaveLayerStrategy, + kNoLayer_SaveLayerStrategy, + }; + + virtual void willSave() {} + // Overriders should call the corresponding INHERITED method up the inheritance chain. + virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& ) { + return kFullLayer_SaveLayerStrategy; + } + + // returns true if we should actually perform the saveBehind, or false if we should just save. + virtual bool onDoSaveBehind(const SkRect*) { return true; } + virtual void willRestore() {} + virtual void didRestore() {} + + virtual void didConcat44(const SkM44&) {} + virtual void didSetM44(const SkM44&) {} + virtual void didTranslate(SkScalar, SkScalar) {} + virtual void didScale(SkScalar, SkScalar) {} + + // NOTE: If you are adding a new onDraw virtual to SkCanvas, PLEASE add an override to + // SkCanvasVirtualEnforcer (in SkCanvasVirtualEnforcer.h). This ensures that subclasses using + // that mechanism will be required to implement the new function. + virtual void onDrawPaint(const SkPaint& paint); + virtual void onDrawBehind(const SkPaint& paint); + virtual void onDrawRect(const SkRect& rect, const SkPaint& paint); + virtual void onDrawRRect(const SkRRect& rrect, const SkPaint& paint); + virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); + virtual void onDrawOval(const SkRect& rect, const SkPaint& paint); + virtual void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint); + virtual void onDrawPath(const SkPath& path, const SkPaint& paint); + virtual void onDrawRegion(const SkRegion& region, const SkPaint& paint); + + virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint); + + virtual void onDrawGlyphRunList(const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); + + virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); + virtual void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint); + + virtual void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, + const SkPaint*); + virtual void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst, + const SkSamplingOptions&, const SkPaint*, SrcRectConstraint); + virtual void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect& dst, + SkFilterMode, const SkPaint*); + virtual void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect src[], + const SkColor[], int count, SkBlendMode, const SkSamplingOptions&, + const SkRect* cull, const SkPaint*); + virtual void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count, + const SkPoint dstClips[], const SkMatrix preViewMatrices[], + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint); + + virtual void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, + const SkPaint& paint); +#ifdef SK_ENABLE_SKSL + virtual void onDrawMesh(const SkMesh&, sk_sp, const SkPaint&); +#endif + virtual void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value); + virtual void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&); + + virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix); + virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint); + + virtual void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, + const SkColor4f& color, SkBlendMode mode); + + enum ClipEdgeStyle { + kHard_ClipEdgeStyle, + kSoft_ClipEdgeStyle + }; + + virtual void onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle); + virtual void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle); + virtual void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle); + virtual void onClipShader(sk_sp, SkClipOp); + virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp op); + virtual void onResetClip(); + + virtual void onDiscard(); + +#if (defined(SK_GANESH) || defined(SK_GRAPHITE)) + /** Experimental + */ + virtual sk_sp onConvertGlyphRunListToSlug( + const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); + + /** Experimental + */ + virtual void onDrawSlug(const sktext::gpu::Slug* slug); +#endif + +private: + + enum ShaderOverrideOpacity { + kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) + kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque + kNotOpaque_ShaderOverrideOpacity, //!< the overriding shader may not be opaque + }; + + // notify our surface (if we have one) that we are about to draw, so it + // can perform copy-on-write or invalidate any cached images + // returns false if the copy failed + bool SK_WARN_UNUSED_RESULT predrawNotify(bool willOverwritesEntireSurface = false); + bool SK_WARN_UNUSED_RESULT predrawNotify(const SkRect*, const SkPaint*, ShaderOverrideOpacity); + + enum class CheckForOverwrite : bool { + kNo = false, + kYes = true + }; + // call the appropriate predrawNotify and create a layer if needed. + std::optional aboutToDraw( + SkCanvas* canvas, + const SkPaint& paint, + const SkRect* rawBounds = nullptr, + CheckForOverwrite = CheckForOverwrite::kNo, + ShaderOverrideOpacity = kNone_ShaderOverrideOpacity); + + // The bottom-most device in the stack, only changed by init(). Image properties and the final + // canvas pixels are determined by this device. + SkBaseDevice* baseDevice() const { + SkASSERT(fBaseDevice); + return fBaseDevice.get(); + } + + // The top-most device in the stack, will change within saveLayer()'s. All drawing and clipping + // operations should route to this device. + SkBaseDevice* topDevice() const; + + // Canvases maintain a sparse stack of layers, where the top-most layer receives the drawing, + // clip, and matrix commands. There is a layer per call to saveLayer() using the + // kFullLayer_SaveLayerStrategy. + struct Layer { + sk_sp fDevice; + sk_sp fImageFilter; // applied to layer *before* being drawn by paint + SkPaint fPaint; + bool fDiscard; + + Layer(sk_sp device, sk_sp imageFilter, const SkPaint& paint); + }; + + // Encapsulate state needed to restore from saveBehind() + struct BackImage { + // Out of line to avoid including SkSpecialImage.h + BackImage(sk_sp, SkIPoint); + BackImage(const BackImage&); + BackImage(BackImage&&); + BackImage& operator=(const BackImage&); + ~BackImage(); + + sk_sp fImage; + SkIPoint fLoc; + }; + + class MCRec { + public: + // If not null, this MCRec corresponds with the saveLayer() record that made the layer. + // The base "layer" is not stored here, since it is stored inline in SkCanvas and has no + // restoration behavior. + std::unique_ptr fLayer; + + // This points to the device of the top-most layer (which may be lower in the stack), or + // to the canvas's fBaseDevice. The MCRec does not own the device. + SkBaseDevice* fDevice; + + std::unique_ptr fBackImage; + SkM44 fMatrix; + int fDeferredSaveCount = 0; + + MCRec(SkBaseDevice* device); + MCRec(const MCRec* prev); + ~MCRec(); + + void newLayer(sk_sp layerDevice, + sk_sp filter, + const SkPaint& restorePaint); + + void reset(SkBaseDevice* device); + }; + + // the first N recs that can fit here mean we won't call malloc + static constexpr int kMCRecSize = 96; // most recent measurement + static constexpr int kMCRecCount = 32; // common depth for save/restores + + intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)]; + + SkDeque fMCStack; + // points to top of stack + MCRec* fMCRec; + + // Installed via init() + sk_sp fBaseDevice; + const SkSurfaceProps fProps; + + int fSaveCount; // value returned by getSaveCount() + + std::unique_ptr fAllocator; + + SkSurface_Base* fSurfaceBase; + SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; } + void setSurfaceBase(SkSurface_Base* sb) { + fSurfaceBase = sb; + } + friend class SkSurface_Base; + friend class SkSurface_Ganesh; + + SkIRect fClipRestrictionRect = SkIRect::MakeEmpty(); + int fClipRestrictionSaveCount = -1; + + void doSave(); + void checkForDeferredSave(); + void internalSetMatrix(const SkM44&); + + friend class SkAndroidFrameworkUtils; + friend class SkCanvasPriv; // needs to expose android functions for testing outside android + friend class AutoLayerForImageFilter; + friend class SkSurface_Raster; // needs getDevice() + friend class SkNoDrawCanvas; // needs resetForNextPicture() + friend class SkNWayCanvas; + friend class SkPictureRecord; // predrawNotify (why does it need it? ) + friend class SkOverdrawCanvas; + friend class SkRasterHandleAllocator; + friend class SkRecords::Draw; + template + friend class SkTestCanvas; + +protected: + // For use by SkNoDrawCanvas (via SkCanvasVirtualEnforcer, which can't be a friend) + SkCanvas(const SkIRect& bounds); +private: + SkCanvas(const SkBitmap&, std::unique_ptr, + SkRasterHandleAllocator::Handle, const SkSurfaceProps* props); + + SkCanvas(SkCanvas&&) = delete; + SkCanvas(const SkCanvas&) = delete; + SkCanvas& operator=(SkCanvas&&) = delete; + SkCanvas& operator=(const SkCanvas&) = delete; + +#if (defined(SK_GANESH) || defined(SK_GRAPHITE)) + friend class sktext::gpu::Slug; + /** Experimental + * Convert a SkTextBlob to a sktext::gpu::Slug using the current canvas state. + */ + sk_sp convertBlobToSlug(const SkTextBlob& blob, SkPoint origin, + const SkPaint& paint); + + /** Experimental + * Draw an sktext::gpu::Slug given the current canvas state. + */ + void drawSlug(const sktext::gpu::Slug* slug); +#endif + + /** Experimental + * Saves the specified subset of the current pixels in the current layer, + * and then clears those pixels to transparent black. + * Restores the pixels on restore() by drawing them in SkBlendMode::kDstOver. + * + * @param subset conservative bounds of the area to be saved / restored. + * @return depth of save state stack before this call was made. + */ + int only_axis_aligned_saveBehind(const SkRect* subset); + + /** + * Like drawPaint, but magically clipped to the most recent saveBehind buffer rectangle. + * If there is no active saveBehind, then this draws nothing. + */ + void drawClippedToSaveBehind(const SkPaint&); + + void resetForNextPicture(const SkIRect& bounds); + + // needs gettotalclip() + friend class SkCanvasStateUtils; + + void init(sk_sp); + + // All base onDrawX() functions should call this and skip drawing if it returns true. + // If 'matrix' is non-null, it maps the paint's fast bounds before checking for quick rejection + bool internalQuickReject(const SkRect& bounds, const SkPaint& paint, + const SkMatrix* matrix = nullptr); + + void internalDrawPaint(const SkPaint& paint); + void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy); + void internalSaveBehind(const SkRect*); + + void internalConcat44(const SkM44&); + + // shared by save() and saveLayer() + void internalSave(); + void internalRestore(); + + enum class DeviceCompatibleWithFilter : bool { + // Check the src device's local-to-device matrix for compatibility with the filter, and if + // it is not compatible, introduce an intermediate image and transformation that allows the + // filter to be evaluated on the modified src content. + kUnknown = false, + // Assume that the src device's local-to-device matrix is compatible with the filter. + kYes = true + }; + /** + * Filters the contents of 'src' and draws the result into 'dst'. The filter is evaluated + * relative to the current canvas matrix, and src is drawn to dst using their relative transform + * 'paint' is applied after the filter and must not have a mask or image filter of its own. + * A null 'filter' behaves as if the identity filter were used. + * + * 'scaleFactor' is an extra uniform scale transform applied to downscale the 'src' image + * before any filtering, or as part of the copy, and is then drawn with 1/scaleFactor to 'dst'. + * Must be 1.0 if 'compat' is kYes (i.e. any scale factor has already been baked into the + * relative transforms between the devices). + */ + void internalDrawDeviceWithFilter(SkBaseDevice* src, SkBaseDevice* dst, + const SkImageFilter* filter, const SkPaint& paint, + DeviceCompatibleWithFilter compat, + SkScalar scaleFactor = 1.f); + + /* + * Returns true if drawing the specified rect (or all if it is null) with the specified + * paint (or default if null) would overwrite the entire root device of the canvas + * (i.e. the canvas' surface if it had one). + */ + bool wouldOverwriteEntireSurface(const SkRect*, const SkPaint*, ShaderOverrideOpacity) const; + + /** + * Returns true if the paint's imagefilter can be invoked directly, without needed a layer. + */ + bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkSamplingOptions&, + const SkPaint&); + + /** + * Returns true if the clip (for any active layer) contains antialiasing. + * If the clip is empty, this will return false. + */ + bool androidFramework_isClipAA() const; + + /** + * Reset the clip to be wide-open (modulo any separately specified device clip restriction). + * This operate within the save/restore clip stack so it can be undone by restoring to an + * earlier save point. + */ + void internal_private_resetClip(); + + virtual SkPaintFilterCanvas* internal_private_asPaintFilterCanvas() const { return nullptr; } + + // Keep track of the device clip bounds in the canvas' global space to reject draws before + // invoking the top-level device. + SkRect fQuickRejectBounds; + + // Compute the clip's bounds based on all clipped SkDevice's reported device bounds transformed + // into the canvas' global space. + SkRect computeDeviceClipBounds(bool outsetForAA=true) const; + + class AutoUpdateQRBounds; + void validateClip() const; + + std::unique_ptr fScratchGlyphRunBuilder; + + using INHERITED = SkRefCnt; +}; + +/** \class SkAutoCanvasRestore + Stack helper class calls SkCanvas::restoreToCount when SkAutoCanvasRestore + goes out of scope. Use this to guarantee that the canvas is restored to a known + state. +*/ +class SkAutoCanvasRestore { +public: + + /** Preserves SkCanvas::save() count. Optionally saves SkCanvas clip and SkCanvas matrix. + + @param canvas SkCanvas to guard + @param doSave call SkCanvas::save() + @return utility to restore SkCanvas state on destructor + */ + SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas), fSaveCount(0) { + if (fCanvas) { + fSaveCount = canvas->getSaveCount(); + if (doSave) { + canvas->save(); + } + } + } + + /** Restores SkCanvas to saved state. Destructor is called when container goes out of + scope. + */ + ~SkAutoCanvasRestore() { + if (fCanvas) { + fCanvas->restoreToCount(fSaveCount); + } + } + + /** Restores SkCanvas to saved state immediately. Subsequent calls and + ~SkAutoCanvasRestore() have no effect. + */ + void restore() { + if (fCanvas) { + fCanvas->restoreToCount(fSaveCount); + fCanvas = nullptr; + } + } + +private: + SkCanvas* fCanvas; + int fSaveCount; + + SkAutoCanvasRestore(SkAutoCanvasRestore&&) = delete; + SkAutoCanvasRestore(const SkAutoCanvasRestore&) = delete; + SkAutoCanvasRestore& operator=(SkAutoCanvasRestore&&) = delete; + SkAutoCanvasRestore& operator=(const SkAutoCanvasRestore&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCanvasVirtualEnforcer.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCanvasVirtualEnforcer.h new file mode 100644 index 00000000000000..5086b4337d3f7e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCanvasVirtualEnforcer.h @@ -0,0 +1,61 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCanvasVirtualEnforcer_DEFINED +#define SkCanvasVirtualEnforcer_DEFINED + +#include "include/core/SkCanvas.h" + +// If you would ordinarily want to inherit from Base (eg SkCanvas, SkNWayCanvas), instead +// inherit from SkCanvasVirtualEnforcer, which will make the build fail if you forget +// to override one of SkCanvas' key virtual hooks. +template +class SkCanvasVirtualEnforcer : public Base { +public: + using Base::Base; + +protected: + void onDrawPaint(const SkPaint& paint) override = 0; + void onDrawBehind(const SkPaint&) override {} // make zero after android updates + void onDrawRect(const SkRect& rect, const SkPaint& paint) override = 0; + void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override = 0; + void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) override = 0; + void onDrawOval(const SkRect& rect, const SkPaint& paint) override = 0; + void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, + const SkPaint& paint) override = 0; + void onDrawPath(const SkPath& path, const SkPaint& paint) override = 0; + void onDrawRegion(const SkRegion& region, const SkPaint& paint) override = 0; + + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override = 0; + + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode mode, + const SkPaint& paint) override = 0; + void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) override = 0; + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + // This is under active development for Chrome and not used in Android. Hold off on adding + // implementations in Android's SkCanvas subclasses until this stabilizes. + void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], + SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, SkBlendMode mode) override {} +#else + void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], + SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, SkBlendMode mode) override = 0; +#endif + + void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override = 0; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override = 0; + + void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override = 0; + void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint) override = 0; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCapabilities.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCapabilities.h new file mode 100644 index 00000000000000..214b5138f0b71d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCapabilities.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCapabilities_DEFINED +#define SkCapabilities_DEFINED + +#include "include/core/SkRefCnt.h" + +#ifdef SK_ENABLE_SKSL +#include "include/sksl/SkSLVersion.h" +namespace SkSL { struct ShaderCaps; } +#endif + +#if defined(SK_GRAPHITE) +namespace skgpu::graphite { class Caps; } +#endif + +class SK_API SkCapabilities : public SkRefCnt { +public: + static sk_sp RasterBackend(); + +#ifdef SK_ENABLE_SKSL + SkSL::Version skslVersion() const { return fSkSLVersion; } +#endif + +protected: +#if defined(SK_GRAPHITE) + friend class skgpu::graphite::Caps; // for ctor +#endif + + SkCapabilities() = default; + +#ifdef SK_ENABLE_SKSL + void initSkCaps(const SkSL::ShaderCaps*); + + SkSL::Version fSkSLVersion = SkSL::Version::k100; +#endif +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkClipOp.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkClipOp.h new file mode 100644 index 00000000000000..3da6c61131f7b2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkClipOp.h @@ -0,0 +1,19 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkClipOp_DEFINED +#define SkClipOp_DEFINED + +#include "include/core/SkTypes.h" + +enum class SkClipOp { + kDifference = 0, + kIntersect = 1, + kMax_EnumValue = kIntersect +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColor.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColor.h new file mode 100644 index 00000000000000..3b46be030f224d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColor.h @@ -0,0 +1,447 @@ +/* + * 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 SkColor_DEFINED +#define SkColor_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" + +#include +#include + +/** \file SkColor.h + + Types, consts, functions, and macros for colors. +*/ + +/** 8-bit type for an alpha value. 255 is 100% opaque, zero is 100% transparent. +*/ +typedef uint8_t SkAlpha; + +/** 32-bit ARGB color value, unpremultiplied. Color components are always in + a known order. This is different from SkPMColor, which has its bytes in a configuration + dependent order, to match the format of kBGRA_8888_SkColorType bitmaps. SkColor + is the type used to specify colors in SkPaint and in gradients. + + Color that is premultiplied has the same component values as color + that is unpremultiplied if alpha is 255, fully opaque, although may have the + component values in a different order. +*/ +typedef uint32_t SkColor; + +/** Returns color value from 8-bit component values. Asserts if SK_DEBUG is defined + if a, r, g, or b exceed 255. Since color is unpremultiplied, a may be smaller + than the largest of r, g, and b. + + @param a amount of alpha, from fully transparent (0) to fully opaque (255) + @param r amount of red, from no red (0) to full red (255) + @param g amount of green, from no green (0) to full green (255) + @param b amount of blue, from no blue (0) to full blue (255) + @return color and alpha, unpremultiplied +*/ +static constexpr inline SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + return SkASSERT(a <= 255 && r <= 255 && g <= 255 && b <= 255), + (a << 24) | (r << 16) | (g << 8) | (b << 0); +} + +/** Returns color value from 8-bit component values, with alpha set + fully opaque to 255. +*/ +#define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b) + +/** Returns alpha byte from color value. +*/ +#define SkColorGetA(color) (((color) >> 24) & 0xFF) + +/** Returns red component of color, from zero to 255. +*/ +#define SkColorGetR(color) (((color) >> 16) & 0xFF) + +/** Returns green component of color, from zero to 255. +*/ +#define SkColorGetG(color) (((color) >> 8) & 0xFF) + +/** Returns blue component of color, from zero to 255. +*/ +#define SkColorGetB(color) (((color) >> 0) & 0xFF) + +/** Returns unpremultiplied color with red, blue, and green set from c; and alpha set + from a. Alpha component of c is ignored and is replaced by a in result. + + @param c packed RGB, eight bits per component + @param a alpha: transparent at zero, fully opaque at 255 + @return color with transparency +*/ +static constexpr inline SkColor SK_WARN_UNUSED_RESULT SkColorSetA(SkColor c, U8CPU a) { + return (c & 0x00FFFFFF) | (a << 24); +} + +/** Represents fully transparent SkAlpha value. SkAlpha ranges from zero, + fully transparent; to 255, fully opaque. +*/ +constexpr SkAlpha SK_AlphaTRANSPARENT = 0x00; + +/** Represents fully opaque SkAlpha value. SkAlpha ranges from zero, + fully transparent; to 255, fully opaque. +*/ +constexpr SkAlpha SK_AlphaOPAQUE = 0xFF; + +/** Represents fully transparent SkColor. May be used to initialize a destination + containing a mask or a non-rectangular image. +*/ +constexpr SkColor SK_ColorTRANSPARENT = SkColorSetARGB(0x00, 0x00, 0x00, 0x00); + +/** Represents fully opaque black. +*/ +constexpr SkColor SK_ColorBLACK = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00); + +/** Represents fully opaque dark gray. + Note that SVG dark gray is equivalent to 0xFFA9A9A9. +*/ +constexpr SkColor SK_ColorDKGRAY = SkColorSetARGB(0xFF, 0x44, 0x44, 0x44); + +/** Represents fully opaque gray. + Note that HTML gray is equivalent to 0xFF808080. +*/ +constexpr SkColor SK_ColorGRAY = SkColorSetARGB(0xFF, 0x88, 0x88, 0x88); + +/** Represents fully opaque light gray. HTML silver is equivalent to 0xFFC0C0C0. + Note that SVG light gray is equivalent to 0xFFD3D3D3. +*/ +constexpr SkColor SK_ColorLTGRAY = SkColorSetARGB(0xFF, 0xCC, 0xCC, 0xCC); + +/** Represents fully opaque white. +*/ +constexpr SkColor SK_ColorWHITE = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF); + +/** Represents fully opaque red. +*/ +constexpr SkColor SK_ColorRED = SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00); + +/** Represents fully opaque green. HTML lime is equivalent. + Note that HTML green is equivalent to 0xFF008000. +*/ +constexpr SkColor SK_ColorGREEN = SkColorSetARGB(0xFF, 0x00, 0xFF, 0x00); + +/** Represents fully opaque blue. +*/ +constexpr SkColor SK_ColorBLUE = SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF); + +/** Represents fully opaque yellow. +*/ +constexpr SkColor SK_ColorYELLOW = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0x00); + +/** Represents fully opaque cyan. HTML aqua is equivalent. +*/ +constexpr SkColor SK_ColorCYAN = SkColorSetARGB(0xFF, 0x00, 0xFF, 0xFF); + +/** Represents fully opaque magenta. HTML fuchsia is equivalent. +*/ +constexpr SkColor SK_ColorMAGENTA = SkColorSetARGB(0xFF, 0xFF, 0x00, 0xFF); + +/** Converts RGB to its HSV components. + hsv[0] contains hsv hue, a value from zero to less than 360. + hsv[1] contains hsv saturation, a value from zero to one. + hsv[2] contains hsv value, a value from zero to one. + + @param red red component value from zero to 255 + @param green green component value from zero to 255 + @param blue blue component value from zero to 255 + @param hsv three element array which holds the resulting HSV components +*/ +SK_API void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]); + +/** Converts ARGB to its HSV components. Alpha in ARGB is ignored. + hsv[0] contains hsv hue, and is assigned a value from zero to less than 360. + hsv[1] contains hsv saturation, a value from zero to one. + hsv[2] contains hsv value, a value from zero to one. + + @param color ARGB color to convert + @param hsv three element array which holds the resulting HSV components +*/ +static inline void SkColorToHSV(SkColor color, SkScalar hsv[3]) { + SkRGBToHSV(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), hsv); +} + +/** Converts HSV components to an ARGB color. Alpha is passed through unchanged. + hsv[0] represents hsv hue, an angle from zero to less than 360. + hsv[1] represents hsv saturation, and varies from zero to one. + hsv[2] represents hsv value, and varies from zero to one. + + Out of range hsv values are pinned. + + @param alpha alpha component of the returned ARGB color + @param hsv three element array which holds the input HSV components + @return ARGB equivalent to HSV +*/ +SK_API SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]); + +/** Converts HSV components to an ARGB color. Alpha is set to 255. + hsv[0] represents hsv hue, an angle from zero to less than 360. + hsv[1] represents hsv saturation, and varies from zero to one. + hsv[2] represents hsv value, and varies from zero to one. + + Out of range hsv values are pinned. + + @param hsv three element array which holds the input HSV components + @return RGB equivalent to HSV +*/ +static inline SkColor SkHSVToColor(const SkScalar hsv[3]) { + return SkHSVToColor(0xFF, hsv); +} + +/** 32-bit ARGB color value, premultiplied. The byte order for this value is + configuration dependent, matching the format of kBGRA_8888_SkColorType bitmaps. + This is different from SkColor, which is unpremultiplied, and is always in the + same byte order. +*/ +typedef uint32_t SkPMColor; + +/** Returns a SkPMColor value from unpremultiplied 8-bit component values. + + @param a amount of alpha, from fully transparent (0) to fully opaque (255) + @param r amount of red, from no red (0) to full red (255) + @param g amount of green, from no green (0) to full green (255) + @param b amount of blue, from no blue (0) to full blue (255) + @return premultiplied color +*/ +SK_API SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); + +/** Returns pmcolor closest to color c. Multiplies c RGB components by the c alpha, + and arranges the bytes to match the format of kN32_SkColorType. + + @param c unpremultiplied ARGB color + @return premultiplied color +*/ +SK_API SkPMColor SkPreMultiplyColor(SkColor c); + +/** \enum SkColorChannel + Describes different color channels one can manipulate +*/ +enum class SkColorChannel { + kR, // the red channel + kG, // the green channel + kB, // the blue channel + kA, // the alpha channel + + kLastEnum = kA, +}; + +/** Used to represent the channels available in a color type or texture format as a mask. */ +enum SkColorChannelFlag : uint32_t { + kRed_SkColorChannelFlag = 1 << static_cast(SkColorChannel::kR), + kGreen_SkColorChannelFlag = 1 << static_cast(SkColorChannel::kG), + kBlue_SkColorChannelFlag = 1 << static_cast(SkColorChannel::kB), + kAlpha_SkColorChannelFlag = 1 << static_cast(SkColorChannel::kA), + kGray_SkColorChannelFlag = 0x10, + // Convenience values + kGrayAlpha_SkColorChannelFlags = kGray_SkColorChannelFlag | kAlpha_SkColorChannelFlag, + kRG_SkColorChannelFlags = kRed_SkColorChannelFlag | kGreen_SkColorChannelFlag, + kRGB_SkColorChannelFlags = kRG_SkColorChannelFlags | kBlue_SkColorChannelFlag, + kRGBA_SkColorChannelFlags = kRGB_SkColorChannelFlags | kAlpha_SkColorChannelFlag, +}; +static_assert(0 == (kGray_SkColorChannelFlag & kRGBA_SkColorChannelFlags), "bitfield conflict"); + +/** \struct SkRGBA4f + RGBA color value, holding four floating point components. Color components are always in + a known order. kAT determines if the SkRGBA4f's R, G, and B components are premultiplied + by alpha or not. + + Skia's public API always uses unpremultiplied colors, which can be stored as + SkRGBA4f. For convenience, this type can also be referred to + as SkColor4f. +*/ +template +struct SkRGBA4f { + float fR; //!< red component + float fG; //!< green component + float fB; //!< blue component + float fA; //!< alpha component + + /** Compares SkRGBA4f with other, and returns true if all components are equal. + + @param other SkRGBA4f to compare + @return true if SkRGBA4f equals other + */ + bool operator==(const SkRGBA4f& other) const { + return fA == other.fA && fR == other.fR && fG == other.fG && fB == other.fB; + } + + /** Compares SkRGBA4f with other, and returns true if not all components are equal. + + @param other SkRGBA4f to compare + @return true if SkRGBA4f is not equal to other + */ + bool operator!=(const SkRGBA4f& other) const { + return !(*this == other); + } + + /** Returns SkRGBA4f multiplied by scale. + + @param scale value to multiply by + @return SkRGBA4f as (fR * scale, fG * scale, fB * scale, fA * scale) + */ + SkRGBA4f operator*(float scale) const { + return { fR * scale, fG * scale, fB * scale, fA * scale }; + } + + /** Returns SkRGBA4f multiplied component-wise by scale. + + @param scale SkRGBA4f to multiply by + @return SkRGBA4f as (fR * scale.fR, fG * scale.fG, fB * scale.fB, fA * scale.fA) + */ + SkRGBA4f operator*(const SkRGBA4f& scale) const { + return { fR * scale.fR, fG * scale.fG, fB * scale.fB, fA * scale.fA }; + } + + /** Returns a pointer to components of SkRGBA4f, for array access. + + @return pointer to array [fR, fG, fB, fA] + */ + const float* vec() const { return &fR; } + + /** Returns a pointer to components of SkRGBA4f, for array access. + + @return pointer to array [fR, fG, fB, fA] + */ + float* vec() { return &fR; } + + /** As a std::array */ + std::array array() const { return {fR, fG, fB, fA}; } + + /** Returns one component. Asserts if index is out of range and SK_DEBUG is defined. + + @param index one of: 0 (fR), 1 (fG), 2 (fB), 3 (fA) + @return value corresponding to index + */ + float operator[](int index) const { + SkASSERT(index >= 0 && index < 4); + return this->vec()[index]; + } + + /** Returns one component. Asserts if index is out of range and SK_DEBUG is defined. + + @param index one of: 0 (fR), 1 (fG), 2 (fB), 3 (fA) + @return value corresponding to index + */ + float& operator[](int index) { + SkASSERT(index >= 0 && index < 4); + return this->vec()[index]; + } + + /** Returns true if SkRGBA4f is an opaque color. Asserts if fA is out of range and + SK_DEBUG is defined. + + @return true if SkRGBA4f is opaque + */ + bool isOpaque() const { + SkASSERT(fA <= 1.0f && fA >= 0.0f); + return fA == 1.0f; + } + + /** Returns true if all channels are in [0, 1]. */ + bool fitsInBytes() const { + SkASSERT(fA >= 0.0f && fA <= 1.0f); + return fR >= 0.0f && fR <= 1.0f && + fG >= 0.0f && fG <= 1.0f && + fB >= 0.0f && fB <= 1.0f; + } + + /** Returns closest SkRGBA4f to SkColor. Only allowed if SkRGBA4f is unpremultiplied. + + @param color Color with Alpha, red, blue, and green components + @return SkColor as SkRGBA4f + + example: https://fiddle.skia.org/c/@RGBA4f_FromColor + */ + static SkRGBA4f FromColor(SkColor color); // impl. depends on kAT + + /** Returns closest SkColor to SkRGBA4f. Only allowed if SkRGBA4f is unpremultiplied. + + @return color as SkColor + + example: https://fiddle.skia.org/c/@RGBA4f_toSkColor + */ + SkColor toSkColor() const; // impl. depends on kAT + + /** Returns closest SkRGBA4f to SkPMColor. Only allowed if SkRGBA4f is premultiplied. + + @return SkPMColor as SkRGBA4f + */ + static SkRGBA4f FromPMColor(SkPMColor); // impl. depends on kAT + + /** Returns SkRGBA4f premultiplied by alpha. Asserts at compile time if SkRGBA4f is + already premultiplied. + + @return premultiplied color + */ + SkRGBA4f premul() const { + static_assert(kAT == kUnpremul_SkAlphaType, ""); + return { fR * fA, fG * fA, fB * fA, fA }; + } + + /** Returns SkRGBA4f unpremultiplied by alpha. Asserts at compile time if SkRGBA4f is + already unpremultiplied. + + @return unpremultiplied color + */ + SkRGBA4f unpremul() const { + static_assert(kAT == kPremul_SkAlphaType, ""); + + if (fA == 0.0f) { + return { 0, 0, 0, 0 }; + } else { + float invAlpha = 1 / fA; + return { fR * invAlpha, fG * invAlpha, fB * invAlpha, fA }; + } + } + + // This produces bytes in RGBA order (eg GrColor). Impl. is the same, regardless of kAT + uint32_t toBytes_RGBA() const; + static SkRGBA4f FromBytes_RGBA(uint32_t color); + + /** + Returns a copy of the SkRGBA4f but with alpha component set to 1.0f. + + @return opaque color + */ + SkRGBA4f makeOpaque() const { + return { fR, fG, fB, 1.0f }; + } +}; + +/** \struct SkColor4f + RGBA color value, holding four floating point components. Color components are always in + a known order, and are unpremultiplied. + + This is a specialization of SkRGBA4f. For details, @see SkRGBA4f. +*/ +using SkColor4f = SkRGBA4f; + +template <> SK_API SkColor4f SkColor4f::FromColor(SkColor); +template <> SK_API SkColor SkColor4f::toSkColor() const; +template <> SK_API uint32_t SkColor4f::toBytes_RGBA() const; +template <> SK_API SkColor4f SkColor4f::FromBytes_RGBA(uint32_t color); + +namespace SkColors { +constexpr SkColor4f kTransparent = {0, 0, 0, 0}; +constexpr SkColor4f kBlack = {0, 0, 0, 1}; +constexpr SkColor4f kDkGray = {0.25f, 0.25f, 0.25f, 1}; +constexpr SkColor4f kGray = {0.50f, 0.50f, 0.50f, 1}; +constexpr SkColor4f kLtGray = {0.75f, 0.75f, 0.75f, 1}; +constexpr SkColor4f kWhite = {1, 1, 1, 1}; +constexpr SkColor4f kRed = {1, 0, 0, 1}; +constexpr SkColor4f kGreen = {0, 1, 0, 1}; +constexpr SkColor4f kBlue = {0, 0, 1, 1}; +constexpr SkColor4f kYellow = {1, 1, 0, 1}; +constexpr SkColor4f kCyan = {0, 1, 1, 1}; +constexpr SkColor4f kMagenta = {1, 0, 1, 1}; +} // namespace SkColors +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorFilter.h new file mode 100644 index 00000000000000..1e0f6ea6f5821f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorFilter.h @@ -0,0 +1,128 @@ +/* + * 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 SkColorFilter_DEFINED +#define SkColorFilter_DEFINED + +#include "include/core/SkBlendMode.h" +#include "include/core/SkColor.h" +#include "include/core/SkFlattenable.h" + +class SkColorMatrix; +class SkColorSpace; + +/** +* ColorFilters are optional objects in the drawing pipeline. When present in +* a paint, they are called with the "src" colors, and return new colors, which +* are then passed onto the next stage (either ImageFilter or Xfermode). +* +* All subclasses are required to be reentrant-safe : it must be legal to share +* the same instance between several threads. +*/ +class SK_API SkColorFilter : public SkFlattenable { +public: + /** If the filter can be represented by a source color plus Mode, this + * returns true, and sets (if not NULL) the color and mode appropriately. + * If not, this returns false and ignores the parameters. + */ + bool asAColorMode(SkColor* color, SkBlendMode* mode) const; + + /** If the filter can be represented by a 5x4 matrix, this + * returns true, and sets the matrix appropriately. + * If not, this returns false and ignores the parameter. + */ + bool asAColorMatrix(float matrix[20]) const; + + // Returns true if the filter is guaranteed to never change the alpha of a color it filters. + bool isAlphaUnchanged() const; + + SkColor filterColor(SkColor) const; + + /** + * Converts the src color (in src colorspace), into the dst colorspace, + * then applies this filter to it, returning the filtered color in the dst colorspace. + */ + SkColor4f filterColor4f(const SkColor4f& srcColor, SkColorSpace* srcCS, + SkColorSpace* dstCS) const; + + /** Construct a colorfilter whose effect is to first apply the inner filter and then apply + * this filter, applied to the output of the inner filter. + * + * result = this(inner(...)) + */ + sk_sp makeComposed(sk_sp inner) const; + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr); + +private: + SkColorFilter() = default; + friend class SkColorFilterBase; + + using INHERITED = SkFlattenable; +}; + +class SK_API SkColorFilters { +public: + static sk_sp Compose(sk_sp outer, sk_sp inner) { + return outer ? outer->makeComposed(inner) : inner; + } + + // Blends between the constant color (src) and input color (dst) based on the SkBlendMode. + // If the color space is null, the constant color is assumed to be defined in sRGB. + static sk_sp Blend(const SkColor4f& c, sk_sp, SkBlendMode mode); + static sk_sp Blend(SkColor c, SkBlendMode mode); + + static sk_sp Matrix(const SkColorMatrix&); + static sk_sp Matrix(const float rowMajor[20]); + + // A version of Matrix which operates in HSLA space instead of RGBA. + // I.e. HSLA-to-RGBA(Matrix(RGBA-to-HSLA(input))). + static sk_sp HSLAMatrix(const SkColorMatrix&); + static sk_sp HSLAMatrix(const float rowMajor[20]); + + static sk_sp LinearToSRGBGamma(); + static sk_sp SRGBToLinearGamma(); + static sk_sp Lerp(float t, sk_sp dst, sk_sp src); + + /** + * Create a table colorfilter, copying the table into the filter, and + * applying it to all 4 components. + * a' = table[a]; + * r' = table[r]; + * g' = table[g]; + * b' = table[b]; + * Components are operated on in unpremultiplied space. If the incomming + * colors are premultiplied, they are temporarily unpremultiplied, then + * the table is applied, and then the result is remultiplied. + */ + static sk_sp Table(const uint8_t table[256]); + + /** + * Create a table colorfilter, with a different table for each + * component [A, R, G, B]. If a given table is NULL, then it is + * treated as identity, with the component left unchanged. If a table + * is not null, then its contents are copied into the filter. + */ + static sk_sp TableARGB(const uint8_t tableA[256], + const uint8_t tableR[256], + const uint8_t tableG[256], + const uint8_t tableB[256]); + + /** + * Create a colorfilter that multiplies the RGB channels by one color, and + * then adds a second color, pinning the result for each component to + * [0..255]. The alpha components of the mul and add arguments + * are ignored. + */ + static sk_sp Lighting(SkColor mul, SkColor add); + +private: + SkColorFilters() = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorPriv.h new file mode 100644 index 00000000000000..f89de9db72fcb0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorPriv.h @@ -0,0 +1,167 @@ +/* + * 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 SkColorPriv_DEFINED +#define SkColorPriv_DEFINED + +#include "include/core/SkColor.h" +#include "include/private/base/SkMath.h" +#include "include/private/base/SkTPin.h" +#include "include/private/base/SkTo.h" + +#include + +/** Turn 0..255 into 0..256 by adding 1 at the half-way point. Used to turn a + byte into a scale value, so that we can say scale * value >> 8 instead of + alpha * value / 255. + + In debugging, asserts that alpha is 0..255 +*/ +static inline unsigned SkAlpha255To256(U8CPU alpha) { + SkASSERT(SkToU8(alpha) == alpha); + // this one assues that blending on top of an opaque dst keeps it that way + // even though it is less accurate than a+(a>>7) for non-opaque dsts + return alpha + 1; +} + +/** Multiplify value by 0..256, and shift the result down 8 + (i.e. return (value * alpha256) >> 8) + */ +#define SkAlphaMul(value, alpha256) (((value) * (alpha256)) >> 8) + +static inline U8CPU SkUnitScalarClampToByte(SkScalar x) { + return static_cast(SkTPin(x, 0.0f, 1.0f) * 255 + 0.5); +} + +#define SK_A32_BITS 8 +#define SK_R32_BITS 8 +#define SK_G32_BITS 8 +#define SK_B32_BITS 8 + +#define SK_A32_MASK ((1 << SK_A32_BITS) - 1) +#define SK_R32_MASK ((1 << SK_R32_BITS) - 1) +#define SK_G32_MASK ((1 << SK_G32_BITS) - 1) +#define SK_B32_MASK ((1 << SK_B32_BITS) - 1) + +/* + * Skia's 32bit backend only supports 1 swizzle order at a time (compile-time). + * This is specified by SK_R32_SHIFT=0 or SK_R32_SHIFT=16. + * + * For easier compatibility with Skia's GPU backend, we further restrict these + * to either (in memory-byte-order) RGBA or BGRA. Note that this "order" does + * not directly correspond to the same shift-order, since we have to take endianess + * into account. + * + * Here we enforce this constraint. + */ + +#define SK_RGBA_R32_SHIFT 0 +#define SK_RGBA_G32_SHIFT 8 +#define SK_RGBA_B32_SHIFT 16 +#define SK_RGBA_A32_SHIFT 24 + +#define SK_BGRA_B32_SHIFT 0 +#define SK_BGRA_G32_SHIFT 8 +#define SK_BGRA_R32_SHIFT 16 +#define SK_BGRA_A32_SHIFT 24 + +#if defined(SK_PMCOLOR_IS_RGBA) || defined(SK_PMCOLOR_IS_BGRA) + #error "Configure PMCOLOR by setting SK_R32_SHIFT." +#endif + +// Deduce which SK_PMCOLOR_IS_ to define from the _SHIFT defines + +#if (SK_A32_SHIFT == SK_RGBA_A32_SHIFT && \ + SK_R32_SHIFT == SK_RGBA_R32_SHIFT && \ + SK_G32_SHIFT == SK_RGBA_G32_SHIFT && \ + SK_B32_SHIFT == SK_RGBA_B32_SHIFT) + #define SK_PMCOLOR_IS_RGBA +#elif (SK_A32_SHIFT == SK_BGRA_A32_SHIFT && \ + SK_R32_SHIFT == SK_BGRA_R32_SHIFT && \ + SK_G32_SHIFT == SK_BGRA_G32_SHIFT && \ + SK_B32_SHIFT == SK_BGRA_B32_SHIFT) + #define SK_PMCOLOR_IS_BGRA +#else + #error "need 32bit packing to be either RGBA or BGRA" +#endif + +#define SkGetPackedA32(packed) ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24) +#define SkGetPackedR32(packed) ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24) +#define SkGetPackedG32(packed) ((uint32_t)((packed) << (24 - SK_G32_SHIFT)) >> 24) +#define SkGetPackedB32(packed) ((uint32_t)((packed) << (24 - SK_B32_SHIFT)) >> 24) + +#define SkA32Assert(a) SkASSERT((unsigned)(a) <= SK_A32_MASK) +#define SkR32Assert(r) SkASSERT((unsigned)(r) <= SK_R32_MASK) +#define SkG32Assert(g) SkASSERT((unsigned)(g) <= SK_G32_MASK) +#define SkB32Assert(b) SkASSERT((unsigned)(b) <= SK_B32_MASK) + +/** + * Pack the components into a SkPMColor, checking (in the debug version) that + * the components are 0..255, and are already premultiplied (i.e. alpha >= color) + */ +static inline SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkA32Assert(a); + SkASSERT(r <= a); + SkASSERT(g <= a); + SkASSERT(b <= a); + + return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) | + (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT); +} + +/** + * Same as SkPackARGB32, but this version guarantees to not check that the + * values are premultiplied in the debug version. + */ +static inline SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) | + (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT); +} + +static inline +SkPMColor SkPremultiplyARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkA32Assert(a); + SkR32Assert(r); + SkG32Assert(g); + SkB32Assert(b); + + if (a != 255) { + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); + } + return SkPackARGB32(a, r, g, b); +} + +// When Android is compiled optimizing for size, SkAlphaMulQ doesn't get +// inlined; forcing inlining significantly improves performance. +static SK_ALWAYS_INLINE uint32_t SkAlphaMulQ(uint32_t c, unsigned scale) { + uint32_t mask = 0xFF00FF; + + uint32_t rb = ((c & mask) * scale) >> 8; + uint32_t ag = ((c >> 8) & mask) * scale; + return (rb & mask) | (ag & ~mask); +} + +static inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst) { + uint32_t scale = SkAlpha255To256(255 - SkGetPackedA32(src)); + + uint32_t mask = 0xFF00FF; + uint32_t rb = (((dst & mask) * scale) >> 8) & mask; + uint32_t ag = (((dst >> 8) & mask) * scale) & ~mask; + + rb += (src & mask); + ag += (src & ~mask); + + // Color channels (but not alpha) can overflow, so we have to saturate to 0xFF in each lane. + return std::min(rb & 0x000001FF, 0x000000FFU) | + std::min(ag & 0x0001FF00, 0x0000FF00U) | + std::min(rb & 0x01FF0000, 0x00FF0000U) | + (ag & 0xFF000000); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorSpace.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorSpace.h new file mode 100644 index 00000000000000..57c29e222a43b0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorSpace.h @@ -0,0 +1,242 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpace_DEFINED +#define SkColorSpace_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkFixed.h" +#include "include/private/base/SkOnce.h" +#include "modules/skcms/skcms.h" + +#include +#include + +class SkData; + +/** + * Describes a color gamut with primaries and a white point. + */ +struct SK_API SkColorSpacePrimaries { + float fRX; + float fRY; + float fGX; + float fGY; + float fBX; + float fBY; + float fWX; + float fWY; + + /** + * Convert primaries and a white point to a toXYZD50 matrix, the preferred color gamut + * representation of SkColorSpace. + */ + bool toXYZD50(skcms_Matrix3x3* toXYZD50) const; +}; + +namespace SkNamedTransferFn { + +// Like SkNamedGamut::kSRGB, keeping this bitwise exactly the same as skcms makes things fastest. +static constexpr skcms_TransferFunction kSRGB = + { 2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0.0f, 0.0f }; + +static constexpr skcms_TransferFunction k2Dot2 = + { 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + +static constexpr skcms_TransferFunction kLinear = + { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + +static constexpr skcms_TransferFunction kRec2020 = + {2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0}; + +static constexpr skcms_TransferFunction kPQ = + {-2.0f, -107/128.0f, 1.0f, 32/2523.0f, 2413/128.0f, -2392/128.0f, 8192/1305.0f }; + +static constexpr skcms_TransferFunction kHLG = + {-3.0f, 2.0f, 2.0f, 1/0.17883277f, 0.28466892f, 0.55991073f, 0.0f }; + +} // namespace SkNamedTransferFn + +namespace SkNamedGamut { + +static constexpr skcms_Matrix3x3 kSRGB = {{ + // ICC fixed-point (16.16) representation, taken from skcms. Please keep them exactly in sync. + // 0.436065674f, 0.385147095f, 0.143066406f, + // 0.222488403f, 0.716873169f, 0.060607910f, + // 0.013916016f, 0.097076416f, 0.714096069f, + { SkFixedToFloat(0x6FA2), SkFixedToFloat(0x6299), SkFixedToFloat(0x24A0) }, + { SkFixedToFloat(0x38F5), SkFixedToFloat(0xB785), SkFixedToFloat(0x0F84) }, + { SkFixedToFloat(0x0390), SkFixedToFloat(0x18DA), SkFixedToFloat(0xB6CF) }, +}}; + +static constexpr skcms_Matrix3x3 kAdobeRGB = {{ + // ICC fixed-point (16.16) repesentation of: + // 0.60974, 0.20528, 0.14919, + // 0.31111, 0.62567, 0.06322, + // 0.01947, 0.06087, 0.74457, + { SkFixedToFloat(0x9c18), SkFixedToFloat(0x348d), SkFixedToFloat(0x2631) }, + { SkFixedToFloat(0x4fa5), SkFixedToFloat(0xa02c), SkFixedToFloat(0x102f) }, + { SkFixedToFloat(0x04fc), SkFixedToFloat(0x0f95), SkFixedToFloat(0xbe9c) }, +}}; + +static constexpr skcms_Matrix3x3 kDisplayP3 = {{ + { 0.515102f, 0.291965f, 0.157153f }, + { 0.241182f, 0.692236f, 0.0665819f }, + { -0.00104941f, 0.0418818f, 0.784378f }, +}}; + +static constexpr skcms_Matrix3x3 kRec2020 = {{ + { 0.673459f, 0.165661f, 0.125100f }, + { 0.279033f, 0.675338f, 0.0456288f }, + { -0.00193139f, 0.0299794f, 0.797162f }, +}}; + +static constexpr skcms_Matrix3x3 kXYZ = {{ + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, +}}; + +} // namespace SkNamedGamut + +class SK_API SkColorSpace : public SkNVRefCnt { +public: + /** + * Create the sRGB color space. + */ + static sk_sp MakeSRGB(); + + /** + * Colorspace with the sRGB primaries, but a linear (1.0) gamma. + */ + static sk_sp MakeSRGBLinear(); + + /** + * Create an SkColorSpace from a transfer function and a row-major 3x3 transformation to XYZ. + */ + static sk_sp MakeRGB(const skcms_TransferFunction& transferFn, + const skcms_Matrix3x3& toXYZ); + + /** + * Create an SkColorSpace from a parsed (skcms) ICC profile. + */ + static sk_sp Make(const skcms_ICCProfile&); + + /** + * Convert this color space to an skcms ICC profile struct. + */ + void toProfile(skcms_ICCProfile*) const; + + /** + * Returns true if the color space gamma is near enough to be approximated as sRGB. + */ + bool gammaCloseToSRGB() const; + + /** + * Returns true if the color space gamma is linear. + */ + bool gammaIsLinear() const; + + /** + * Sets |fn| to the transfer function from this color space. Returns true if the transfer + * function can be represented as coefficients to the standard ICC 7-parameter equation. + * Returns false otherwise (eg, PQ, HLG). + */ + bool isNumericalTransferFn(skcms_TransferFunction* fn) const; + + /** + * Returns true and sets |toXYZD50|. + */ + bool toXYZD50(skcms_Matrix3x3* toXYZD50) const; + + /** + * Returns a hash of the gamut transformation to XYZ D50. Allows for fast equality checking + * of gamuts, at the (very small) risk of collision. + */ + uint32_t toXYZD50Hash() const { return fToXYZD50Hash; } + + /** + * Returns a color space with the same gamut as this one, but with a linear gamma. + */ + sk_sp makeLinearGamma() const; + + /** + * Returns a color space with the same gamut as this one, but with the sRGB transfer + * function. + */ + sk_sp makeSRGBGamma() const; + + /** + * Returns a color space with the same transfer function as this one, but with the primary + * colors rotated. In other words, this produces a new color space that maps RGB to GBR + * (when applied to a source), and maps RGB to BRG (when applied to a destination). + * + * This is used for testing, to construct color spaces that have severe and testable behavior. + */ + sk_sp makeColorSpin() const; + + /** + * Returns true if the color space is sRGB. + * Returns false otherwise. + * + * This allows a little bit of tolerance, given that we might see small numerical error + * in some cases: converting ICC fixed point to float, converting white point to D50, + * rounding decisions on transfer function and matrix. + * + * This does not consider a 2.2f exponential transfer function to be sRGB. While these + * functions are similar (and it is sometimes useful to consider them together), this + * function checks for logical equality. + */ + bool isSRGB() const; + + /** + * Returns a serialized representation of this color space. + */ + sk_sp serialize() const; + + /** + * If |memory| is nullptr, returns the size required to serialize. + * Otherwise, serializes into |memory| and returns the size. + */ + size_t writeToMemory(void* memory) const; + + static sk_sp Deserialize(const void* data, size_t length); + + /** + * If both are null, we return true. If one is null and the other is not, we return false. + * If both are non-null, we do a deeper compare. + */ + static bool Equals(const SkColorSpace*, const SkColorSpace*); + + void transferFn(float gabcdef[7]) const; // DEPRECATED: Remove when webview usage is gone + void transferFn(skcms_TransferFunction* fn) const; + void invTransferFn(skcms_TransferFunction* fn) const; + void gamutTransformTo(const SkColorSpace* dst, skcms_Matrix3x3* src_to_dst) const; + + uint32_t transferFnHash() const { return fTransferFnHash; } + uint64_t hash() const { return (uint64_t)fTransferFnHash << 32 | fToXYZD50Hash; } + +private: + friend class SkColorSpaceSingletonFactory; + + SkColorSpace(const skcms_TransferFunction& transferFn, const skcms_Matrix3x3& toXYZ); + + void computeLazyDstFields() const; + + uint32_t fTransferFnHash; + uint32_t fToXYZD50Hash; + + skcms_TransferFunction fTransferFn; + skcms_Matrix3x3 fToXYZD50; + + mutable skcms_TransferFunction fInvTransferFn; + mutable skcms_Matrix3x3 fFromXYZD50; + mutable SkOnce fLazyDstFieldsOnce; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorType.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorType.h new file mode 100644 index 00000000000000..a68dc833b49b59 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkColorType.h @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorType_DEFINED +#define SkColorType_DEFINED + +#include "include/core/SkTypes.h" + +/** \enum SkColorType + Describes how pixel bits encode color. A pixel may be an alpha mask, a grayscale, RGB, or ARGB. + + kN32_SkColorType selects the native 32-bit ARGB format for the current configuration. This can + lead to inconsistent results across platforms, so use with caution. +*/ +enum SkColorType : int { + kUnknown_SkColorType, //!< uninitialized + kAlpha_8_SkColorType, //!< pixel with alpha in 8-bit byte + kRGB_565_SkColorType, //!< pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word + kARGB_4444_SkColorType, //!< pixel with 4 bits for alpha, red, green, blue; in 16-bit word + kRGBA_8888_SkColorType, //!< pixel with 8 bits for red, green, blue, alpha; in 32-bit word + kRGB_888x_SkColorType, //!< pixel with 8 bits each for red, green, blue; in 32-bit word + kBGRA_8888_SkColorType, //!< pixel with 8 bits for blue, green, red, alpha; in 32-bit word + kRGBA_1010102_SkColorType, //!< 10 bits for red, green, blue; 2 bits for alpha; in 32-bit word + kBGRA_1010102_SkColorType, //!< 10 bits for blue, green, red; 2 bits for alpha; in 32-bit word + kRGB_101010x_SkColorType, //!< pixel with 10 bits each for red, green, blue; in 32-bit word + kBGR_101010x_SkColorType, //!< pixel with 10 bits each for blue, green, red; in 32-bit word + kBGR_101010x_XR_SkColorType, //!< pixel with 10 bits each for blue, green, red; in 32-bit word, extended range + kGray_8_SkColorType, //!< pixel with grayscale level in 8-bit byte + kRGBA_F16Norm_SkColorType, //!< pixel with half floats in [0,1] for red, green, blue, alpha; + // in 64-bit word + kRGBA_F16_SkColorType, //!< pixel with half floats for red, green, blue, alpha; + // in 64-bit word + kRGBA_F32_SkColorType, //!< pixel using C float for red, green, blue, alpha; in 128-bit word + + // The following 6 colortypes are just for reading from - not for rendering to + kR8G8_unorm_SkColorType, //!< pixel with a uint8_t for red and green + + kA16_float_SkColorType, //!< pixel with a half float for alpha + kR16G16_float_SkColorType, //!< pixel with a half float for red and green + + kA16_unorm_SkColorType, //!< pixel with a little endian uint16_t for alpha + kR16G16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red and green + kR16G16B16A16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red, green, blue + // and alpha + + kSRGBA_8888_SkColorType, + kR8_unorm_SkColorType, + + kLastEnum_SkColorType = kR8_unorm_SkColorType, //!< last valid value + +#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) + kN32_SkColorType = kBGRA_8888_SkColorType,//!< native 32-bit BGRA encoding + +#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) + kN32_SkColorType = kRGBA_8888_SkColorType,//!< native 32-bit RGBA encoding + +#else + #error "SK_*32_SHIFT values must correspond to BGRA or RGBA byte order" +#endif +}; +static constexpr int kSkColorTypeCnt = static_cast(kLastEnum_SkColorType) + 1; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkContourMeasure.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkContourMeasure.h new file mode 100644 index 00000000000000..7090deaaed22a6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkContourMeasure.h @@ -0,0 +1,131 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkContourMeasure_DEFINED +#define SkContourMeasure_DEFINED + +#include "include/core/SkPath.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkTDArray.h" + +struct SkConic; + +class SK_API SkContourMeasure : public SkRefCnt { +public: + /** Return the length of the contour. + */ + SkScalar length() const { return fLength; } + + /** Pins distance to 0 <= distance <= length(), and then computes the corresponding + * position and tangent. + */ + bool SK_WARN_UNUSED_RESULT getPosTan(SkScalar distance, SkPoint* position, + SkVector* tangent) const; + + enum MatrixFlags { + kGetPosition_MatrixFlag = 0x01, + kGetTangent_MatrixFlag = 0x02, + kGetPosAndTan_MatrixFlag = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag + }; + + /** Pins distance to 0 <= distance <= getLength(), and then computes + the corresponding matrix (by calling getPosTan). + Returns false if there is no path, or a zero-length path was specified, in which case + matrix is unchanged. + */ + bool SK_WARN_UNUSED_RESULT getMatrix(SkScalar distance, SkMatrix* matrix, + MatrixFlags flags = kGetPosAndTan_MatrixFlag) const; + + /** Given a start and stop distance, return in dst the intervening segment(s). + If the segment is zero-length, return false, else return true. + startD and stopD are pinned to legal values (0..getLength()). If startD > stopD + then return false (and leave dst untouched). + Begin the segment with a moveTo if startWithMoveTo is true + */ + bool SK_WARN_UNUSED_RESULT getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, + bool startWithMoveTo) const; + + /** Return true if the contour is closed() + */ + bool isClosed() const { return fIsClosed; } + +private: + struct Segment { + SkScalar fDistance; // total distance up to this point + unsigned fPtIndex; // index into the fPts array + unsigned fTValue : 30; + unsigned fType : 2; // actually the enum SkSegType + // See SkPathMeasurePriv.h + + SkScalar getScalarT() const; + + static const Segment* Next(const Segment* seg) { + unsigned ptIndex = seg->fPtIndex; + do { + ++seg; + } while (seg->fPtIndex == ptIndex); + return seg; + } + + }; + + const SkTDArray fSegments; + const SkTDArray fPts; // Points used to define the segments + + const SkScalar fLength; + const bool fIsClosed; + + SkContourMeasure(SkTDArray&& segs, SkTDArray&& pts, + SkScalar length, bool isClosed); + ~SkContourMeasure() override {} + + const Segment* distanceToSegment(SkScalar distance, SkScalar* t) const; + + friend class SkContourMeasureIter; +}; + +class SK_API SkContourMeasureIter { +public: + SkContourMeasureIter(); + /** + * Initialize the Iter with a path. + * The parts of the path that are needed are copied, so the client is free to modify/delete + * the path after this call. + * + * resScale controls the precision of the measure. values > 1 increase the + * precision (and possibly slow down the computation). + */ + SkContourMeasureIter(const SkPath& path, bool forceClosed, SkScalar resScale = 1); + ~SkContourMeasureIter(); + + /** + * Reset the Iter with a path. + * The parts of the path that are needed are copied, so the client is free to modify/delete + * the path after this call. + */ + void reset(const SkPath& path, bool forceClosed, SkScalar resScale = 1); + + /** + * Iterates through contours in path, returning a contour-measure object for each contour + * in the path. Returns null when it is done. + * + * This only returns non-zero length contours, where a contour is the segments between + * a kMove_Verb and either ... + * - the next kMove_Verb + * - kClose_Verb (1 or more) + * - kDone_Verb + * If it encounters a zero-length contour, it is skipped. + */ + sk_sp next(); + +private: + class Impl; + + std::unique_ptr fImpl; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCoverageMode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCoverageMode.h new file mode 100644 index 00000000000000..aaae60c41920dc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCoverageMode.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCoverageMode_DEFINED +#define SkCoverageMode_DEFINED + +/** + * Describes geometric operations (ala SkRegion::Op) that can be applied to coverage bytes. + * These can be thought of as variants of porter-duff (SkBlendMode) modes, but only applied + * to the alpha channel. + * + * See SkMaskFilter for ways to use these when combining two different masks. + */ +enum class SkCoverageMode { + kUnion, // A ∪ B A+B-A*B + kIntersect, // A ∩ B A*B + kDifference, // A - B A*(1-B) + kReverseDifference, // B - A B*(1-A) + kXor, // A ⊕ B A+B-2*A*B + + kLast = kXor, +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCubicMap.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCubicMap.h new file mode 100644 index 00000000000000..863c9333f6e1e9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkCubicMap.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCubicMap_DEFINED +#define SkCubicMap_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +/** + * Fast evaluation of a cubic ease-in / ease-out curve. This is defined as a parametric cubic + * curve inside the unit square. + * + * pt[0] is implicitly { 0, 0 } + * pt[3] is implicitly { 1, 1 } + * pts[1,2].X are inside the unit [0..1] + */ +class SK_API SkCubicMap { +public: + SkCubicMap(SkPoint p1, SkPoint p2); + + static bool IsLinear(SkPoint p1, SkPoint p2) { + return SkScalarNearlyEqual(p1.fX, p1.fY) && SkScalarNearlyEqual(p2.fX, p2.fY); + } + + float computeYFromX(float x) const; + + SkPoint computeFromT(float t) const; + +private: + enum Type { + kLine_Type, // x == y + kCubeRoot_Type, // At^3 == x + kSolver_Type, // general monotonic cubic solver + }; + + SkPoint fCoeff[3]; + Type fType; +}; + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkData.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkData.h new file mode 100644 index 00000000000000..2b50cebc81b6ae --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkData.h @@ -0,0 +1,191 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkData_DEFINED +#define SkData_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" + +#include +#include + +class SkStream; + +/** + * SkData holds an immutable data buffer. Not only is the data immutable, + * but the actual ptr that is returned (by data() or bytes()) is guaranteed + * to always be the same for the life of this instance. + */ +class SK_API SkData final : public SkNVRefCnt { +public: + /** + * Returns the number of bytes stored. + */ + size_t size() const { return fSize; } + + bool isEmpty() const { return 0 == fSize; } + + /** + * Returns the ptr to the data. + */ + const void* data() const { return fPtr; } + + /** + * Like data(), returns a read-only ptr into the data, but in this case + * it is cast to uint8_t*, to make it easy to add an offset to it. + */ + const uint8_t* bytes() const { + return reinterpret_cast(fPtr); + } + + /** + * USE WITH CAUTION. + * This call will assert that the refcnt is 1, as a precaution against modifying the + * contents when another client/thread has access to the data. + */ + void* writable_data() { + if (fSize) { + // only assert we're unique if we're not empty + SkASSERT(this->unique()); + } + return const_cast(fPtr); + } + + /** + * Helper to copy a range of the data into a caller-provided buffer. + * Returns the actual number of bytes copied, after clamping offset and + * length to the size of the data. If buffer is NULL, it is ignored, and + * only the computed number of bytes is returned. + */ + size_t copyRange(size_t offset, size_t length, void* buffer) const; + + /** + * Returns true if these two objects have the same length and contents, + * effectively returning 0 == memcmp(...) + */ + bool equals(const SkData* other) const; + + /** + * Function that, if provided, will be called when the SkData goes out + * of scope, allowing for custom allocation/freeing of the data's contents. + */ + typedef void (*ReleaseProc)(const void* ptr, void* context); + + /** + * Create a new dataref by copying the specified data + */ + static sk_sp MakeWithCopy(const void* data, size_t length); + + + /** + * Create a new data with uninitialized contents. The caller should call writable_data() + * to write into the buffer, but this must be done before another ref() is made. + */ + static sk_sp MakeUninitialized(size_t length); + + /** + * Create a new data with zero-initialized contents. The caller should call writable_data() + * to write into the buffer, but this must be done before another ref() is made. + */ + static sk_sp MakeZeroInitialized(size_t length); + + /** + * Create a new dataref by copying the specified c-string + * (a null-terminated array of bytes). The returned SkData will have size() + * equal to strlen(cstr) + 1. If cstr is NULL, it will be treated the same + * as "". + */ + static sk_sp MakeWithCString(const char cstr[]); + + /** + * Create a new dataref, taking the ptr as is, and using the + * releaseproc to free it. The proc may be NULL. + */ + static sk_sp MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx); + + /** + * Call this when the data parameter is already const and will outlive the lifetime of the + * SkData. Suitable for with const globals. + */ + static sk_sp MakeWithoutCopy(const void* data, size_t length) { + return MakeWithProc(data, length, NoopReleaseProc, nullptr); + } + + /** + * Create a new dataref from a pointer allocated by malloc. The Data object + * takes ownership of that allocation, and will handling calling sk_free. + */ + static sk_sp MakeFromMalloc(const void* data, size_t length); + + /** + * Create a new dataref the file with the specified path. + * If the file cannot be opened, this returns NULL. + */ + static sk_sp MakeFromFileName(const char path[]); + + /** + * Create a new dataref from a stdio FILE. + * This does not take ownership of the FILE, nor close it. + * The caller is free to close the FILE at its convenience. + * The FILE must be open for reading only. + * Returns NULL on failure. + */ + static sk_sp MakeFromFILE(FILE* f); + + /** + * Create a new dataref from a file descriptor. + * This does not take ownership of the file descriptor, nor close it. + * The caller is free to close the file descriptor at its convenience. + * The file descriptor must be open for reading only. + * Returns NULL on failure. + */ + static sk_sp MakeFromFD(int fd); + + /** + * Attempt to read size bytes into a SkData. If the read succeeds, return the data, + * else return NULL. Either way the stream's cursor may have been changed as a result + * of calling read(). + */ + static sk_sp MakeFromStream(SkStream*, size_t size); + + /** + * Create a new dataref using a subset of the data in the specified + * src dataref. + */ + static sk_sp MakeSubset(const SkData* src, size_t offset, size_t length); + + /** + * Returns a new empty dataref (or a reference to a shared empty dataref). + * New or shared, the caller must see that unref() is eventually called. + */ + static sk_sp MakeEmpty(); + +private: + friend class SkNVRefCnt; + ReleaseProc fReleaseProc; + void* fReleaseProcContext; + const void* fPtr; + size_t fSize; + + SkData(const void* ptr, size_t size, ReleaseProc, void* context); + explicit SkData(size_t size); // inplace new/delete + ~SkData(); + + // Ensure the unsized delete is called. + void operator delete(void* p); + + // shared internal factory + static sk_sp PrivateNewWithCopy(const void* srcOrNull, size_t length); + + static void NoopReleaseProc(const void*, void*); // {} + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDataTable.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDataTable.h new file mode 100644 index 00000000000000..3aa48d5f33ea09 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDataTable.h @@ -0,0 +1,122 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDataTable_DEFINED +#define SkDataTable_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" + +#include +#include + +/** + * Like SkData, SkDataTable holds an immutable data buffer. The data buffer is + * organized into a table of entries, each with a length, so the entries are + * not required to all be the same size. + */ +class SK_API SkDataTable : public SkRefCnt { +public: + /** + * Returns true if the table is empty (i.e. has no entries). + */ + bool isEmpty() const { return 0 == fCount; } + + /** + * Return the number of entries in the table. 0 for an empty table + */ + int count() const { return fCount; } + + /** + * Return the size of the index'th entry in the table. The caller must + * ensure that index is valid for this table. + */ + size_t atSize(int index) const; + + /** + * Return a pointer to the data of the index'th entry in the table. + * The caller must ensure that index is valid for this table. + * + * @param size If non-null, this returns the byte size of this entry. This + * will be the same value that atSize(index) would return. + */ + const void* at(int index, size_t* size = nullptr) const; + + template + const T* atT(int index, size_t* size = nullptr) const { + return reinterpret_cast(this->at(index, size)); + } + + /** + * Returns the index'th entry as a c-string, and assumes that the trailing + * null byte had been copied into the table as well. + */ + const char* atStr(int index) const { + size_t size; + const char* str = this->atT(index, &size); + SkASSERT(strlen(str) + 1 == size); + return str; + } + + typedef void (*FreeProc)(void* context); + + static sk_sp MakeEmpty(); + + /** + * Return a new DataTable that contains a copy of the data stored in each + * "array". + * + * @param ptrs array of points to each element to be copied into the table. + * @param sizes array of byte-lengths for each entry in the corresponding + * ptrs[] array. + * @param count the number of array elements in ptrs[] and sizes[] to copy. + */ + static sk_sp MakeCopyArrays(const void * const * ptrs, + const size_t sizes[], int count); + + /** + * Return a new table that contains a copy of the data in array. + * + * @param array contiguous array of data for all elements to be copied. + * @param elemSize byte-length for a given element. + * @param count the number of entries to be copied out of array. The number + * of bytes that will be copied is count * elemSize. + */ + static sk_sp MakeCopyArray(const void* array, size_t elemSize, int count); + + static sk_sp MakeArrayProc(const void* array, size_t elemSize, int count, + FreeProc proc, void* context); + +private: + struct Dir { + const void* fPtr; + uintptr_t fSize; + }; + + int fCount; + size_t fElemSize; + union { + const Dir* fDir; + const char* fElems; + } fU; + + FreeProc fFreeProc; + void* fFreeProcContext; + + SkDataTable(); + SkDataTable(const void* array, size_t elemSize, int count, + FreeProc, void* context); + SkDataTable(const Dir*, int count, FreeProc, void* context); + ~SkDataTable() override; + + friend class SkDataTableBuilder; // access to Dir + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDeferredDisplayList.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDeferredDisplayList.h new file mode 100644 index 00000000000000..e5511beea3aea6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDeferredDisplayList.h @@ -0,0 +1,111 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDeferredDisplayList_DEFINED +#define SkDeferredDisplayList_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSurfaceCharacterization.h" +#include "include/core/SkTypes.h" + +class SkDeferredDisplayListPriv; +class SkPromiseImageTexture; + +#if defined(SK_GANESH) +#include "include/gpu/GrRecordingContext.h" +#include "include/private/base/SkTArray.h" +#include +class GrRenderTask; +class GrRenderTargetProxy; +#else +using GrRenderTargetProxy = SkRefCnt; +#endif + +/* + * This class contains pre-processed gpu operations that can be replayed into + * an SkSurface via SkSurface::draw(SkDeferredDisplayList*). + */ +class SkDeferredDisplayList : public SkNVRefCnt { +public: + SK_API ~SkDeferredDisplayList(); + + SK_API const SkSurfaceCharacterization& characterization() const { + return fCharacterization; + } + +#if defined(SK_GANESH) + /** + * Iterate through the programs required by the DDL. + */ + class SK_API ProgramIterator { + public: + ProgramIterator(GrDirectContext*, SkDeferredDisplayList*); + ~ProgramIterator(); + + // This returns true if any work was done. Getting a cache hit does not count as work. + bool compile(); + bool done() const; + void next(); + + private: + GrDirectContext* fDContext; + const skia_private::TArray& fProgramData; + int fIndex; + }; +#endif + + // Provides access to functions that aren't part of the public API. + SkDeferredDisplayListPriv priv(); + const SkDeferredDisplayListPriv priv() const; // NOLINT(readability-const-return-type) + +private: + friend class GrDrawingManager; // for access to 'fRenderTasks', 'fLazyProxyData', 'fArenas' + friend class SkDeferredDisplayListRecorder; // for access to 'fLazyProxyData' + friend class SkDeferredDisplayListPriv; + + // This object is the source from which the lazy proxy backing the DDL will pull its backing + // texture when the DDL is replayed. It has to be separately ref counted bc the lazy proxy + // can outlive the DDL. + class LazyProxyData : public SkRefCnt { +#if defined(SK_GANESH) + public: + // Upon being replayed - this field will be filled in (by the DrawingManager) with the + // proxy backing the destination SkSurface. Note that, since there is no good place to + // clear it, it can become a dangling pointer. Additionally, since the renderTargetProxy + // doesn't get a ref here, the SkSurface that owns it must remain alive until the DDL + // is flushed. + // TODO: the drawing manager could ref the renderTargetProxy for the DDL and then add + // a renderingTask to unref it after the DDL's ops have been executed. + GrRenderTargetProxy* fReplayDest = nullptr; +#endif + }; + + SK_API SkDeferredDisplayList(const SkSurfaceCharacterization& characterization, + sk_sp fTargetProxy, + sk_sp); + +#if defined(SK_GANESH) + const skia_private::TArray& programData() const { + return fProgramData; + } +#endif + + const SkSurfaceCharacterization fCharacterization; + +#if defined(SK_GANESH) + // These are ordered such that the destructor cleans op tasks up first (which may refer back + // to the arena and memory pool in their destructors). + GrRecordingContext::OwnedArenas fArenas; + skia_private::TArray> fRenderTasks; + + skia_private::TArray fProgramData; + sk_sp fTargetProxy; + sk_sp fLazyProxyData; +#endif +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDeferredDisplayListRecorder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDeferredDisplayListRecorder.h new file mode 100644 index 00000000000000..cd91798513bdf0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDeferredDisplayListRecorder.h @@ -0,0 +1,98 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDeferredDisplayListRecorder_DEFINED +#define SkDeferredDisplayListRecorder_DEFINED + +#include "include/core/SkDeferredDisplayList.h" +#include "include/core/SkImage.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSurfaceCharacterization.h" +#include "include/core/SkTypes.h" + +class GrBackendFormat; +class GrBackendTexture; +class GrRecordingContext; +class GrYUVABackendTextureInfo; +class SkCanvas; +class SkSurface; + +/* + * This class is intended to be used as: + * Get an SkSurfaceCharacterization representing the intended gpu-backed destination SkSurface + * Create one of these (an SkDeferredDisplayListRecorder) on the stack + * Get the canvas and render into it + * Snap off and hold on to an SkDeferredDisplayList + * Once your app actually needs the pixels, call SkSurface::draw(SkDeferredDisplayList*) + * + * This class never accesses the GPU but performs all the cpu work it can. It + * is thread-safe (i.e., one can break a scene into tiles and perform their cpu-side + * work in parallel ahead of time). + */ +class SK_API SkDeferredDisplayListRecorder { +public: + SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&); + ~SkDeferredDisplayListRecorder(); + + const SkSurfaceCharacterization& characterization() const { + return fCharacterization; + } + + // The backing canvas will become invalid (and this entry point will return + // null) once 'detach' is called. + // Note: ownership of the SkCanvas is not transferred via this call. + SkCanvas* getCanvas(); + + sk_sp detach(); + +#if defined(SK_GANESH) + using PromiseImageTextureContext = void*; + using PromiseImageTextureFulfillProc = + sk_sp (*)(PromiseImageTextureContext); + using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext); + +#ifndef SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API + /** Deprecated: Use SkImages::PromiseTextureFrom instead. */ + sk_sp makePromiseTexture(const GrBackendFormat& backendFormat, + int width, + int height, + GrMipmapped mipmapped, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp colorSpace, + PromiseImageTextureFulfillProc textureFulfillProc, + PromiseImageTextureReleaseProc textureReleaseProc, + PromiseImageTextureContext textureContext); + + /** Deprecated: Use SkImages::PromiseTextureFromYUVA instead. */ + sk_sp makeYUVAPromiseTexture(const GrYUVABackendTextureInfo& yuvaBackendTextureInfo, + sk_sp imageColorSpace, + PromiseImageTextureFulfillProc textureFulfillProc, + PromiseImageTextureReleaseProc textureReleaseProc, + PromiseImageTextureContext textureContexts[]); +#endif // SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API +#endif // defined(SK_GANESH) + +private: + SkDeferredDisplayListRecorder(const SkDeferredDisplayListRecorder&) = delete; + SkDeferredDisplayListRecorder& operator=(const SkDeferredDisplayListRecorder&) = delete; + + bool init(); + + const SkSurfaceCharacterization fCharacterization; + +#if defined(SK_GANESH) + sk_sp fContext; + sk_sp fTargetProxy; + sk_sp fLazyProxyData; + sk_sp fSurface; +#endif +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDocument.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDocument.h new file mode 100644 index 00000000000000..eacfb2c040b87c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDocument.h @@ -0,0 +1,91 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDocument_DEFINED +#define SkDocument_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" + +class SkCanvas; +class SkWStream; +struct SkRect; + +/** SK_ScalarDefaultDPI is 72 dots per inch. */ +static constexpr SkScalar SK_ScalarDefaultRasterDPI = 72.0f; + +/** + * High-level API for creating a document-based canvas. To use.. + * + * 1. Create a document, specifying a stream to store the output. + * 2. For each "page" of content: + * a. canvas = doc->beginPage(...) + * b. draw_my_content(canvas); + * c. doc->endPage(); + * 3. Close the document with doc->close(). + */ +class SK_API SkDocument : public SkRefCnt { +public: + + /** + * Begin a new page for the document, returning the canvas that will draw + * into the page. The document owns this canvas, and it will go out of + * scope when endPage() or close() is called, or the document is deleted. + */ + SkCanvas* beginPage(SkScalar width, SkScalar height, const SkRect* content = nullptr); + + /** + * Call endPage() when the content for the current page has been drawn + * (into the canvas returned by beginPage()). After this call the canvas + * returned by beginPage() will be out-of-scope. + */ + void endPage(); + + /** + * Call close() when all pages have been drawn. This will close the file + * or stream holding the document's contents. After close() the document + * can no longer add new pages. Deleting the document will automatically + * call close() if need be. + */ + void close(); + + /** + * Call abort() to stop producing the document immediately. + * The stream output must be ignored, and should not be trusted. + */ + void abort(); + +protected: + SkDocument(SkWStream*); + + // note: subclasses must call close() in their destructor, as the base class + // cannot do this for them. + ~SkDocument() override; + + virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height) = 0; + virtual void onEndPage() = 0; + virtual void onClose(SkWStream*) = 0; + virtual void onAbort() = 0; + + // Allows subclasses to write to the stream as pages are written. + SkWStream* getStream() { return fStream; } + + enum State { + kBetweenPages_State, + kInPage_State, + kClosed_State + }; + State getState() const { return fState; } + +private: + SkWStream* fStream; + State fState; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDrawLooper.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDrawLooper.h new file mode 100644 index 00000000000000..69d341c25fd5e2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDrawLooper.h @@ -0,0 +1,135 @@ + +/* + * Copyright 2011 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 SkDrawLooper_DEFINED +#define SkDrawLooper_DEFINED + +#include "include/core/SkBlurTypes.h" +#include "include/core/SkColor.h" +#include "include/core/SkFlattenable.h" +#include "include/core/SkPoint.h" +#include // std::function + +#ifndef SK_SUPPORT_LEGACY_DRAWLOOPER +#error "SkDrawLooper is unsupported" +#endif + +class SkArenaAlloc; +class SkCanvas; +class SkMatrix; +class SkPaint; +struct SkRect; + +/** \class SkDrawLooper + DEPRECATED: No longer supported in Skia. +*/ +class SK_API SkDrawLooper : public SkFlattenable { +public: + /** + * Holds state during a draw. Users call next() until it returns false. + * + * Subclasses of SkDrawLooper should create a subclass of this object to + * hold state specific to their subclass. + */ + class SK_API Context { + public: + Context() {} + virtual ~Context() {} + + struct Info { + SkVector fTranslate; + bool fApplyPostCTM; + + void applyToCTM(SkMatrix* ctm) const; + void applyToCanvas(SkCanvas*) const; + }; + + /** + * Called in a loop on objects returned by SkDrawLooper::createContext(). + * Each time true is returned, the object is drawn (possibly with a modified + * canvas and/or paint). When false is finally returned, drawing for the object + * stops. + * + * On each call, the paint will be in its original state, but the + * canvas will be as it was following the previous call to next() or + * createContext(). + * + * The implementation must ensure that, when next() finally returns + * false, the canvas has been restored to the state it was + * initially, before createContext() was first called. + */ + virtual bool next(Info*, SkPaint*) = 0; + + private: + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + }; + + /** + * Called right before something is being drawn. Returns a Context + * whose next() method should be called until it returns false. + */ + virtual Context* makeContext(SkArenaAlloc*) const = 0; + + /** + * The fast bounds functions are used to enable the paint to be culled early + * in the drawing pipeline. If a subclass can support this feature it must + * return true for the canComputeFastBounds() function. If that function + * returns false then computeFastBounds behavior is undefined otherwise it + * is expected to have the following behavior. Given the parent paint and + * the parent's bounding rect the subclass must fill in and return the + * storage rect, where the storage rect is with the union of the src rect + * and the looper's bounding rect. + */ + bool canComputeFastBounds(const SkPaint& paint) const; + void computeFastBounds(const SkPaint& paint, const SkRect& src, SkRect* dst) const; + + struct BlurShadowRec { + SkScalar fSigma; + SkVector fOffset; + SkColor fColor; + SkBlurStyle fStyle; + }; + /** + * If this looper can be interpreted as having two layers, such that + * 1. The first layer (bottom most) just has a blur and translate + * 2. The second layer has no modifications to either paint or canvas + * 3. No other layers. + * then return true, and if not null, fill out the BlurShadowRec). + * + * If any of the above are not met, return false and ignore the BlurShadowRec parameter. + */ + virtual bool asABlurShadow(BlurShadowRec*) const; + + static SkFlattenable::Type GetFlattenableType() { + return kSkDrawLooper_Type; + } + + SkFlattenable::Type getFlattenableType() const override { + return kSkDrawLooper_Type; + } + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize( + kSkDrawLooper_Type, data, size, procs).release())); + } + + void apply(SkCanvas* canvas, const SkPaint& paint, + std::function); + +protected: + SkDrawLooper() {} + +private: + using INHERITED = SkFlattenable; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDrawable.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDrawable.h new file mode 100644 index 00000000000000..316bf058bcf5a2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkDrawable.h @@ -0,0 +1,175 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDrawable_DEFINED +#define SkDrawable_DEFINED + +#include "include/core/SkFlattenable.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/private/base/SkAPI.h" + +#include +#include +#include + +class GrBackendDrawableInfo; +class SkCanvas; +class SkMatrix; +class SkPicture; +enum class GrBackendApi : unsigned int; +struct SkDeserialProcs; +struct SkIRect; +struct SkImageInfo; +struct SkRect; + +/** + * Base-class for objects that draw into SkCanvas. + * + * The object has a generation ID, which is guaranteed to be unique across all drawables. To + * allow for clients of the drawable that may want to cache the results, the drawable must + * change its generation ID whenever its internal state changes such that it will draw differently. + */ +class SK_API SkDrawable : public SkFlattenable { +public: + /** + * Draws into the specified content. The drawing sequence will be balanced upon return + * (i.e. the saveLevel() on the canvas will match what it was when draw() was called, + * and the current matrix and clip settings will not be changed. + */ + void draw(SkCanvas*, const SkMatrix* = nullptr); + void draw(SkCanvas*, SkScalar x, SkScalar y); + + /** + * When using the GPU backend it is possible for a drawable to execute using the underlying 3D + * API rather than the SkCanvas API. It does so by creating a GpuDrawHandler. The GPU backend + * is deferred so the handler will be given access to the 3D API at the correct point in the + * drawing stream as the GPU backend flushes. Since the drawable may mutate, each time it is + * drawn to a GPU-backed canvas a new handler is snapped, representing the drawable's state at + * the time of the snap. + * + * When the GPU backend flushes to the 3D API it will call the draw method on the + * GpuDrawHandler. At this time the drawable may add commands to the stream of GPU commands for + * the unerlying 3D API. The draw function takes a GrBackendDrawableInfo which contains + * information about the current state of 3D API which the caller must respect. See + * GrBackendDrawableInfo for more specific details on what information is sent and the + * requirements for different 3D APIs. + * + * Additionaly there may be a slight delay from when the drawable adds its commands to when + * those commands are actually submitted to the GPU. Thus the drawable or GpuDrawHandler is + * required to keep any resources that are used by its added commands alive and valid until + * those commands are submitted to the GPU. The GpuDrawHandler will be kept alive and then + * deleted once the commands are submitted to the GPU. The dtor of the GpuDrawHandler is the + * signal to the drawable that the commands have all been submitted. Different 3D APIs may have + * additional requirements for certain resources which require waiting for the GPU to finish + * all work on those resources before reusing or deleting them. In this case, the drawable can + * use the dtor call of the GpuDrawHandler to add a fence to the GPU to track when the GPU work + * has completed. + * + * Currently this is only supported for the GPU Vulkan backend. + */ + + class GpuDrawHandler { + public: + virtual ~GpuDrawHandler() {} + + virtual void draw(const GrBackendDrawableInfo&) {} + }; + + /** + * Snaps off a GpuDrawHandler to represent the state of the SkDrawable at the time the snap is + * called. This is used for executing GPU backend specific draws intermixed with normal Skia GPU + * draws. The GPU API, which will be used for the draw, as well as the full matrix, device clip + * bounds and imageInfo of the target buffer are passed in as inputs. + */ + std::unique_ptr snapGpuDrawHandler(GrBackendApi backendApi, + const SkMatrix& matrix, + const SkIRect& clipBounds, + const SkImageInfo& bufferInfo) { + return this->onSnapGpuDrawHandler(backendApi, matrix, clipBounds, bufferInfo); + } + + SkPicture* newPictureSnapshot(); + + /** + * Return a unique value for this instance. If two calls to this return the same value, + * it is presumed that calling the draw() method will render the same thing as well. + * + * Subclasses that change their state should call notifyDrawingChanged() to ensure that + * a new value will be returned the next time it is called. + */ + uint32_t getGenerationID(); + + /** + * Return the (conservative) bounds of what the drawable will draw. If the drawable can + * change what it draws (e.g. animation or in response to some external change), then this + * must return a bounds that is always valid for all possible states. + */ + SkRect getBounds(); + + /** + * Return approximately how many bytes would be freed if this drawable is destroyed. + * The base implementation returns 0 to indicate that this is unknown. + */ + size_t approximateBytesUsed(); + + /** + * Calling this invalidates the previous generation ID, and causes a new one to be computed + * the next time getGenerationID() is called. Typically this is called by the object itself, + * in response to its internal state changing. + */ + void notifyDrawingChanged(); + + static SkFlattenable::Type GetFlattenableType() { + return kSkDrawable_Type; + } + + SkFlattenable::Type getFlattenableType() const override { + return kSkDrawable_Type; + } + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize( + kSkDrawable_Type, data, size, procs).release())); + } + + Factory getFactory() const override { return nullptr; } + const char* getTypeName() const override { return nullptr; } + +protected: + SkDrawable(); + + virtual SkRect onGetBounds() = 0; + virtual size_t onApproximateBytesUsed(); + virtual void onDraw(SkCanvas*) = 0; + + virtual std::unique_ptr onSnapGpuDrawHandler(GrBackendApi, const SkMatrix&, + const SkIRect& /*clipBounds*/, + const SkImageInfo&) { + return nullptr; + } + + // TODO: Delete this once Android gets updated to take the clipBounds version above. + virtual std::unique_ptr onSnapGpuDrawHandler(GrBackendApi, const SkMatrix&) { + return nullptr; + } + + /** + * Default implementation calls onDraw() with a canvas that records into a picture. Subclasses + * may override if they have a more efficient way to return a picture for the current state + * of their drawable. Note: this picture must draw the same as what would be drawn from + * onDraw(). + */ + virtual SkPicture* onNewPictureSnapshot(); + +private: + int32_t fGenerationID; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkEncodedImageFormat.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkEncodedImageFormat.h new file mode 100644 index 00000000000000..0db3830b9ac712 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkEncodedImageFormat.h @@ -0,0 +1,9 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// TODO(kjlubick) remove this shim after clients have been moved to the new location +#include "include/codec/SkEncodedImageFormat.h" // IWYU pragma: export diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkExecutor.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkExecutor.h new file mode 100644 index 00000000000000..88e2ca6e52ec5e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkExecutor.h @@ -0,0 +1,41 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkExecutor_DEFINED +#define SkExecutor_DEFINED + +#include +#include +#include "include/core/SkTypes.h" + +class SK_API SkExecutor { +public: + virtual ~SkExecutor(); + + // Create a thread pool SkExecutor with a fixed thread count, by default the number of cores. + static std::unique_ptr MakeFIFOThreadPool(int threads = 0, + bool allowBorrowing = true); + static std::unique_ptr MakeLIFOThreadPool(int threads = 0, + bool allowBorrowing = true); + + // There is always a default SkExecutor available by calling SkExecutor::GetDefault(). + static SkExecutor& GetDefault(); + static void SetDefault(SkExecutor*); // Does not take ownership. Not thread safe. + + // Add work to execute. + virtual void add(std::function) = 0; + + // If it makes sense for this executor, use this thread to execute work for a little while. + virtual void borrow() {} + +protected: + SkExecutor() = default; + SkExecutor(const SkExecutor&) = delete; + SkExecutor& operator=(const SkExecutor&) = delete; +}; + +#endif//SkExecutor_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFlattenable.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFlattenable.h new file mode 100644 index 00000000000000..3585e845b54896 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFlattenable.h @@ -0,0 +1,115 @@ +/* + * 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 SkFlattenable_DEFINED +#define SkFlattenable_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include + +class SkData; +class SkReadBuffer; +class SkWriteBuffer; +struct SkDeserialProcs; +struct SkSerialProcs; + +/** \class SkFlattenable + + SkFlattenable is the base class for objects that need to be flattened + into a data stream for either transport or as part of the key to the + font cache. + */ +class SK_API SkFlattenable : public SkRefCnt { +public: + enum Type { + kSkColorFilter_Type, + kSkBlender_Type, + kSkDrawable_Type, + kSkDrawLooper_Type, // no longer used internally by Skia + kSkImageFilter_Type, + kSkMaskFilter_Type, + kSkPathEffect_Type, + kSkShader_Type, + }; + + typedef sk_sp (*Factory)(SkReadBuffer&); + + SkFlattenable() {} + + /** Implement this to return a factory function pointer that can be called + to recreate your class given a buffer (previously written to by your + override of flatten(). + */ + virtual Factory getFactory() const = 0; + + /** + * Returns the name of the object's class. + */ + virtual const char* getTypeName() const = 0; + + static Factory NameToFactory(const char name[]); + static const char* FactoryToName(Factory); + + static void Register(const char name[], Factory); + + /** + * Override this if your subclass needs to record data that it will need to recreate itself + * from its CreateProc (returned by getFactory()). + * + * DEPRECATED public : will move to protected ... use serialize() instead + */ + virtual void flatten(SkWriteBuffer&) const {} + + virtual Type getFlattenableType() const = 0; + + // + // public ways to serialize / deserialize + // + sk_sp serialize(const SkSerialProcs* = nullptr) const; + size_t serialize(void* memory, size_t memory_size, + const SkSerialProcs* = nullptr) const; + static sk_sp Deserialize(Type, const void* data, size_t length, + const SkDeserialProcs* procs = nullptr); + +protected: + class PrivateInitializer { + public: + static void InitEffects(); + static void InitImageFilters(); + }; + +private: + static void RegisterFlattenablesIfNeeded(); + static void Finalize(); + + friend class SkGraphics; + + using INHERITED = SkRefCnt; +}; + +#if defined(SK_DISABLE_EFFECT_DESERIALIZATION) + #define SK_REGISTER_FLATTENABLE(type) do{}while(false) + + #define SK_FLATTENABLE_HOOKS(type) \ + static sk_sp CreateProc(SkReadBuffer&); \ + friend class SkFlattenable::PrivateInitializer; \ + Factory getFactory() const override { return nullptr; } \ + const char* getTypeName() const override { return #type; } +#else + #define SK_REGISTER_FLATTENABLE(type) \ + SkFlattenable::Register(#type, type::CreateProc) + + #define SK_FLATTENABLE_HOOKS(type) \ + static sk_sp CreateProc(SkReadBuffer&); \ + friend class SkFlattenable::PrivateInitializer; \ + Factory getFactory() const override { return type::CreateProc; } \ + const char* getTypeName() const override { return #type; } +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFont.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFont.h new file mode 100644 index 00000000000000..88e92694bd4558 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFont.h @@ -0,0 +1,540 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFont_DEFINED +#define SkFont_DEFINED + +#include "include/core/SkFontTypes.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypeface.h" +#include "include/private/base/SkTemplates.h" + +#include + +class SkMatrix; +class SkPaint; +class SkPath; +struct SkFontMetrics; + +/** \class SkFont + SkFont controls options applied when drawing and measuring text. +*/ +class SK_API SkFont { +public: + /** Whether edge pixels draw opaque or with partial transparency. + */ + enum class Edging { + kAlias, //!< no transparent pixels on glyph edges + kAntiAlias, //!< may have transparent pixels on glyph edges + kSubpixelAntiAlias, //!< glyph positioned in pixel using transparency + }; + + /** Constructs SkFont with default values. + + @return default initialized SkFont + */ + SkFont(); + + /** Constructs SkFont with default values with SkTypeface and size in points. + + @param typeface font and style used to draw and measure text + @param size typographic height of text + @return initialized SkFont + */ + SkFont(sk_sp typeface, SkScalar size); + + /** Constructs SkFont with default values with SkTypeface. + + @param typeface font and style used to draw and measure text + @return initialized SkFont + */ + explicit SkFont(sk_sp typeface); + + + /** Constructs SkFont with default values with SkTypeface and size in points, + horizontal scale, and horizontal skew. Horizontal scale emulates condensed + and expanded fonts. Horizontal skew emulates oblique fonts. + + @param typeface font and style used to draw and measure text + @param size typographic height of text + @param scaleX text horizontal scale + @param skewX additional shear on x-axis relative to y-axis + @return initialized SkFont + */ + SkFont(sk_sp typeface, SkScalar size, SkScalar scaleX, SkScalar skewX); + + + /** Compares SkFont and font, and returns true if they are equivalent. + May return false if SkTypeface has identical contents but different pointers. + + @param font font to compare + @return true if SkFont pair are equivalent + */ + bool operator==(const SkFont& font) const; + + /** Compares SkFont and font, and returns true if they are not equivalent. + May return true if SkTypeface has identical contents but different pointers. + + @param font font to compare + @return true if SkFont pair are not equivalent + */ + bool operator!=(const SkFont& font) const { return !(*this == font); } + + /** If true, instructs the font manager to always hint glyphs. + Returned value is only meaningful if platform uses FreeType as the font manager. + + @return true if all glyphs are hinted + */ + bool isForceAutoHinting() const { return SkToBool(fFlags & kForceAutoHinting_PrivFlag); } + + /** Returns true if font engine may return glyphs from font bitmaps instead of from outlines. + + @return true if glyphs may be font bitmaps + */ + bool isEmbeddedBitmaps() const { return SkToBool(fFlags & kEmbeddedBitmaps_PrivFlag); } + + /** Returns true if glyphs may be drawn at sub-pixel offsets. + + @return true if glyphs may be drawn at sub-pixel offsets. + */ + bool isSubpixel() const { return SkToBool(fFlags & kSubpixel_PrivFlag); } + + /** Returns true if font and glyph metrics are requested to be linearly scalable. + + @return true if font and glyph metrics are requested to be linearly scalable. + */ + bool isLinearMetrics() const { return SkToBool(fFlags & kLinearMetrics_PrivFlag); } + + /** Returns true if bold is approximated by increasing the stroke width when creating glyph + bitmaps from outlines. + + @return bold is approximated through stroke width + */ + bool isEmbolden() const { return SkToBool(fFlags & kEmbolden_PrivFlag); } + + /** Returns true if baselines will be snapped to pixel positions when the current transformation + matrix is axis aligned. + + @return baselines may be snapped to pixels + */ + bool isBaselineSnap() const { return SkToBool(fFlags & kBaselineSnap_PrivFlag); } + + /** Sets whether to always hint glyphs. + If forceAutoHinting is set, instructs the font manager to always hint glyphs. + + Only affects platforms that use FreeType as the font manager. + + @param forceAutoHinting setting to always hint glyphs + */ + void setForceAutoHinting(bool forceAutoHinting); + + /** Requests, but does not require, to use bitmaps in fonts instead of outlines. + + @param embeddedBitmaps setting to use bitmaps in fonts + */ + void setEmbeddedBitmaps(bool embeddedBitmaps); + + /** Requests, but does not require, that glyphs respect sub-pixel positioning. + + @param subpixel setting for sub-pixel positioning + */ + void setSubpixel(bool subpixel); + + /** Requests, but does not require, linearly scalable font and glyph metrics. + + For outline fonts 'true' means font and glyph metrics should ignore hinting and rounding. + Note that some bitmap formats may not be able to scale linearly and will ignore this flag. + + @param linearMetrics setting for linearly scalable font and glyph metrics. + */ + void setLinearMetrics(bool linearMetrics); + + /** Increases stroke width when creating glyph bitmaps to approximate a bold typeface. + + @param embolden setting for bold approximation + */ + void setEmbolden(bool embolden); + + /** Requests that baselines be snapped to pixels when the current transformation matrix is axis + aligned. + + @param baselineSnap setting for baseline snapping to pixels + */ + void setBaselineSnap(bool baselineSnap); + + /** Whether edge pixels draw opaque or with partial transparency. + */ + Edging getEdging() const { return (Edging)fEdging; } + + /** Requests, but does not require, that edge pixels draw opaque or with + partial transparency. + */ + void setEdging(Edging edging); + + /** Sets level of glyph outline adjustment. + Does not check for valid values of hintingLevel. + */ + void setHinting(SkFontHinting hintingLevel); + + /** Returns level of glyph outline adjustment. + */ + SkFontHinting getHinting() const { return (SkFontHinting)fHinting; } + + /** Returns a font with the same attributes of this font, but with the specified size. + Returns nullptr if size is less than zero, infinite, or NaN. + + @param size typographic height of text + @return initialized SkFont + */ + SkFont makeWithSize(SkScalar size) const; + + /** Returns SkTypeface if set, or nullptr. + Does not alter SkTypeface SkRefCnt. + + @return SkTypeface if previously set, nullptr otherwise + */ + SkTypeface* getTypeface() const {return fTypeface.get(); } + + /** Returns SkTypeface if set, or the default typeface. + Does not alter SkTypeface SkRefCnt. + + @return SkTypeface if previously set or, a pointer to the default typeface if not + previously set. + */ + SkTypeface* getTypefaceOrDefault() const; + + /** Returns text size in points. + + @return typographic height of text + */ + SkScalar getSize() const { return fSize; } + + /** Returns text scale on x-axis. + Default value is 1. + + @return text horizontal scale + */ + SkScalar getScaleX() const { return fScaleX; } + + /** Returns text skew on x-axis. + Default value is zero. + + @return additional shear on x-axis relative to y-axis + */ + SkScalar getSkewX() const { return fSkewX; } + + /** Increases SkTypeface SkRefCnt by one. + + @return SkTypeface if previously set, nullptr otherwise + */ + sk_sp refTypeface() const { return fTypeface; } + + /** Increases SkTypeface SkRefCnt by one. + + @return SkTypeface if previously set or, a pointer to the default typeface if not + previously set. + */ + sk_sp refTypefaceOrDefault() const; + + /** Sets SkTypeface to typeface, decreasing SkRefCnt of the previous SkTypeface. + Pass nullptr to clear SkTypeface and use the default typeface. Increments + tf SkRefCnt by one. + + @param tf font and style used to draw text + */ + void setTypeface(sk_sp tf) { fTypeface = tf; } + + /** Sets text size in points. + Has no effect if textSize is not greater than or equal to zero. + + @param textSize typographic height of text + */ + void setSize(SkScalar textSize); + + /** Sets text scale on x-axis. + Default value is 1. + + @param scaleX text horizontal scale + */ + void setScaleX(SkScalar scaleX); + + /** Sets text skew on x-axis. + Default value is zero. + + @param skewX additional shear on x-axis relative to y-axis + */ + void setSkewX(SkScalar skewX); + + /** Converts text into glyph indices. + Returns the number of glyph indices represented by text. + SkTextEncoding specifies how text represents characters or glyphs. + glyphs may be nullptr, to compute the glyph count. + + Does not check text for valid character codes or valid glyph indices. + + If byteLength equals zero, returns zero. + If byteLength includes a partial character, the partial character is ignored. + + If encoding is SkTextEncoding::kUTF8 and text contains an invalid UTF-8 sequence, + zero is returned. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32; then each Unicode codepoint is mapped to a + single glyph. This function uses the default character-to-glyph + mapping from the SkTypeface and maps characters not found in the + SkTypeface to zero. + + If maxGlyphCount is not sufficient to store all the glyphs, no glyphs are copied. + The total glyph count is returned for subsequent buffer reallocation. + + @param text character storage encoded with SkTextEncoding + @param byteLength length of character storage in bytes + @param glyphs storage for glyph indices; may be nullptr + @param maxGlyphCount storage capacity + @return number of glyphs represented by text of length byteLength + */ + int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding, + SkGlyphID glyphs[], int maxGlyphCount) const; + + /** Returns glyph index for Unicode character. + + If the character is not supported by the SkTypeface, returns 0. + + @param uni Unicode character + @return glyph index + */ + SkGlyphID unicharToGlyph(SkUnichar uni) const; + + void unicharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const; + + /** Returns number of glyphs represented by text. + + If encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32; then each Unicode codepoint is mapped to a + single glyph. + + @param text character storage encoded with SkTextEncoding + @param byteLength length of character storage in bytes + @return number of glyphs represented by text of length byteLength + */ + int countText(const void* text, size_t byteLength, SkTextEncoding encoding) const { + return this->textToGlyphs(text, byteLength, encoding, nullptr, 0); + } + + /** Returns the advance width of text. + The advance is the normal distance to move before drawing additional text. + Returns the bounding box of text if bounds is not nullptr. + + @param text character storage encoded with SkTextEncoding + @param byteLength length of character storage in bytes + @param bounds returns bounding box relative to (0, 0) if not nullptr + @return the sum of the default advance widths + */ + SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding encoding, + SkRect* bounds = nullptr) const { + return this->measureText(text, byteLength, encoding, bounds, nullptr); + } + + /** Returns the advance width of text. + The advance is the normal distance to move before drawing additional text. + Returns the bounding box of text if bounds is not nullptr. The paint + stroke settings, mask filter, or path effect may modify the bounds. + + @param text character storage encoded with SkTextEncoding + @param byteLength length of character storage in bytes + @param bounds returns bounding box relative to (0, 0) if not nullptr + @param paint optional; may be nullptr + @return the sum of the default advance widths + */ + SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding encoding, + SkRect* bounds, const SkPaint* paint) const; + + /** DEPRECATED + Retrieves the advance and bounds for each glyph in glyphs. + Both widths and bounds may be nullptr. + If widths is not nullptr, widths must be an array of count entries. + if bounds is not nullptr, bounds must be an array of count entries. + + @param glyphs array of glyph indices to be measured + @param count number of glyphs + @param widths returns text advances for each glyph; may be nullptr + @param bounds returns bounds for each glyph relative to (0, 0); may be nullptr + */ + void getWidths(const SkGlyphID glyphs[], int count, SkScalar widths[], SkRect bounds[]) const { + this->getWidthsBounds(glyphs, count, widths, bounds, nullptr); + } + + // DEPRECATED + void getWidths(const SkGlyphID glyphs[], int count, SkScalar widths[], std::nullptr_t) const { + this->getWidths(glyphs, count, widths); + } + + /** Retrieves the advance and bounds for each glyph in glyphs. + Both widths and bounds may be nullptr. + If widths is not nullptr, widths must be an array of count entries. + if bounds is not nullptr, bounds must be an array of count entries. + + @param glyphs array of glyph indices to be measured + @param count number of glyphs + @param widths returns text advances for each glyph + */ + void getWidths(const SkGlyphID glyphs[], int count, SkScalar widths[]) const { + this->getWidthsBounds(glyphs, count, widths, nullptr, nullptr); + } + + /** Retrieves the advance and bounds for each glyph in glyphs. + Both widths and bounds may be nullptr. + If widths is not nullptr, widths must be an array of count entries. + if bounds is not nullptr, bounds must be an array of count entries. + + @param glyphs array of glyph indices to be measured + @param count number of glyphs + @param widths returns text advances for each glyph; may be nullptr + @param bounds returns bounds for each glyph relative to (0, 0); may be nullptr + @param paint optional, specifies stroking, SkPathEffect and SkMaskFilter + */ + void getWidthsBounds(const SkGlyphID glyphs[], int count, SkScalar widths[], SkRect bounds[], + const SkPaint* paint) const; + + + /** Retrieves the bounds for each glyph in glyphs. + bounds must be an array of count entries. + If paint is not nullptr, its stroking, SkPathEffect, and SkMaskFilter fields are respected. + + @param glyphs array of glyph indices to be measured + @param count number of glyphs + @param bounds returns bounds for each glyph relative to (0, 0); may be nullptr + @param paint optional, specifies stroking, SkPathEffect, and SkMaskFilter + */ + void getBounds(const SkGlyphID glyphs[], int count, SkRect bounds[], + const SkPaint* paint) const { + this->getWidthsBounds(glyphs, count, nullptr, bounds, paint); + } + + /** Retrieves the positions for each glyph, beginning at the specified origin. The caller + must allocated at least count number of elements in the pos[] array. + + @param glyphs array of glyph indices to be positioned + @param count number of glyphs + @param pos returns glyphs positions + @param origin location of the first glyph. Defaults to {0, 0}. + */ + void getPos(const SkGlyphID glyphs[], int count, SkPoint pos[], SkPoint origin = {0, 0}) const; + + /** Retrieves the x-positions for each glyph, beginning at the specified origin. The caller + must allocated at least count number of elements in the xpos[] array. + + @param glyphs array of glyph indices to be positioned + @param count number of glyphs + @param xpos returns glyphs x-positions + @param origin x-position of the first glyph. Defaults to 0. + */ + void getXPos(const SkGlyphID glyphs[], int count, SkScalar xpos[], SkScalar origin = 0) const; + + /** Returns intervals [start, end] describing lines parallel to the advance that intersect + * with the glyphs. + * + * @param glyphs the glyphs to intersect + * @param count the number of glyphs and positions + * @param pos the position of each glyph + * @param top the top of the line intersecting + * @param bottom the bottom of the line intersecting + @return array of pairs of x values [start, end]. May be empty. + */ + std::vector getIntercepts(const SkGlyphID glyphs[], int count, const SkPoint pos[], + SkScalar top, SkScalar bottom, + const SkPaint* = nullptr) const; + + /** Modifies path to be the outline of the glyph. + If the glyph has an outline, modifies path to be the glyph's outline and returns true. + The glyph outline may be empty. Degenerate contours in the glyph outline will be skipped. + If glyph is described by a bitmap, returns false and ignores path parameter. + + @param glyphID index of glyph + @param path pointer to existing SkPath + @return true if glyphID is described by path + */ + bool getPath(SkGlyphID glyphID, SkPath* path) const; + + /** Returns path corresponding to glyph array. + + @param glyphIDs array of glyph indices + @param count number of glyphs + @param glyphPathProc function returning one glyph description as path + @param ctx function context + */ + void getPaths(const SkGlyphID glyphIDs[], int count, + void (*glyphPathProc)(const SkPath* pathOrNull, const SkMatrix& mx, void* ctx), + void* ctx) const; + + /** Returns SkFontMetrics associated with SkTypeface. + The return value is the recommended spacing between lines: the sum of metrics + descent, ascent, and leading. + If metrics is not nullptr, SkFontMetrics is copied to metrics. + Results are scaled by text size but does not take into account + dimensions required by text scale, text skew, fake bold, + style stroke, and SkPathEffect. + + @param metrics storage for SkFontMetrics; may be nullptr + @return recommended spacing between lines + */ + SkScalar getMetrics(SkFontMetrics* metrics) const; + + /** Returns the recommended spacing between lines: the sum of metrics + descent, ascent, and leading. + Result is scaled by text size but does not take into account + dimensions required by stroking and SkPathEffect. + Returns the same result as getMetrics(). + + @return recommended spacing between lines + */ + SkScalar getSpacing() const { return this->getMetrics(nullptr); } + + /** Dumps fields of the font to SkDebugf. May change its output over time, so clients should + * not rely on this for anything specific. Used to aid in debugging. + */ + void dump() const; + + using sk_is_trivially_relocatable = std::true_type; + +private: + enum PrivFlags { + kForceAutoHinting_PrivFlag = 1 << 0, + kEmbeddedBitmaps_PrivFlag = 1 << 1, + kSubpixel_PrivFlag = 1 << 2, + kLinearMetrics_PrivFlag = 1 << 3, + kEmbolden_PrivFlag = 1 << 4, + kBaselineSnap_PrivFlag = 1 << 5, + }; + + static constexpr unsigned kAllFlags = kForceAutoHinting_PrivFlag + | kEmbeddedBitmaps_PrivFlag + | kSubpixel_PrivFlag + | kLinearMetrics_PrivFlag + | kEmbolden_PrivFlag + | kBaselineSnap_PrivFlag; + + sk_sp fTypeface; + SkScalar fSize; + SkScalar fScaleX; + SkScalar fSkewX; + uint8_t fFlags; + uint8_t fEdging; + uint8_t fHinting; + + static_assert(::sk_is_trivially_relocatable::value); + + SkScalar setupForAsPaths(SkPaint*); + bool hasSomeAntiAliasing() const; + + friend class SkFontPriv; + friend class SkGlyphRunListPainterCPU; + friend class SkStrikeSpec; + friend class SkRemoteGlyphCacheTest; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontArguments.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontArguments.h new file mode 100644 index 00000000000000..a5139bb21bde68 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontArguments.h @@ -0,0 +1,94 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontArguments_DEFINED +#define SkFontArguments_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +/** Represents a set of actual arguments for a font. */ +struct SkFontArguments { + struct VariationPosition { + struct Coordinate { + SkFourByteTag axis; + float value; + }; + const Coordinate* coordinates; + int coordinateCount; + }; + + /** Specify a palette to use and overrides for palette entries. + * + * `overrides` is a list of pairs of palette entry index and color. + * The overriden palette entries will use the associated color. + * Override pairs with palette entry indices out of range will not be applied. + * Later override entries override earlier ones. + */ + struct Palette { + struct Override { + int index; + SkColor color; + }; + int index; + const Override* overrides; + int overrideCount; + }; + + SkFontArguments() + : fCollectionIndex(0) + , fVariationDesignPosition{nullptr, 0} + , fPalette{0, nullptr, 0} {} + + /** Specify the index of the desired font. + * + * Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed + * collections of fonts. + */ + SkFontArguments& setCollectionIndex(int collectionIndex) { + fCollectionIndex = collectionIndex; + return *this; + } + + /** Specify a position in the variation design space. + * + * Any axis not specified will use the default value. + * Any specified axis not actually present in the font will be ignored. + * + * @param position not copied. The value must remain valid for life of SkFontArguments. + */ + SkFontArguments& setVariationDesignPosition(VariationPosition position) { + fVariationDesignPosition.coordinates = position.coordinates; + fVariationDesignPosition.coordinateCount = position.coordinateCount; + return *this; + } + + int getCollectionIndex() const { + return fCollectionIndex; + } + + VariationPosition getVariationDesignPosition() const { + return fVariationDesignPosition; + } + + SkFontArguments& setPalette(Palette palette) { + fPalette.index = palette.index; + fPalette.overrides = palette.overrides; + fPalette.overrideCount = palette.overrideCount; + return *this; + } + + Palette getPalette() const { return fPalette; } + +private: + int fCollectionIndex; + VariationPosition fVariationDesignPosition; + Palette fPalette; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontMetrics.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontMetrics.h new file mode 100644 index 00000000000000..f4960393113cb7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontMetrics.h @@ -0,0 +1,139 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMetrics_DEFINED +#define SkFontMetrics_DEFINED + +#include "include/core/SkScalar.h" +#include "include/private/base/SkTo.h" + +/** \class SkFontMetrics + The metrics of an SkFont. + The metric values are consistent with the Skia y-down coordinate system. + */ +struct SK_API SkFontMetrics { + bool operator==(const SkFontMetrics& that) { + return + this->fFlags == that.fFlags && + this->fTop == that.fTop && + this->fAscent == that.fAscent && + this->fDescent == that.fDescent && + this->fBottom == that.fBottom && + this->fLeading == that.fLeading && + this->fAvgCharWidth == that.fAvgCharWidth && + this->fMaxCharWidth == that.fMaxCharWidth && + this->fXMin == that.fXMin && + this->fXMax == that.fXMax && + this->fXHeight == that.fXHeight && + this->fCapHeight == that.fCapHeight && + this->fUnderlineThickness == that.fUnderlineThickness && + this->fUnderlinePosition == that.fUnderlinePosition && + this->fStrikeoutThickness == that.fStrikeoutThickness && + this->fStrikeoutPosition == that.fStrikeoutPosition; + } + + /** \enum FontMetricsFlags + FontMetricsFlags indicate when certain metrics are valid; + the underline or strikeout metrics may be valid and zero. + Fonts with embedded bitmaps may not have valid underline or strikeout metrics. + */ + enum FontMetricsFlags { + kUnderlineThicknessIsValid_Flag = 1 << 0, //!< set if fUnderlineThickness is valid + kUnderlinePositionIsValid_Flag = 1 << 1, //!< set if fUnderlinePosition is valid + kStrikeoutThicknessIsValid_Flag = 1 << 2, //!< set if fStrikeoutThickness is valid + kStrikeoutPositionIsValid_Flag = 1 << 3, //!< set if fStrikeoutPosition is valid + kBoundsInvalid_Flag = 1 << 4, //!< set if fTop, fBottom, fXMin, fXMax invalid + }; + + uint32_t fFlags; //!< FontMetricsFlags indicating which metrics are valid + SkScalar fTop; //!< greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable fonts + SkScalar fAscent; //!< distance to reserve above baseline, typically negative + SkScalar fDescent; //!< distance to reserve below baseline, typically positive + SkScalar fBottom; //!< greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable fonts + SkScalar fLeading; //!< distance to add between lines, typically positive or zero + SkScalar fAvgCharWidth; //!< average character width, zero if unknown + SkScalar fMaxCharWidth; //!< maximum character width, zero if unknown + SkScalar fXMin; //!< greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with variable fonts + SkScalar fXMax; //!< greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with variable fonts + SkScalar fXHeight; //!< height of lower-case 'x', zero if unknown, typically negative + SkScalar fCapHeight; //!< height of an upper-case letter, zero if unknown, typically negative + SkScalar fUnderlineThickness; //!< underline thickness + SkScalar fUnderlinePosition; //!< distance from baseline to top of stroke, typically positive + SkScalar fStrikeoutThickness; //!< strikeout thickness + SkScalar fStrikeoutPosition; //!< distance from baseline to bottom of stroke, typically negative + + /** Returns true if SkFontMetrics has a valid underline thickness, and sets + thickness to that value. If the underline thickness is not valid, + return false, and ignore thickness. + + @param thickness storage for underline width + @return true if font specifies underline width + */ + bool hasUnderlineThickness(SkScalar* thickness) const { + if (SkToBool(fFlags & kUnderlineThicknessIsValid_Flag)) { + *thickness = fUnderlineThickness; + return true; + } + return false; + } + + /** Returns true if SkFontMetrics has a valid underline position, and sets + position to that value. If the underline position is not valid, + return false, and ignore position. + + @param position storage for underline position + @return true if font specifies underline position + */ + bool hasUnderlinePosition(SkScalar* position) const { + if (SkToBool(fFlags & kUnderlinePositionIsValid_Flag)) { + *position = fUnderlinePosition; + return true; + } + return false; + } + + /** Returns true if SkFontMetrics has a valid strikeout thickness, and sets + thickness to that value. If the underline thickness is not valid, + return false, and ignore thickness. + + @param thickness storage for strikeout width + @return true if font specifies strikeout width + */ + bool hasStrikeoutThickness(SkScalar* thickness) const { + if (SkToBool(fFlags & kStrikeoutThicknessIsValid_Flag)) { + *thickness = fStrikeoutThickness; + return true; + } + return false; + } + + /** Returns true if SkFontMetrics has a valid strikeout position, and sets + position to that value. If the underline position is not valid, + return false, and ignore position. + + @param position storage for strikeout position + @return true if font specifies strikeout position + */ + bool hasStrikeoutPosition(SkScalar* position) const { + if (SkToBool(fFlags & kStrikeoutPositionIsValid_Flag)) { + *position = fStrikeoutPosition; + return true; + } + return false; + } + + /** Returns true if SkFontMetrics has a valid fTop, fBottom, fXMin, and fXMax. + If the bounds are not valid, return false. + + @return true if font specifies maximum glyph bounds + */ + bool hasBounds() const { + return !SkToBool(fFlags & kBoundsInvalid_Flag); + } +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontMgr.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontMgr.h new file mode 100644 index 00000000000000..eccb0a729cba03 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontMgr.h @@ -0,0 +1,151 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_DEFINED +#define SkFontMgr_DEFINED + +#include "include/core/SkFontArguments.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include + +class SkData; +class SkFontData; +class SkStreamAsset; +class SkString; +class SkTypeface; + +class SK_API SkFontStyleSet : public SkRefCnt { +public: + virtual int count() = 0; + virtual void getStyle(int index, SkFontStyle*, SkString* style) = 0; + virtual sk_sp createTypeface(int index) = 0; + virtual sk_sp matchStyle(const SkFontStyle& pattern) = 0; + + static sk_sp CreateEmpty(); + +protected: + sk_sp matchStyleCSS3(const SkFontStyle& pattern); +}; + +class SK_API SkFontMgr : public SkRefCnt { +public: + int countFamilies() const; + void getFamilyName(int index, SkString* familyName) const; + sk_sp createStyleSet(int index) const; + + /** + * The caller must call unref() on the returned object. + * Never returns NULL; will return an empty set if the name is not found. + * + * Passing nullptr as the parameter will return the default system family. + * Note that most systems don't have a default system family, so passing nullptr will often + * result in the empty set. + * + * It is possible that this will return a style set not accessible from + * createStyleSet(int) due to hidden or auto-activated fonts. + */ + sk_sp matchFamily(const char familyName[]) const; + + /** + * Find the closest matching typeface to the specified familyName and style + * and return a ref to it. The caller must call unref() on the returned + * object. Will return nullptr if no 'good' match is found. + * + * Passing |nullptr| as the parameter for |familyName| will return the + * default system font. + * + * It is possible that this will return a style set not accessible from + * createStyleSet(int) or matchFamily(const char[]) due to hidden or + * auto-activated fonts. + */ + sk_sp matchFamilyStyle(const char familyName[], const SkFontStyle&) const; + + /** + * Use the system fallback to find a typeface for the given character. + * Note that bcp47 is a combination of ISO 639, 15924, and 3166-1 codes, + * so it is fine to just pass a ISO 639 here. + * + * Will return NULL if no family can be found for the character + * in the system fallback. + * + * Passing |nullptr| as the parameter for |familyName| will return the + * default system font. + * + * bcp47[0] is the least significant fallback, bcp47[bcp47Count-1] is the + * most significant. If no specified bcp47 codes match, any font with the + * requested character will be matched. + */ + sk_sp matchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const; + + /** + * Create a typeface for the specified data and TTC index (pass 0 for none) + * or NULL if the data is not recognized. The caller must call unref() on + * the returned object if it is not null. + */ + sk_sp makeFromData(sk_sp, int ttcIndex = 0) const; + + /** + * Create a typeface for the specified stream and TTC index + * (pass 0 for none) or NULL if the stream is not recognized. The caller + * must call unref() on the returned object if it is not null. + */ + sk_sp makeFromStream(std::unique_ptr, int ttcIndex = 0) const; + + /* Experimental, API subject to change. */ + sk_sp makeFromStream(std::unique_ptr, const SkFontArguments&) const; + + /** + * Create a typeface for the specified fileName and TTC index + * (pass 0 for none) or NULL if the file is not found, or its contents are + * not recognized. The caller must call unref() on the returned object + * if it is not null. + */ + sk_sp makeFromFile(const char path[], int ttcIndex = 0) const; + + sk_sp legacyMakeTypeface(const char familyName[], SkFontStyle style) const; + + /** Return the default fontmgr. */ + static sk_sp RefDefault(); + + /* Returns an empty font manager without any typeface dependencies */ + static sk_sp RefEmpty(); + +protected: + virtual int onCountFamilies() const = 0; + virtual void onGetFamilyName(int index, SkString* familyName) const = 0; + virtual sk_sp onCreateStyleSet(int index)const = 0; + + /** May return NULL if the name is not found. */ + virtual sk_sp onMatchFamily(const char familyName[]) const = 0; + + virtual sk_sp onMatchFamilyStyle(const char familyName[], + const SkFontStyle&) const = 0; + virtual sk_sp onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const = 0; + + virtual sk_sp onMakeFromData(sk_sp, int ttcIndex) const = 0; + virtual sk_sp onMakeFromStreamIndex(std::unique_ptr, + int ttcIndex) const = 0; + virtual sk_sp onMakeFromStreamArgs(std::unique_ptr, + const SkFontArguments&) const = 0; + virtual sk_sp onMakeFromFile(const char path[], int ttcIndex) const = 0; + + virtual sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const = 0; + +private: + /** Implemented by porting layer to return the default factory. */ + static sk_sp Factory(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontParameters.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontParameters.h new file mode 100644 index 00000000000000..ae4f1d68b6c87a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontParameters.h @@ -0,0 +1,42 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontParameters_DEFINED +#define SkFontParameters_DEFINED + +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +struct SkFontParameters { + struct Variation { + // Parameters in a variation font axis. + struct Axis { + constexpr Axis() : tag(0), min(0), def(0), max(0), flags(0) {} + constexpr Axis(SkFourByteTag tag, float min, float def, float max, bool hidden) : + tag(tag), min(min), def(def), max(max), flags(hidden ? HIDDEN : 0) {} + + // Four character identifier of the font axis (weight, width, slant, italic...). + SkFourByteTag tag; + // Minimum value supported by this axis. + float min; + // Default value set by this axis. + float def; + // Maximum value supported by this axis. The maximum can equal the minimum. + float max; + // Return whether this axis is recommended to be remain hidden in user interfaces. + bool isHidden() const { return flags & HIDDEN; } + // Set this axis to be remain hidden in user interfaces. + void setHidden(bool hidden) { flags = hidden ? (flags | HIDDEN) : (flags & ~HIDDEN); } + private: + static constexpr uint16_t HIDDEN = 0x0001; + // Attributes for a font axis. + uint16_t flags; + }; + }; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontStyle.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontStyle.h new file mode 100644 index 00000000000000..be46b53bb28527 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontStyle.h @@ -0,0 +1,84 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontStyle_DEFINED +#define SkFontStyle_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/base/SkTPin.h" + +#include + +class SK_API SkFontStyle { +public: + enum Weight { + kInvisible_Weight = 0, + kThin_Weight = 100, + kExtraLight_Weight = 200, + kLight_Weight = 300, + kNormal_Weight = 400, + kMedium_Weight = 500, + kSemiBold_Weight = 600, + kBold_Weight = 700, + kExtraBold_Weight = 800, + kBlack_Weight = 900, + kExtraBlack_Weight = 1000, + }; + + enum Width { + kUltraCondensed_Width = 1, + kExtraCondensed_Width = 2, + kCondensed_Width = 3, + kSemiCondensed_Width = 4, + kNormal_Width = 5, + kSemiExpanded_Width = 6, + kExpanded_Width = 7, + kExtraExpanded_Width = 8, + kUltraExpanded_Width = 9, + }; + + enum Slant { + kUpright_Slant, + kItalic_Slant, + kOblique_Slant, + }; + + constexpr SkFontStyle(int weight, int width, Slant slant) : fValue( + (SkTPin(weight, kInvisible_Weight, kExtraBlack_Weight)) + + (SkTPin(width, kUltraCondensed_Width, kUltraExpanded_Width) << 16) + + (SkTPin(slant, kUpright_Slant, kOblique_Slant) << 24) + ) { } + + constexpr SkFontStyle() : SkFontStyle{kNormal_Weight, kNormal_Width, kUpright_Slant} { } + + bool operator==(const SkFontStyle& rhs) const { + return fValue == rhs.fValue; + } + + int weight() const { return fValue & 0xFFFF; } + int width() const { return (fValue >> 16) & 0xFF; } + Slant slant() const { return (Slant)((fValue >> 24) & 0xFF); } + + static constexpr SkFontStyle Normal() { + return SkFontStyle(kNormal_Weight, kNormal_Width, kUpright_Slant); + } + static constexpr SkFontStyle Bold() { + return SkFontStyle(kBold_Weight, kNormal_Width, kUpright_Slant); + } + static constexpr SkFontStyle Italic() { + return SkFontStyle(kNormal_Weight, kNormal_Width, kItalic_Slant ); + } + static constexpr SkFontStyle BoldItalic() { + return SkFontStyle(kBold_Weight, kNormal_Width, kItalic_Slant ); + } + +private: + friend class SkTypefaceProxyPrototype; // To serialize fValue + int32_t fValue; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontTypes.h new file mode 100644 index 00000000000000..76f5dde67fe838 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkFontTypes.h @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontTypes_DEFINED +#define SkFontTypes_DEFINED + +enum class SkTextEncoding { + kUTF8, //!< uses bytes to represent UTF-8 or ASCII + kUTF16, //!< uses two byte words to represent most of Unicode + kUTF32, //!< uses four byte words to represent all of Unicode + kGlyphID, //!< uses two byte words to represent glyph indices +}; + +enum class SkFontHinting { + kNone, //!< glyph outlines unchanged + kSlight, //!< minimal modification to improve constrast + kNormal, //!< glyph outlines modified to improve constrast + kFull, //!< modifies glyph outlines for maximum constrast +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkGraphics.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkGraphics.h new file mode 100644 index 00000000000000..6ce9175d1e091a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkGraphics.h @@ -0,0 +1,178 @@ +/* + * 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 SkGraphics_DEFINED +#define SkGraphics_DEFINED + +#include "include/core/SkRefCnt.h" + +#include + +class SkData; +class SkImageGenerator; +class SkOpenTypeSVGDecoder; +class SkPath; +class SkTraceMemoryDump; + +class SK_API SkGraphics { +public: + /** + * Call this at process initialization time if your environment does not + * permit static global initializers that execute code. + * Init() is thread-safe and idempotent. + */ + static void Init(); + + /** + * Return the max number of bytes that should be used by the font cache. + * If the cache needs to allocate more, it will purge previous entries. + * This max can be changed by calling SetFontCacheLimit(). + */ + static size_t GetFontCacheLimit(); + + /** + * Specify the max number of bytes that should be used by the font cache. + * If the cache needs to allocate more, it will purge previous entries. + * + * This function returns the previous setting, as if GetFontCacheLimit() + * had be called before the new limit was set. + */ + static size_t SetFontCacheLimit(size_t bytes); + + /** + * Return the number of bytes currently used by the font cache. + */ + static size_t GetFontCacheUsed(); + + /** + * Return the number of entries in the font cache. + * A cache "entry" is associated with each typeface + pointSize + matrix. + */ + static int GetFontCacheCountUsed(); + + /** + * Return the current limit to the number of entries in the font cache. + * A cache "entry" is associated with each typeface + pointSize + matrix. + */ + static int GetFontCacheCountLimit(); + + /** + * Set the limit to the number of entries in the font cache, and return + * the previous value. If this new value is lower than the previous, + * it will automatically try to purge entries to meet the new limit. + */ + static int SetFontCacheCountLimit(int count); + + /** + * For debugging purposes, this will attempt to purge the font cache. It + * does not change the limit, but will cause subsequent font measures and + * draws to be recreated, since they will no longer be in the cache. + */ + static void PurgeFontCache(); + + /** + * This function returns the memory used for temporary images and other resources. + */ + static size_t GetResourceCacheTotalBytesUsed(); + + /** + * These functions get/set the memory usage limit for the resource cache, used for temporary + * bitmaps and other resources. Entries are purged from the cache when the memory useage + * exceeds this limit. + */ + static size_t GetResourceCacheTotalByteLimit(); + static size_t SetResourceCacheTotalByteLimit(size_t newLimit); + + /** + * For debugging purposes, this will attempt to purge the resource cache. It + * does not change the limit. + */ + static void PurgeResourceCache(); + + /** + * When the cachable entry is very lage (e.g. a large scaled bitmap), adding it to the cache + * can cause most/all of the existing entries to be purged. To avoid the, the client can set + * a limit for a single allocation. If a cacheable entry would have been cached, but its size + * exceeds this limit, then we do not attempt to cache it at all. + * + * Zero is the default value, meaning we always attempt to cache entries. + */ + static size_t GetResourceCacheSingleAllocationByteLimit(); + static size_t SetResourceCacheSingleAllocationByteLimit(size_t newLimit); + + /** + * Dumps memory usage of caches using the SkTraceMemoryDump interface. See SkTraceMemoryDump + * for usage of this method. + */ + static void DumpMemoryStatistics(SkTraceMemoryDump* dump); + + /** + * Free as much globally cached memory as possible. This will purge all private caches in Skia, + * including font and image caches. + * + * If there are caches associated with GPU context, those will not be affected by this call. + */ + static void PurgeAllCaches(); + + typedef std::unique_ptr + (*ImageGeneratorFromEncodedDataFactory)(sk_sp); + + /** + * To instantiate images from encoded data, first looks at this runtime function-ptr. If it + * exists, it is called to create an SkImageGenerator from SkData. If there is no function-ptr + * or there is, but it returns NULL, then skia will call its internal default implementation. + * + * Returns the previous factory (which could be NULL). + */ + static ImageGeneratorFromEncodedDataFactory + SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory); + + /** + * To draw OpenType SVG data, Skia will look at this runtime function pointer. If this function + * pointer is set, the SkTypeface implementations which support OpenType SVG will call this + * function to create an SkOpenTypeSVGDecoder to decode the OpenType SVG and draw it as needed. + * If this function is not set, the SkTypeface implementations will generally not support + * OpenType SVG and attempt to use other glyph representations if available. + */ + using OpenTypeSVGDecoderFactory = + std::unique_ptr (*)(const uint8_t* svg, size_t length); + static OpenTypeSVGDecoderFactory SetOpenTypeSVGDecoderFactory(OpenTypeSVGDecoderFactory); + static OpenTypeSVGDecoderFactory GetOpenTypeSVGDecoderFactory(); + + /** + * Call early in main() to allow Skia to use a JIT to accelerate CPU-bound operations. + */ + static void AllowJIT(); + + /** + * To override the default AA algorithm choice in the CPU backend, provide a function that + * returns whether to use analytic (true) or supersampled (false) for a given path. + * + * NOTE: This is a temporary API, intended for migration of all clients to one algorithm, + * and should not be used. + */ + typedef bool (*PathAnalyticAADeciderProc)(const SkPath&); + static void SetPathAnalyticAADecider(PathAnalyticAADeciderProc); + + /* + * Similar to above, but simply forces the CPU backend to always use analytic AA. + * + * NOTE: This is a temporary API, intended for migration of all clients to one algorithm. + * If the PathAnalyticAADeciderProc is *also* set, this setting has no effect. + * Unlike that API, this function is thread-safe. + */ + static void SetForceAnalyticAA(bool); +}; + +class SkAutoGraphics { +public: + SkAutoGraphics() { + SkGraphics::Init(); + } +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkICC.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkICC.h new file mode 100644 index 00000000000000..c0b458100cf889 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkICC.h @@ -0,0 +1,9 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// TODO(kjlubick) remove this shim after clients have been moved to the new location +#include "include/encode/SkICC.h" // IWYU pragma: export diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImage.h new file mode 100644 index 00000000000000..8f7d4a46bd9d95 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImage.h @@ -0,0 +1,1085 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImage_DEFINED +#define SkImage_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/private/base/SkAPI.h" + +#if defined(SK_GRAPHITE) +#include "include/gpu/graphite/GraphiteTypes.h" +class SkYUVAPixmaps; +#endif + +#include +#include +#include +#include + +class GrDirectContext; +class GrRecordingContext; +class SkBitmap; +class SkColorSpace; +class SkData; +class SkImage; +class SkImageFilter; +class SkImageGenerator; +class SkMatrix; +class SkMipmap; +class SkPaint; +class SkPicture; +class SkPixmap; +class SkShader; +class SkSurfaceProps; +enum SkColorType : int; +enum class SkTextureCompressionType; +enum class SkTileMode; + +struct SkIPoint; +struct SkSamplingOptions; + +#if defined(SK_GRAPHITE) +namespace skgpu::graphite { +class BackendTexture; +class Recorder; +class TextureInfo; +enum class Volatile : bool; +class YUVABackendTextures; +} +#endif + +namespace SkImages { + +/** Caller data passed to RasterReleaseProc; may be nullptr. */ +using ReleaseContext = void*; +/** Function called when SkImage no longer shares pixels. ReleaseContext is + provided by caller when SkImage is created, and may be nullptr. +*/ +using RasterReleaseProc = void(const void* pixels, ReleaseContext); + +/** Creates a CPU-backed SkImage from bitmap, sharing or copying bitmap pixels. If the bitmap + is marked immutable, and its pixel memory is shareable, it may be shared + instead of copied. + + SkImage is returned if bitmap is valid. Valid SkBitmap parameters include: + dimensions are greater than zero; + each dimension fits in 29 bits; + SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType; + row bytes are large enough to hold one row of pixels; + pixel address is not nullptr. + + @param bitmap SkImageInfo, row bytes, and pixels + @return created SkImage, or nullptr +*/ +SK_API sk_sp RasterFromBitmap(const SkBitmap& bitmap); + +/** Creates a CPU-backed SkImage from compressed data. + + This method will decompress the compressed data and create an image wrapping + it. Any mipmap levels present in the compressed data are discarded. + + @param data compressed data to store in SkImage + @param width width of full SkImage + @param height height of full SkImage + @param type type of compression used + @return created SkImage, or nullptr +*/ +SK_API sk_sp RasterFromCompressedTextureData(sk_sp data, + int width, + int height, + SkTextureCompressionType type); + +/** + * Return a SkImage using the encoded data, but attempts to defer decoding until the + * image is actually used/drawn. This deferral allows the system to cache the result, either on the + * CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may + * be purged, causing the next draw of the image to have to re-decode. + * + * If alphaType is nullopt, the image's alpha type will be chosen automatically based on the + * image format. Transparent images will default to kPremul_SkAlphaType. If alphaType contains + * kPremul_SkAlphaType or kUnpremul_SkAlphaType, that alpha type will be used. Forcing opaque + * (passing kOpaque_SkAlphaType) is not allowed, and will return nullptr. + * + * If the encoded format is not supported, nullptr is returned. + * + * @param encoded the encoded data + * @return created SkImage, or nullptr + + example: https://fiddle.skia.org/c/@Image_DeferredFromEncodedData +*/ +SK_API sk_sp DeferredFromEncodedData(sk_sp encoded, + std::optional alphaType = std::nullopt); + +/** Creates SkImage from data returned by imageGenerator. The image data will not be created + (on either the CPU or GPU) until the image is actually drawn. + Generated data is owned by SkImage and may not be shared or accessed. + + SkImage is returned if generator data is valid. Valid data parameters vary by type of data + and platform. + + imageGenerator may wrap SkPicture data, codec data, or custom data. + + @param imageGenerator stock or custom routines to retrieve SkImage + @return created SkImage, or nullptr +*/ +SK_API sk_sp DeferredFromGenerator(std::unique_ptr imageGenerator); + +enum class BitDepth { + kU8, //!< uses 8-bit unsigned int per color component + kF16, //!< uses 16-bit float per color component +}; + +/** Creates SkImage from picture. Returned SkImage width and height are set by dimensions. + SkImage draws picture with matrix and paint, set to bitDepth and colorSpace. + + The Picture data is not turned into an image (CPU or GPU) until it is drawn. + + If matrix is nullptr, draws with identity SkMatrix. If paint is nullptr, draws + with default SkPaint. colorSpace may be nullptr. + + @param picture stream of drawing commands + @param dimensions width and height + @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr + @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr + @param bitDepth 8-bit integer or 16-bit float: per component + @param colorSpace range of colors; may be nullptr + @param props props to use when rasterizing the picture + @return created SkImage, or nullptr +*/ +SK_API sk_sp DeferredFromPicture(sk_sp picture, + const SkISize& dimensions, + const SkMatrix* matrix, + const SkPaint* paint, + BitDepth bitDepth, + sk_sp colorSpace, + SkSurfaceProps props); +SK_API sk_sp DeferredFromPicture(sk_sp picture, + const SkISize& dimensions, + const SkMatrix* matrix, + const SkPaint* paint, + BitDepth bitDepth, + sk_sp colorSpace); + +/** Creates a CPU-backed SkImage from pixmap, copying the pixel data. + As a result, pixmap pixels may be modified or deleted without affecting SkImage. + + SkImage is returned if SkPixmap is valid. Valid SkPixmap parameters include: + dimensions are greater than zero; + each dimension fits in 29 bits; + SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType; + row bytes are large enough to hold one row of pixels; + pixel address is not nullptr. + + @param pixmap SkImageInfo, pixel address, and row bytes + @return copy of SkPixmap pixels, or nullptr + + example: https://fiddle.skia.org/c/@Image_RasterFromPixmapCopy +*/ +SK_API sk_sp RasterFromPixmapCopy(const SkPixmap& pixmap); + +/** Creates CPU-backed SkImage from pixmap, sharing SkPixmap pixels. Pixels must remain valid and + unchanged until rasterReleaseProc is called. rasterReleaseProc is passed + releaseContext when SkImage is deleted or no longer refers to pixmap pixels. + + Pass nullptr for rasterReleaseProc to share SkPixmap without requiring a callback + when SkImage is released. Pass nullptr for releaseContext if rasterReleaseProc + does not require state. + + SkImage is returned if pixmap is valid. Valid SkPixmap parameters include: + dimensions are greater than zero; + each dimension fits in 29 bits; + SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType; + row bytes are large enough to hold one row of pixels; + pixel address is not nullptr. + + @param pixmap SkImageInfo, pixel address, and row bytes + @param rasterReleaseProc function called when pixels can be released; or nullptr + @param releaseContext state passed to rasterReleaseProc; or nullptr + @return SkImage sharing pixmap +*/ +SK_API sk_sp RasterFromPixmap(const SkPixmap& pixmap, + RasterReleaseProc rasterReleaseProc, + ReleaseContext releaseContext); + +/** Creates CPU-backed SkImage from pixel data described by info. + The pixels data will *not* be copied. + + SkImage is returned if SkImageInfo is valid. Valid SkImageInfo parameters include: + dimensions are greater than zero; + each dimension fits in 29 bits; + SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType; + rowBytes are large enough to hold one row of pixels; + pixels is not nullptr, and contains enough data for SkImage. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage + @param rowBytes size of pixel row or larger + @return SkImage sharing pixels, or nullptr +*/ +SK_API sk_sp RasterFromData(const SkImageInfo& info, + sk_sp pixels, + size_t rowBytes); + +} // namespace SkImages + +/** \class SkImage + SkImage describes a two dimensional array of pixels to draw. The pixels may be + decoded in a raster bitmap, encoded in a SkPicture or compressed data stream, + or located in GPU memory as a GPU texture. + + SkImage cannot be modified after it is created. SkImage may allocate additional + storage as needed; for instance, an encoded SkImage may decode when drawn. + + SkImage width and height are greater than zero. Creating an SkImage with zero width + or height returns SkImage equal to nullptr. + + SkImage may be created from SkBitmap, SkPixmap, SkSurface, SkPicture, encoded streams, + GPU texture, YUV_ColorSpace data, or hardware buffer. Encoded streams supported + include BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP. Supported encoding details + vary with platform. + + See SkImages namespace for the static factory methods to make SkImages. + + Clients should *not* subclass SkImage as there is a lot of internal machinery that is + not publicly accessible. +*/ +class SK_API SkImage : public SkRefCnt { +public: + /** Returns a SkImageInfo describing the width, height, color type, alpha type, and color space + of the SkImage. + + @return image info of SkImage. + */ + const SkImageInfo& imageInfo() const { return fInfo; } + + /** Returns pixel count in each row. + + @return pixel width in SkImage + */ + int width() const { return fInfo.width(); } + + /** Returns pixel row count. + + @return pixel height in SkImage + */ + int height() const { return fInfo.height(); } + + /** Returns SkISize { width(), height() }. + + @return integral size of width() and height() + */ + SkISize dimensions() const { return SkISize::Make(fInfo.width(), fInfo.height()); } + + /** Returns SkIRect { 0, 0, width(), height() }. + + @return integral rectangle from origin to width() and height() + */ + SkIRect bounds() const { return SkIRect::MakeWH(fInfo.width(), fInfo.height()); } + + /** Returns value unique to image. SkImage contents cannot change after SkImage is + created. Any operation to create a new SkImage will receive generate a new + unique number. + + @return unique identifier + */ + uint32_t uniqueID() const { return fUniqueID; } + + /** Returns SkAlphaType. + + SkAlphaType returned was a parameter to an SkImage constructor, + or was parsed from encoded data. + + @return SkAlphaType in SkImage + + example: https://fiddle.skia.org/c/@Image_alphaType + */ + SkAlphaType alphaType() const; + + /** Returns SkColorType if known; otherwise, returns kUnknown_SkColorType. + + @return SkColorType of SkImage + + example: https://fiddle.skia.org/c/@Image_colorType + */ + SkColorType colorType() const; + + /** Returns SkColorSpace, the range of colors, associated with SkImage. The + reference count of SkColorSpace is unchanged. The returned SkColorSpace is + immutable. + + SkColorSpace returned was passed to an SkImage constructor, + or was parsed from encoded data. SkColorSpace returned may be ignored when SkImage + is drawn, depending on the capabilities of the SkSurface receiving the drawing. + + @return SkColorSpace in SkImage, or nullptr + + example: https://fiddle.skia.org/c/@Image_colorSpace + */ + SkColorSpace* colorSpace() const; + + /** Returns a smart pointer to SkColorSpace, the range of colors, associated with + SkImage. The smart pointer tracks the number of objects sharing this + SkColorSpace reference so the memory is released when the owners destruct. + + The returned SkColorSpace is immutable. + + SkColorSpace returned was passed to an SkImage constructor, + or was parsed from encoded data. SkColorSpace returned may be ignored when SkImage + is drawn, depending on the capabilities of the SkSurface receiving the drawing. + + @return SkColorSpace in SkImage, or nullptr, wrapped in a smart pointer + + example: https://fiddle.skia.org/c/@Image_refColorSpace + */ + sk_sp refColorSpace() const; + + /** Returns true if SkImage pixels represent transparency only. If true, each pixel + is packed in 8 bits as defined by kAlpha_8_SkColorType. + + @return true if pixels represent a transparency mask + + example: https://fiddle.skia.org/c/@Image_isAlphaOnly + */ + bool isAlphaOnly() const; + + /** Returns true if pixels ignore their alpha value and are treated as fully opaque. + + @return true if SkAlphaType is kOpaque_SkAlphaType + */ + bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); } + + /** + * Make a shader with the specified tiling and mipmap sampling. + */ + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling, + const SkMatrix& lm) const; + /** Defaults to clamp in both X and Y. */ + sk_sp makeShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const; + sk_sp makeShader(const SkSamplingOptions& sampling, + const SkMatrix* lm = nullptr) const; + + /** + * makeRawShader functions like makeShader, but for images that contain non-color data. + * This includes images encoding things like normals, material properties (eg, roughness), + * heightmaps, or any other purely mathematical data that happens to be stored in an image. + * These types of images are useful with some programmable shaders (see: SkRuntimeEffect). + * + * Raw image shaders work like regular image shaders (including filtering and tiling), with + * a few major differences: + * - No color space transformation is ever applied (the color space of the image is ignored). + * - Images with an alpha type of kUnpremul are *not* automatically premultiplied. + * - Bicubic filtering is not supported. If SkSamplingOptions::useCubic is true, these + * factories will return nullptr. + */ + sk_sp makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling, + const SkMatrix& lm) const; + /** Defaults to clamp in both X and Y. */ + sk_sp makeRawShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const; + sk_sp makeRawShader(const SkSamplingOptions& sampling, + const SkMatrix* lm = nullptr) const; + + /** Copies SkImage pixel address, row bytes, and SkImageInfo to pixmap, if address + is available, and returns true. If pixel address is not available, return + false and leave pixmap unchanged. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkImage has direct access to pixels + + example: https://fiddle.skia.org/c/@Image_peekPixels + */ + bool peekPixels(SkPixmap* pixmap) const; + + /** Returns true if the contents of SkImage was created on or uploaded to GPU memory, + and is available as a GPU texture. + + @return true if SkImage is a GPU texture + + example: https://fiddle.skia.org/c/@Image_isTextureBacked + */ + virtual bool isTextureBacked() const = 0; + + /** Returns an approximation of the amount of texture memory used by the image. Returns + zero if the image is not texture backed or if the texture has an external format. + */ + virtual size_t textureSize() const = 0; + + /** Returns true if SkImage can be drawn on either raster surface or GPU surface. + If context is nullptr, tests if SkImage draws on raster surface; + otherwise, tests if SkImage draws on GPU surface associated with context. + + SkImage backed by GPU texture may become invalid if associated context is + invalid. lazy image may be invalid and may not draw to raster surface or + GPU surface or both. + + @param context GPU context + @return true if SkImage can be drawn + + example: https://fiddle.skia.org/c/@Image_isValid + */ + virtual bool isValid(GrRecordingContext* context) const = 0; + + /** \enum SkImage::CachingHint + CachingHint selects whether Skia may internally cache SkBitmap generated by + decoding SkImage, or by copying SkImage from GPU to CPU. The default behavior + allows caching SkBitmap. + + Choose kDisallow_CachingHint if SkImage pixels are to be used only once, or + if SkImage pixels reside in a cache outside of Skia, or to reduce memory pressure. + + Choosing kAllow_CachingHint does not ensure that pixels will be cached. + SkImage pixels may not be cached if memory requirements are too large or + pixels are not accessible. + */ + enum CachingHint { + kAllow_CachingHint, //!< allows internally caching decoded and copied pixels + kDisallow_CachingHint, //!< disallows internally caching decoded and copied pixels + }; + + /** Copies SkRect of pixels from SkImage to dstPixels. Copy starts at offset (srcX, srcY), + and does not exceed SkImage (width(), height()). + + dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of + destination. dstRowBytes specifies the gap from one destination row to the next. + Returns true if pixels are copied. Returns false if: + - dstInfo.addr() equals nullptr + - dstRowBytes is less than dstInfo.minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If SkImage SkColorType is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If SkImage SkAlphaType is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If SkImage SkColorSpace is nullptr, dstInfo.colorSpace() must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= Image width(), or if abs(srcY) >= Image height(). + + If cachingHint is kAllow_CachingHint, pixels may be retained locally. + If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache. + + @param context the GrDirectContext in play, if it exists + @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace + @param dstPixels destination pixel storage + @param dstRowBytes destination row length + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @param cachingHint whether the pixels should be cached locally + @return true if pixels are copied to dstPixels + */ + bool readPixels(GrDirectContext* context, + const SkImageInfo& dstInfo, + void* dstPixels, + size_t dstRowBytes, + int srcX, int srcY, + CachingHint cachingHint = kAllow_CachingHint) const; + + /** Copies a SkRect of pixels from SkImage to dst. Copy starts at (srcX, srcY), and + does not exceed SkImage (width(), height()). + + dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of destination. dst.rowBytes() specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dst pixel storage equals nullptr + - dst.rowBytes is less than SkImageInfo::minRowBytes + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.colorType() must match. + If SkImage SkColorType is kGray_8_SkColorType, dst.colorSpace() must match. + If SkImage SkAlphaType is kOpaque_SkAlphaType, dst.alphaType() must + match. If SkImage SkColorSpace is nullptr, dst.colorSpace() must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= Image width(), or if abs(srcY) >= Image height(). + + If cachingHint is kAllow_CachingHint, pixels may be retained locally. + If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache. + + @param context the GrDirectContext in play, if it exists + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @param cachingHint whether the pixels should be cached locallyZ + @return true if pixels are copied to dst + */ + bool readPixels(GrDirectContext* context, + const SkPixmap& dst, + int srcX, + int srcY, + CachingHint cachingHint = kAllow_CachingHint) const; + +#ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API + /** Deprecated. Use the variants that accept a GrDirectContext. */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY, CachingHint cachingHint = kAllow_CachingHint) const; + bool readPixels(const SkPixmap& dst, int srcX, int srcY, + CachingHint cachingHint = kAllow_CachingHint) const; +#endif + + /** The result from asyncRescaleAndReadPixels() or asyncRescaleAndReadPixelsYUV420(). */ + class AsyncReadResult { + public: + AsyncReadResult(const AsyncReadResult&) = delete; + AsyncReadResult(AsyncReadResult&&) = delete; + AsyncReadResult& operator=(const AsyncReadResult&) = delete; + AsyncReadResult& operator=(AsyncReadResult&&) = delete; + + virtual ~AsyncReadResult() = default; + virtual int count() const = 0; + virtual const void* data(int i) const = 0; + virtual size_t rowBytes(int i) const = 0; + + protected: + AsyncReadResult() = default; + }; + + /** Client-provided context that is passed to client-provided ReadPixelsContext. */ + using ReadPixelsContext = void*; + + /** Client-provided callback to asyncRescaleAndReadPixels() or + asyncRescaleAndReadPixelsYUV420() that is called when read result is ready or on failure. + */ + using ReadPixelsCallback = void(ReadPixelsContext, std::unique_ptr); + + enum class RescaleGamma : bool { kSrc, kLinear }; + + enum class RescaleMode { + kNearest, + kLinear, + kRepeatedLinear, + kRepeatedCubic, + }; + + /** Makes image pixel data available to caller, possibly asynchronously. It can also rescale + the image pixels. + + Currently asynchronous reads are only supported on the GPU backend and only when the + underlying 3D API supports transfer buffers and CPU/GPU synchronization primitives. In all + other cases this operates synchronously. + + Data is read from the source sub-rectangle, is optionally converted to a linear gamma, is + rescaled to the size indicated by 'info', is then converted to the color space, color type, + and alpha type of 'info'. A 'srcRect' that is not contained by the bounds of the image + causes failure. + + When the pixel data is ready the caller's ReadPixelsCallback is called with a + AsyncReadResult containing pixel data in the requested color type, alpha type, and color + space. The AsyncReadResult will have count() == 1. Upon failure the callback is called with + nullptr for AsyncReadResult. For a GPU image this flushes work but a submit must occur to + guarantee a finite time before the callback is called. + + The data is valid for the lifetime of AsyncReadResult with the exception that if the SkImage + is GPU-backed the data is immediately invalidated if the context is abandoned or + destroyed. + + @param info info of the requested pixels + @param srcRect subrectangle of image to read + @param rescaleGamma controls whether rescaling is done in the image's gamma or whether + the source data is transformed to a linear gamma before rescaling. + @param rescaleMode controls the technique (and cost) of the rescaling + @param callback function to call with result of the read + @param context passed to callback + */ + void asyncRescaleAndReadPixels(const SkImageInfo& info, + const SkIRect& srcRect, + RescaleGamma rescaleGamma, + RescaleMode rescaleMode, + ReadPixelsCallback callback, + ReadPixelsContext context) const; + + /** + Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The + RGB->YUV conversion is controlled by 'yuvColorSpace'. The YUV data is returned as three + planes ordered y, u, v. The u and v planes are half the width and height of the resized + rectangle. The y, u, and v values are single bytes. Currently this fails if 'dstSize' + width and height are not even. A 'srcRect' that is not contained by the bounds of the + image causes failure. + + When the pixel data is ready the caller's ReadPixelsCallback is called with a + AsyncReadResult containing the planar data. The AsyncReadResult will have count() == 3. + Upon failure the callback is called with nullptr for AsyncReadResult. For a GPU image this + flushes work but a submit must occur to guarantee a finite time before the callback is + called. + + The data is valid for the lifetime of AsyncReadResult with the exception that if the SkImage + is GPU-backed the data is immediately invalidated if the context is abandoned or + destroyed. + + @param yuvColorSpace The transformation from RGB to YUV. Applied to the resized image + after it is converted to dstColorSpace. + @param dstColorSpace The color space to convert the resized image to, after rescaling. + @param srcRect The portion of the image to rescale and convert to YUV planes. + @param dstSize The size to rescale srcRect to + @param rescaleGamma controls whether rescaling is done in the image's gamma or whether + the source data is transformed to a linear gamma before rescaling. + @param rescaleMode controls the technique (and cost) of the rescaling + @param callback function to call with the planar read result + @param context passed to callback + */ + void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace, + sk_sp dstColorSpace, + const SkIRect& srcRect, + const SkISize& dstSize, + RescaleGamma rescaleGamma, + RescaleMode rescaleMode, + ReadPixelsCallback callback, + ReadPixelsContext context) const; + + /** Copies SkImage to dst, scaling pixels to fit dst.width() and dst.height(), and + converting pixels to match dst.colorType() and dst.alphaType(). Returns true if + pixels are copied. Returns false if dst.addr() is nullptr, or dst.rowBytes() is + less than dst SkImageInfo::minRowBytes. + + Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.colorType() must match. + If SkImage SkColorType is kGray_8_SkColorType, dst.colorSpace() must match. + If SkImage SkAlphaType is kOpaque_SkAlphaType, dst.alphaType() must + match. If SkImage SkColorSpace is nullptr, dst.colorSpace() must match. Returns + false if pixel conversion is not possible. + + If cachingHint is kAllow_CachingHint, pixels may be retained locally. + If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache. + + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @return true if pixels are scaled to fit dst + */ + bool scalePixels(const SkPixmap& dst, const SkSamplingOptions&, + CachingHint cachingHint = kAllow_CachingHint) const; + + /** Returns encoded SkImage pixels as SkData, if SkImage was created from supported + encoded stream format. Platform support for formats vary and may require building + with one or more of: SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP. + + Returns nullptr if SkImage contents are not encoded. + + @return encoded SkImage, or nullptr + + example: https://fiddle.skia.org/c/@Image_refEncodedData + */ + sk_sp refEncodedData() const; + + /** Returns subset of this image. + + Returns nullptr if any of the following are true: + - Subset is empty + - Subset is not contained inside the image's bounds + - Pixels in the image could not be read or copied + + If this image is texture-backed, the context parameter is required and must match the + context of the source image. If the context parameter is provided, and the image is + raster-backed, the subset will be converted to texture-backed. + + @param subset bounds of returned SkImage + @param context the GrDirectContext in play, if it exists + @return the subsetted image, or nullptr + + example: https://fiddle.skia.org/c/@Image_makeSubset + */ + sk_sp makeSubset(const SkIRect& subset, GrDirectContext* direct = nullptr) const; + + /** + * Returns true if the image has mipmap levels. + */ + bool hasMipmaps() const; + + /** + * Returns an image with the same "base" pixels as the this image, but with mipmap levels + * automatically generated and attached. + */ + sk_sp withDefaultMipmaps() const; + +#if defined(SK_GANESH) || defined(SK_GRAPHITE) + using ReleaseContext = SkImages::ReleaseContext; + using TextureReleaseProc = void (*)(ReleaseContext); +#endif + +#if defined(SK_GRAPHITE) + // Passed to both fulfill and imageRelease + using GraphitePromiseImageContext = void*; + // Returned from fulfill and passed into textureRelease + using GraphitePromiseTextureReleaseContext = void*; + + using GraphitePromiseImageFulfillProc = + std::tuple + (*)(GraphitePromiseImageContext); + using GraphitePromiseImageReleaseProc = void (*)(GraphitePromiseImageContext); + using GraphitePromiseTextureReleaseProc = void (*)(GraphitePromiseTextureReleaseContext); + + /** Create a new SkImage that is very similar to an SkImage created by + MakeGraphiteFromBackendTexture. The difference is that the caller need not have created the + backend texture nor populated it with data when creating the image. Instead of passing a + BackendTexture to the factory the client supplies a description of the texture consisting + of dimensions, TextureInfo, SkColorInfo and Volatility. + + In general, 'fulfill' must return a BackendTexture that matches the properties + provided at SkImage creation time. The BackendTexture must refer to a valid existing + texture in the backend API context/device, and already be populated with data. + The texture cannot be deleted until 'textureRelease' is called. 'textureRelease' will + be called with the textureReleaseContext returned by 'fulfill'. + + Wrt when and how often the fulfill, imageRelease, and textureRelease callbacks will + be called: + + For non-volatile promise images, 'fulfill' will be called at Context::insertRecording + time. Regardless of whether 'fulfill' succeeded or failed, 'imageRelease' will always be + called only once - when Skia will no longer try calling 'fulfill' to get a backend + texture. If 'fulfill' failed (i.e., it didn't return a valid backend texture) then + 'textureRelease' will never be called. If 'fulfill' was successful then + 'textureRelease' will be called only once when the GPU is done with the contents of the + promise image. This will usually occur during a Context::submit call but it could occur + earlier due to error conditions. 'fulfill' can be called multiple times if the promise + image is used in multiple recordings. If 'fulfill' fails, the insertRecording itself will + fail. Subsequent insertRecording calls (with Recordings that use the promise image) will + keep calling 'fulfill' until it succeeds. + + For volatile promise images, 'fulfill' will be called each time the Recording is inserted + into a Context. Regardless of whether 'fulfill' succeeded or failed, 'imageRelease' + will always be called only once just like the non-volatile case. If 'fulfill' fails at + insertRecording-time, 'textureRelease' will never be called. If 'fulfill' was successful + then a 'textureRelease' matching that 'fulfill' will be called when the GPU is done with + the contents of the promise image. This will usually occur during a Context::submit call + but it could occur earlier due to error conditions. + + @param recorder the recorder that will capture the commands creating the image + @param dimensions width & height of promised gpu texture + @param textureInfo structural information for the promised gpu texture + @param colorInfo color type, alpha type and colorSpace information for the image + @param isVolatile volatility of the promise image + @param fulfill function called to get the actual backend texture + @param imageRelease function called when any image-centric data can be deleted + @param textureRelease function called when the backend texture can be deleted + @param imageContext state passed to fulfill and imageRelease + @return created SkImage, or nullptr + */ + static sk_sp MakeGraphitePromiseTexture(skgpu::graphite::Recorder*, + SkISize dimensions, + const skgpu::graphite::TextureInfo&, + const SkColorInfo&, + skgpu::graphite::Volatile, + GraphitePromiseImageFulfillProc, + GraphitePromiseImageReleaseProc, + GraphitePromiseTextureReleaseProc, + GraphitePromiseImageContext); + + /** Creates an SkImage from a GPU texture associated with the recorder. + + SkImage is returned if the format of backendTexture is recognized and supported. + Recognized formats vary by GPU back-end. + + @param recorder The recorder + @param backendTexture texture residing on GPU + @param colorSpace This describes the color space of this image's contents, as + seen after sampling. In general, if the format of the backend + texture is SRGB, some linear colorSpace should be supplied + (e.g., SkColorSpace::MakeSRGBLinear()). If the format of the + backend texture is linear, then the colorSpace should include + a description of the transfer function as + well (e.g., SkColorSpace::MakeSRGB()). + @return created SkImage, or nullptr + */ + static sk_sp MakeGraphiteFromBackendTexture(skgpu::graphite::Recorder*, + const skgpu::graphite::BackendTexture&, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp colorSpace, + TextureReleaseProc = nullptr, + ReleaseContext = nullptr); + + /** Creates an SkImage from YUV[A] planar textures associated with the recorder. + @param recorder The recorder. + @param yuvaBackendTextures A set of textures containing YUVA data and a description of the + data and transformation to RGBA. + @param imageColorSpace range of colors of the resulting image after conversion to RGB; + may be nullptr + @param TextureReleaseProc called when the backend textures can be released + @param ReleaseContext state passed to TextureReleaseProc + @return created SkImage, or nullptr + */ + static sk_sp MakeGraphiteFromYUVABackendTextures( + skgpu::graphite::Recorder* recorder, + const skgpu::graphite::YUVABackendTextures& yuvaBackendTextures, + sk_sp imageColorSpace, + TextureReleaseProc = nullptr, + ReleaseContext = nullptr); + + struct RequiredImageProperties { + skgpu::Mipmapped fMipmapped; + }; + + /** Creates SkImage from SkYUVAPixmaps. + + The image will remain planar with each plane converted to a texture using the passed + Recorder. + + SkYUVAPixmaps has a SkYUVAInfo which specifies the transformation from YUV to RGB. + The SkColorSpace of the resulting RGB values is specified by imgColorSpace. This will + be the SkColorSpace reported by the image and when drawn the RGB values will be converted + from this space into the destination space (if the destination is tagged). + + This is only supported using the GPU backend and will fail if recorder is nullptr. + + SkYUVAPixmaps does not need to remain valid after this returns. + + @param Recorder The Recorder to use for storing commands + @param pixmaps The planes as pixmaps with supported SkYUVAInfo that + specifies conversion to RGB. + @param RequiredImageProperties Properties the returned SkImage must possess (e.g., + mipmaps) + @param limitToMaxTextureSize Downscale image to GPU maximum texture size, if necessary + @param imgColorSpace Range of colors of the resulting image; may be nullptr + @return Created SkImage, or nullptr + */ + static sk_sp MakeGraphiteFromYUVAPixmaps(skgpu::graphite::Recorder*, + const SkYUVAPixmaps& pixmaps, + RequiredImageProperties = {}, + bool limitToMaxTextureSize = false, + sk_sp imgColorSpace = nullptr); + + /** Graphite version of makeTextureImage. + + Returns an SkImage backed by a Graphite texture, using the provided Recorder for creation + and uploads if necessary. The returned SkImage respects the required image properties' + mipmap setting for non-Graphite SkImages; i.e., if mipmapping is required, the backing + Graphite texture will have allocated mip map levels. + + It is assumed that MIP maps are always supported by the GPU. + + Returns original SkImage if the image is already Graphite-backed and the required mipmapping + is compatible with the backing Graphite texture. If the required mipmapping is not + compatible, nullptr will be returned. + + Returns nullptr if no Recorder is provided, or if SkImage was created with another + Recorder and work on that Recorder has not been submitted. + + @param Recorder the Recorder to use for storing commands + @param RequiredImageProperties properties the returned SkImage must possess (e.g., + mipmaps) + @return created SkImage, or nullptr + */ + virtual sk_sp makeTextureImage(skgpu::graphite::Recorder*, + RequiredImageProperties = {}) const = 0; + + /** Returns subset of this image. + + Returns nullptr if any of the following are true: + - Subset is empty + - Subset is not contained inside the image's bounds + - Pixels in the image could not be read or copied + + If this image is texture-backed, the recorder parameter is required. + If the recorder parameter is provided, and the image is raster-backed, the subset will + be converted to texture-backed. + + @param subset bounds of returned SkImage + @param recorder the recorder in which to create the new image + @param RequiredImageProperties properties the returned SkImage must possess (e.g., + mipmaps) + @return the subsetted image, or nullptr + */ + sk_sp makeSubset(const SkIRect& subset, + skgpu::graphite::Recorder*, + RequiredImageProperties = {}) const; + + /** Creates SkImage in target SkColorSpace. + Returns nullptr if SkImage could not be created. + + Returns original SkImage if it is in target SkColorSpace. + Otherwise, converts pixels from SkImage SkColorSpace to target SkColorSpace. + If SkImage colorSpace() returns nullptr, SkImage SkColorSpace is assumed to be sRGB. + + If this image is graphite-backed, the recorder parameter is required. + + @param targetColorSpace SkColorSpace describing color range of returned SkImage + @param recorder The Recorder in which to create the new image + @param RequiredImageProperties properties the returned SkImage must possess (e.g., + mipmaps) + @return created SkImage in target SkColorSpace + */ + sk_sp makeColorSpace(sk_sp targetColorSpace, + skgpu::graphite::Recorder*, + RequiredImageProperties = {}) const; + + /** Experimental. + Creates SkImage in target SkColorType and SkColorSpace. + Returns nullptr if SkImage could not be created. + + Returns original SkImage if it is in target SkColorType and SkColorSpace. + + If this image is graphite-backed, the recorder parameter is required. + + @param targetColorType SkColorType of returned SkImage + @param targetColorSpace SkColorSpace of returned SkImage + @param recorder The Recorder in which to create the new image + @param RequiredImageProperties properties the returned SkImage must possess (e.g., + mipmaps) + @return created SkImage in target SkColorType and SkColorSpace + */ + sk_sp makeColorTypeAndColorSpace(SkColorType targetColorType, + sk_sp targetColorSpace, + skgpu::graphite::Recorder*, + RequiredImageProperties = {}) const; + +#endif // SK_GRAPHITE + + /** Returns raster image or lazy image. Copies SkImage backed by GPU texture into + CPU memory if needed. Returns original SkImage if decoded in raster bitmap, + or if encoded in a stream. + + Returns nullptr if backed by GPU texture and copy fails. + + @return raster image, lazy image, or nullptr + + example: https://fiddle.skia.org/c/@Image_makeNonTextureImage + */ + sk_sp makeNonTextureImage() const; + + /** Returns raster image. Copies SkImage backed by GPU texture into CPU memory, + or decodes SkImage from lazy image. Returns original SkImage if decoded in + raster bitmap. + + Returns nullptr if copy, decode, or pixel read fails. + + If cachingHint is kAllow_CachingHint, pixels may be retained locally. + If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache. + + @return raster image, or nullptr + + example: https://fiddle.skia.org/c/@Image_makeRasterImage + */ + sk_sp makeRasterImage(CachingHint cachingHint = kDisallow_CachingHint) const; + + /** Creates filtered SkImage. filter processes original SkImage, potentially changing + color, position, and size. subset is the bounds of original SkImage processed + by filter. clipBounds is the expected bounds of the filtered SkImage. outSubset + is required storage for the actual bounds of the filtered SkImage. offset is + required storage for translation of returned SkImage. + + Returns nullptr if SkImage could not be created or if the recording context provided doesn't + match the GPU context in which the image was created. If nullptr is returned, outSubset + and offset are undefined. + + Useful for animation of SkImageFilter that varies size from frame to frame. + Returned SkImage is created larger than required by filter so that GPU texture + can be reused with different sized effects. outSubset describes the valid bounds + of GPU texture returned. offset translates the returned SkImage to keep subsequent + animation frames aligned with respect to each other. + + @param context the GrRecordingContext in play - if it exists + @param filter how SkImage is sampled when transformed + @param subset bounds of SkImage processed by filter + @param clipBounds expected bounds of filtered SkImage + @param outSubset storage for returned SkImage bounds + @param offset storage for returned SkImage translation + @return filtered SkImage, or nullptr + */ + sk_sp makeWithFilter(GrRecordingContext* context, + const SkImageFilter* filter, const SkIRect& subset, + const SkIRect& clipBounds, SkIRect* outSubset, + SkIPoint* offset) const; + + /** Deprecated. + */ + enum LegacyBitmapMode { + kRO_LegacyBitmapMode, //!< returned bitmap is read-only and immutable + }; + + /** Deprecated. + Creates raster SkBitmap with same pixels as SkImage. If legacyBitmapMode is + kRO_LegacyBitmapMode, returned bitmap is read-only and immutable. + Returns true if SkBitmap is stored in bitmap. Returns false and resets bitmap if + SkBitmap write did not succeed. + + @param bitmap storage for legacy SkBitmap + @param legacyBitmapMode bitmap is read-only and immutable + @return true if SkBitmap was created + */ + bool asLegacyBitmap(SkBitmap* bitmap, + LegacyBitmapMode legacyBitmapMode = kRO_LegacyBitmapMode) const; + + /** Returns true if SkImage is backed by an image-generator or other service that creates + and caches its pixels or texture on-demand. + + @return true if SkImage is created as needed + + example: https://fiddle.skia.org/c/@Image_isLazyGenerated_a + example: https://fiddle.skia.org/c/@Image_isLazyGenerated_b + */ + bool isLazyGenerated() const; + + /** Creates SkImage in target SkColorSpace. + Returns nullptr if SkImage could not be created. + + Returns original SkImage if it is in target SkColorSpace. + Otherwise, converts pixels from SkImage SkColorSpace to target SkColorSpace. + If SkImage colorSpace() returns nullptr, SkImage SkColorSpace is assumed to be sRGB. + + If this image is texture-backed, the context parameter is required and must match the + context of the source image. + + @param target SkColorSpace describing color range of returned SkImage + @param direct The GrDirectContext in play, if it exists + @return created SkImage in target SkColorSpace + + example: https://fiddle.skia.org/c/@Image_makeColorSpace + */ + sk_sp makeColorSpace(sk_sp target, + GrDirectContext* direct = nullptr) const; + + /** Experimental. + Creates SkImage in target SkColorType and SkColorSpace. + Returns nullptr if SkImage could not be created. + + Returns original SkImage if it is in target SkColorType and SkColorSpace. + + If this image is texture-backed, the context parameter is required and must match the + context of the source image. + + @param targetColorType SkColorType of returned SkImage + @param targetColorSpace SkColorSpace of returned SkImage + @param direct The GrDirectContext in play, if it exists + @return created SkImage in target SkColorType and SkColorSpace + */ + sk_sp makeColorTypeAndColorSpace(SkColorType targetColorType, + sk_sp targetColorSpace, + GrDirectContext* direct = nullptr) const; + + /** Creates a new SkImage identical to this one, but with a different SkColorSpace. + This does not convert the underlying pixel data, so the resulting image will draw + differently. + */ + sk_sp reinterpretColorSpace(sk_sp newColorSpace) const; + +private: + SkImage(const SkImageInfo& info, uint32_t uniqueID); + + friend class SkBitmap; + friend class SkImage_Base; // for private ctor + friend class SkImage_Raster; // for withMipmaps + friend class SkMipmapBuilder; + + SkImageInfo fInfo; + const uint32_t fUniqueID; + + sk_sp withMipmaps(sk_sp) const; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageFilter.h new file mode 100644 index 00000000000000..e2240916d4054d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageFilter.h @@ -0,0 +1,114 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageFilter_DEFINED +#define SkImageFilter_DEFINED + +#include "include/core/SkFlattenable.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkRect.h" + +class SkColorFilter; + +/** + * Base class for image filters. If one is installed in the paint, then all drawing occurs as + * usual, but it is as if the drawing happened into an offscreen (before the xfermode is applied). + * This offscreen bitmap will then be handed to the imagefilter, who in turn creates a new bitmap + * which is what will finally be drawn to the device (using the original xfermode). + * + * The local space of image filters matches the local space of the drawn geometry. For instance if + * there is rotation on the canvas, the blur will be computed along those rotated axes and not in + * the device space. In order to achieve this result, the actual drawing of the geometry may happen + * in an unrotated coordinate system so that the filtered image can be computed more easily, and + * then it will be post transformed to match what would have been produced if the geometry were + * drawn with the total canvas matrix to begin with. + */ +class SK_API SkImageFilter : public SkFlattenable { +public: + enum MapDirection { + kForward_MapDirection, + kReverse_MapDirection, + }; + /** + * Map a device-space rect recursively forward or backward through the filter DAG. + * kForward_MapDirection is used to determine which pixels of the destination canvas a source + * image rect would touch after filtering. kReverse_MapDirection is used to determine which rect + * of the source image would be required to fill the given rect (typically, clip bounds). Used + * for clipping and temp-buffer allocations, so the result need not be exact, but should never + * be smaller than the real answer. The default implementation recursively unions all input + * bounds, or returns the source rect if no inputs. + * + * In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward + * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting answer + * may be incorrect. + */ + SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect = nullptr) const; + + /** + * Returns whether this image filter is a color filter and puts the color filter into the + * "filterPtr" parameter if it can. Does nothing otherwise. + * If this returns false, then the filterPtr is unchanged. + * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler + * (i.e. it may not be set to NULL). + */ + bool isColorFilterNode(SkColorFilter** filterPtr) const; + + // DEPRECATED : use isColorFilterNode() instead + bool asColorFilter(SkColorFilter** filterPtr) const { + return this->isColorFilterNode(filterPtr); + } + + /** + * Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely + * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the same + * way. + */ + bool asAColorFilter(SkColorFilter** filterPtr) const; + + /** + * Returns the number of inputs this filter will accept (some inputs can be NULL). + */ + int countInputs() const; + + /** + * Returns the input filter at a given index, or NULL if no input is connected. The indices + * used are filter-specific. + */ + const SkImageFilter* getInput(int i) const; + + // Default impl returns union of all input bounds. + virtual SkRect computeFastBounds(const SkRect& bounds) const; + + // Can this filter DAG compute the resulting bounds of an object-space rectangle? + bool canComputeFastBounds() const; + + /** + * If this filter can be represented by another filter + a localMatrix, return that filter, + * else return null. + */ + sk_sp makeWithLocalMatrix(const SkMatrix& matrix) const; + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize(kSkImageFilter_Type, data, size, procs).release())); + } + +protected: + + sk_sp refMe() const { + return sk_ref_sp(const_cast(this)); + } + +private: + friend class SkImageFilter_Base; + + using INHERITED = SkFlattenable; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageGenerator.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageGenerator.h new file mode 100644 index 00000000000000..ba9ae098330663 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageGenerator.h @@ -0,0 +1,171 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageGenerator_DEFINED +#define SkImageGenerator_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkYUVAPixmaps.h" +#include "include/private/base/SkAPI.h" + +#if defined(SK_GRAPHITE) +#include "include/core/SkImage.h" +#include "include/gpu/graphite/Recorder.h" +#endif + +#include +#include +#include +#include + +class GrRecordingContext; +enum SkAlphaType : int; + +class SK_API SkImageGenerator { +public: + /** + * The PixelRef which takes ownership of this SkImageGenerator + * will call the image generator's destructor. + */ + virtual ~SkImageGenerator() { } + + uint32_t uniqueID() const { return fUniqueID; } + + /** + * Return a ref to the encoded (i.e. compressed) representation + * of this data. + * + * If non-NULL is returned, the caller is responsible for calling + * unref() on the data when it is finished. + */ + sk_sp refEncodedData() { + return this->onRefEncodedData(); + } + + /** + * Return the ImageInfo associated with this generator. + */ + const SkImageInfo& getInfo() const { return fInfo; } + + /** + * Can this generator be used to produce images that will be drawable to the specified context + * (or to CPU, if context is nullptr)? + */ + bool isValid(GrRecordingContext* context) const { + return this->onIsValid(context); + } + + /** + * Decode into the given pixels, a block of memory of size at + * least (info.fHeight - 1) * rowBytes + (info.fWidth * + * bytesPerPixel) + * + * Repeated calls to this function should give the same results, + * allowing the PixelRef to be immutable. + * + * @param info A description of the format + * expected by the caller. This can simply be identical + * to the info returned by getInfo(). + * + * This contract also allows the caller to specify + * different output-configs, which the implementation can + * decide to support or not. + * + * A size that does not match getInfo() implies a request + * to scale. If the generator cannot perform this scale, + * it will return false. + * + * @return true on success. + */ + bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes); + + bool getPixels(const SkPixmap& pm) { + return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes()); + } + + /** + * If decoding to YUV is supported, this returns true. Otherwise, this + * returns false and the caller will ignore output parameter yuvaPixmapInfo. + * + * @param supportedDataTypes Indicates the data type/planar config combinations that are + * supported by the caller. If the generator supports decoding to + * YUV(A), but not as a type in supportedDataTypes, this method + * returns false. + * @param yuvaPixmapInfo Output parameter that specifies the planar configuration, subsampling, + * orientation, chroma siting, plane color types, and row bytes. + */ + bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, + SkYUVAPixmapInfo* yuvaPixmapInfo) const; + + /** + * Returns true on success and false on failure. + * This always attempts to perform a full decode. To get the planar + * configuration without decoding use queryYUVAInfo(). + * + * @param yuvaPixmaps Contains preallocated pixmaps configured according to a successful call + * to queryYUVAInfo(). + */ + bool getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps); + + virtual bool isTextureGenerator() const { return false; } + +#if defined(SK_GRAPHITE) + sk_sp makeTextureImage(skgpu::graphite::Recorder*, + const SkImageInfo&, + skgpu::Mipmapped); +#endif + + /** + * If the default image decoder system can interpret the specified (encoded) data, then + * this returns a new ImageGenerator for it. Otherwise this returns NULL. Either way + * the caller is still responsible for managing their ownership of the data. + * By default, images will be converted to premultiplied pixels. The alpha type can be + * overridden by specifying kPremul_SkAlphaType or kUnpremul_SkAlphaType. Specifying + * kOpaque_SkAlphaType is not supported, and will return NULL. + */ + static std::unique_ptr MakeFromEncoded( + sk_sp, std::optional = std::nullopt); + +protected: + static constexpr int kNeedNewImageUniqueID = 0; + + SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID); + + virtual sk_sp onRefEncodedData() { return nullptr; } + struct Options {}; + virtual bool onGetPixels(const SkImageInfo&, void*, size_t, const Options&) { return false; } + virtual bool onIsValid(GrRecordingContext*) const { return true; } + virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const { return false; } + virtual bool onGetYUVAPlanes(const SkYUVAPixmaps&) { return false; } + +#if defined(SK_GRAPHITE) + virtual sk_sp onMakeTextureImage(skgpu::graphite::Recorder*, + const SkImageInfo&, + skgpu::Mipmapped); +#endif + const SkImageInfo fInfo; + +private: + const uint32_t fUniqueID; + + // This is our default impl, which may be different on different platforms. + // It is called from NewFromEncoded() after it has checked for any runtime factory. + // The SkData will never be NULL, as that will have been checked by NewFromEncoded. + static std::unique_ptr MakeFromEncodedImpl(sk_sp, + std::optional); + + SkImageGenerator(SkImageGenerator&&) = delete; + SkImageGenerator(const SkImageGenerator&) = delete; + SkImageGenerator& operator=(SkImageGenerator&&) = delete; + SkImageGenerator& operator=(const SkImageGenerator&) = delete; +}; + +#endif // SkImageGenerator_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageInfo.h new file mode 100644 index 00000000000000..b5661719006ef3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkImageInfo.h @@ -0,0 +1,616 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageInfo_DEFINED +#define SkImageInfo_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkColorType.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMath.h" +#include "include/private/base/SkTFitsIn.h" + +#include +#include +#include + +class SkColorSpace; + +/** Returns the number of bytes required to store a pixel, including unused padding. + Returns zero if ct is kUnknown_SkColorType or invalid. + + @return bytes per pixel +*/ +SK_API int SkColorTypeBytesPerPixel(SkColorType ct); + +/** Returns true if SkColorType always decodes alpha to 1.0, making the pixel + fully opaque. If true, SkColorType does not reserve bits to encode alpha. + + @return true if alpha is always set to 1.0 +*/ +SK_API bool SkColorTypeIsAlwaysOpaque(SkColorType ct); + +/** Returns true if canonical can be set to a valid SkAlphaType for colorType. If + there is more than one valid canonical SkAlphaType, set to alphaType, if valid. + If true is returned and canonical is not nullptr, store valid SkAlphaType. + + Returns false only if alphaType is kUnknown_SkAlphaType, color type is not + kUnknown_SkColorType, and SkColorType is not always opaque. If false is returned, + canonical is ignored. + + @param canonical storage for SkAlphaType + @return true if valid SkAlphaType can be associated with colorType +*/ +SK_API bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, + SkAlphaType* canonical = nullptr); + +/** \enum SkImageInfo::SkYUVColorSpace + Describes color range of YUV pixels. The color mapping from YUV to RGB varies + depending on the source. YUV pixels may be generated by JPEG images, standard + video streams, or high definition video streams. Each has its own mapping from + YUV to RGB. + + JPEG YUV values encode the full range of 0 to 255 for all three components. + Video YUV values often range from 16 to 235 for Y and from 16 to 240 for U and V (limited). + Details of encoding and conversion to RGB are described in YCbCr color space. + + The identity colorspace exists to provide a utility mapping from Y to R, U to G and V to B. + It can be used to visualize the YUV planes or to explicitly post process the YUV channels. +*/ +enum SkYUVColorSpace : int { + kJPEG_Full_SkYUVColorSpace, //!< describes full range + kRec601_Limited_SkYUVColorSpace, //!< describes SDTV range + kRec709_Full_SkYUVColorSpace, //!< describes HDTV range + kRec709_Limited_SkYUVColorSpace, + kBT2020_8bit_Full_SkYUVColorSpace, //!< describes UHDTV range, non-constant-luminance + kBT2020_8bit_Limited_SkYUVColorSpace, + kBT2020_10bit_Full_SkYUVColorSpace, + kBT2020_10bit_Limited_SkYUVColorSpace, + kBT2020_12bit_Full_SkYUVColorSpace, + kBT2020_12bit_Limited_SkYUVColorSpace, + kIdentity_SkYUVColorSpace, //!< maps Y->R, U->G, V->B + + kLastEnum_SkYUVColorSpace = kIdentity_SkYUVColorSpace, //!< last valid value + + // Legacy (deprecated) names: + kJPEG_SkYUVColorSpace = kJPEG_Full_SkYUVColorSpace, + kRec601_SkYUVColorSpace = kRec601_Limited_SkYUVColorSpace, + kRec709_SkYUVColorSpace = kRec709_Limited_SkYUVColorSpace, + kBT2020_SkYUVColorSpace = kBT2020_8bit_Limited_SkYUVColorSpace, +}; + +/** \struct SkColorInfo + Describes pixel and encoding. SkImageInfo can be created from SkColorInfo by + providing dimensions. + + It encodes how pixel bits describe alpha, transparency; color components red, blue, + and green; and SkColorSpace, the range and linearity of colors. +*/ +class SK_API SkColorInfo { +public: + /** Creates an SkColorInfo with kUnknown_SkColorType, kUnknown_SkAlphaType, + and no SkColorSpace. + + @return empty SkImageInfo + */ + SkColorInfo(); + ~SkColorInfo(); + + /** Creates SkColorInfo from SkColorType ct, SkAlphaType at, and optionally SkColorSpace cs. + + If SkColorSpace cs is nullptr and SkColorInfo is part of drawing source: SkColorSpace + defaults to sRGB, mapping into SkSurface SkColorSpace. + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + @return created SkColorInfo + */ + SkColorInfo(SkColorType ct, SkAlphaType at, sk_sp cs); + + SkColorInfo(const SkColorInfo&); + SkColorInfo(SkColorInfo&&); + + SkColorInfo& operator=(const SkColorInfo&); + SkColorInfo& operator=(SkColorInfo&&); + + SkColorSpace* colorSpace() const; + sk_sp refColorSpace() const; + SkColorType colorType() const { return fColorType; } + SkAlphaType alphaType() const { return fAlphaType; } + + bool isOpaque() const { + return SkAlphaTypeIsOpaque(fAlphaType) + || SkColorTypeIsAlwaysOpaque(fColorType); + } + + bool gammaCloseToSRGB() const; + + /** Does other represent the same color type, alpha type, and color space? */ + bool operator==(const SkColorInfo& other) const; + + /** Does other represent a different color type, alpha type, or color space? */ + bool operator!=(const SkColorInfo& other) const; + + /** Creates SkColorInfo with same SkColorType, SkColorSpace, with SkAlphaType set + to newAlphaType. + + Created SkColorInfo contains newAlphaType even if it is incompatible with + SkColorType, in which case SkAlphaType in SkColorInfo is ignored. + */ + SkColorInfo makeAlphaType(SkAlphaType newAlphaType) const; + + /** Creates new SkColorInfo with same SkAlphaType, SkColorSpace, with SkColorType + set to newColorType. + */ + SkColorInfo makeColorType(SkColorType newColorType) const; + + /** Creates SkColorInfo with same SkAlphaType, SkColorType, with SkColorSpace + set to cs. cs may be nullptr. + */ + SkColorInfo makeColorSpace(sk_sp cs) const; + + /** Returns number of bytes per pixel required by SkColorType. + Returns zero if colorType() is kUnknown_SkColorType. + + @return bytes in pixel + + example: https://fiddle.skia.org/c/@ImageInfo_bytesPerPixel + */ + int bytesPerPixel() const; + + /** Returns bit shift converting row bytes to row pixels. + Returns zero for kUnknown_SkColorType. + + @return one of: 0, 1, 2, 3, 4; left shift to convert pixels to bytes + + example: https://fiddle.skia.org/c/@ImageInfo_shiftPerPixel + */ + int shiftPerPixel() const; + +private: + sk_sp fColorSpace; + SkColorType fColorType = kUnknown_SkColorType; + SkAlphaType fAlphaType = kUnknown_SkAlphaType; +}; + +/** \struct SkImageInfo + Describes pixel dimensions and encoding. SkBitmap, SkImage, PixMap, and SkSurface + can be created from SkImageInfo. SkImageInfo can be retrieved from SkBitmap and + SkPixmap, but not from SkImage and SkSurface. For example, SkImage and SkSurface + implementations may defer pixel depth, so may not completely specify SkImageInfo. + + SkImageInfo contains dimensions, the pixel integral width and height. It encodes + how pixel bits describe alpha, transparency; color components red, blue, + and green; and SkColorSpace, the range and linearity of colors. +*/ +struct SK_API SkImageInfo { +public: + + /** Creates an empty SkImageInfo with kUnknown_SkColorType, kUnknown_SkAlphaType, + a width and height of zero, and no SkColorSpace. + + @return empty SkImageInfo + */ + SkImageInfo() = default; + + /** Creates SkImageInfo from integral dimensions width and height, SkColorType ct, + SkAlphaType at, and optionally SkColorSpace cs. + + If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace + defaults to sRGB, mapping into SkSurface SkColorSpace. + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param cs range of colors; may be nullptr + @return created SkImageInfo + */ + static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at); + static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at, + sk_sp cs); + static SkImageInfo Make(SkISize dimensions, SkColorType ct, SkAlphaType at); + static SkImageInfo Make(SkISize dimensions, SkColorType ct, SkAlphaType at, + sk_sp cs); + + /** Creates SkImageInfo from integral dimensions and SkColorInfo colorInfo, + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + + @param dimensions pixel column and row count; must be zeros or greater + @param SkColorInfo the pixel encoding consisting of SkColorType, SkAlphaType, and + SkColorSpace (which may be nullptr) + @return created SkImageInfo + */ + static SkImageInfo Make(SkISize dimensions, const SkColorInfo& colorInfo) { + return SkImageInfo(dimensions, colorInfo); + } + static SkImageInfo Make(SkISize dimensions, SkColorInfo&& colorInfo) { + return SkImageInfo(dimensions, std::move(colorInfo)); + } + + /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType, + SkAlphaType at, and optionally SkColorSpace cs. kN32_SkColorType will equal either + kBGRA_8888_SkColorType or kRGBA_8888_SkColorType, whichever is optimal. + + If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace + defaults to sRGB, mapping into SkSurface SkColorSpace. + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param cs range of colors; may be nullptr + @return created SkImageInfo + */ + static SkImageInfo MakeN32(int width, int height, SkAlphaType at); + static SkImageInfo MakeN32(int width, int height, SkAlphaType at, sk_sp cs); + + /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType, + SkAlphaType at, with sRGB SkColorSpace. + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @return created SkImageInfo + + example: https://fiddle.skia.org/c/@ImageInfo_MakeS32 + */ + static SkImageInfo MakeS32(int width, int height, SkAlphaType at); + + /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType, + kPremul_SkAlphaType, with optional SkColorSpace. + + If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace + defaults to sRGB, mapping into SkSurface SkColorSpace. + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param cs range of colors; may be nullptr + @return created SkImageInfo + */ + static SkImageInfo MakeN32Premul(int width, int height); + static SkImageInfo MakeN32Premul(int width, int height, sk_sp cs); + + /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType, + kPremul_SkAlphaType, with SkColorSpace set to nullptr. + + If SkImageInfo is part of drawing source: SkColorSpace defaults to sRGB, mapping + into SkSurface SkColorSpace. + + Parameters are not validated to see if their values are legal, or that the + combination is supported. + + @param dimensions width and height, each must be zero or greater + @param cs range of colors; may be nullptr + @return created SkImageInfo + */ + static SkImageInfo MakeN32Premul(SkISize dimensions); + static SkImageInfo MakeN32Premul(SkISize dimensions, sk_sp cs); + + /** Creates SkImageInfo from integral dimensions width and height, kAlpha_8_SkColorType, + kPremul_SkAlphaType, with SkColorSpace set to nullptr. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @return created SkImageInfo + */ + static SkImageInfo MakeA8(int width, int height); + /** Creates SkImageInfo from integral dimensions, kAlpha_8_SkColorType, + kPremul_SkAlphaType, with SkColorSpace set to nullptr. + + @param dimensions pixel row and column count; must be zero or greater + @return created SkImageInfo + */ + static SkImageInfo MakeA8(SkISize dimensions); + + /** Creates SkImageInfo from integral dimensions width and height, kUnknown_SkColorType, + kUnknown_SkAlphaType, with SkColorSpace set to nullptr. + + Returned SkImageInfo as part of source does not draw, and as part of destination + can not be drawn to. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @return created SkImageInfo + */ + static SkImageInfo MakeUnknown(int width, int height); + + /** Creates SkImageInfo from integral dimensions width and height set to zero, + kUnknown_SkColorType, kUnknown_SkAlphaType, with SkColorSpace set to nullptr. + + Returned SkImageInfo as part of source does not draw, and as part of destination + can not be drawn to. + + @return created SkImageInfo + */ + static SkImageInfo MakeUnknown() { + return MakeUnknown(0, 0); + } + + /** Returns pixel count in each row. + + @return pixel width + */ + int width() const { return fDimensions.width(); } + + /** Returns pixel row count. + + @return pixel height + */ + int height() const { return fDimensions.height(); } + + SkColorType colorType() const { return fColorInfo.colorType(); } + + SkAlphaType alphaType() const { return fColorInfo.alphaType(); } + + /** Returns SkColorSpace, the range of colors. The reference count of + SkColorSpace is unchanged. The returned SkColorSpace is immutable. + + @return SkColorSpace, or nullptr + */ + SkColorSpace* colorSpace() const; + + /** Returns smart pointer to SkColorSpace, the range of colors. The smart pointer + tracks the number of objects sharing this SkColorSpace reference so the memory + is released when the owners destruct. + + The returned SkColorSpace is immutable. + + @return SkColorSpace wrapped in a smart pointer + */ + sk_sp refColorSpace() const; + + /** Returns if SkImageInfo describes an empty area of pixels by checking if either + width or height is zero or smaller. + + @return true if either dimension is zero or smaller + */ + bool isEmpty() const { return fDimensions.isEmpty(); } + + /** Returns the dimensionless SkColorInfo that represents the same color type, + alpha type, and color space as this SkImageInfo. + */ + const SkColorInfo& colorInfo() const { return fColorInfo; } + + /** Returns true if SkAlphaType is set to hint that all pixels are opaque; their + alpha value is implicitly or explicitly 1.0. If true, and all pixels are + not opaque, Skia may draw incorrectly. + + Does not check if SkColorType allows alpha, or if any pixel value has + transparency. + + @return true if SkAlphaType is kOpaque_SkAlphaType + */ + bool isOpaque() const { return fColorInfo.isOpaque(); } + + /** Returns SkISize { width(), height() }. + + @return integral size of width() and height() + */ + SkISize dimensions() const { return fDimensions; } + + /** Returns SkIRect { 0, 0, width(), height() }. + + @return integral rectangle from origin to width() and height() + */ + SkIRect bounds() const { return SkIRect::MakeSize(fDimensions); } + + /** Returns true if associated SkColorSpace is not nullptr, and SkColorSpace gamma + is approximately the same as sRGB. + This includes the + + @return true if SkColorSpace gamma is approximately the same as sRGB + */ + bool gammaCloseToSRGB() const { return fColorInfo.gammaCloseToSRGB(); } + + /** Creates SkImageInfo with the same SkColorType, SkColorSpace, and SkAlphaType, + with dimensions set to width and height. + + @param newWidth pixel column count; must be zero or greater + @param newHeight pixel row count; must be zero or greater + @return created SkImageInfo + */ + SkImageInfo makeWH(int newWidth, int newHeight) const { + return Make({newWidth, newHeight}, fColorInfo); + } + + /** Creates SkImageInfo with the same SkColorType, SkColorSpace, and SkAlphaType, + with dimensions set to newDimensions. + + @param newSize pixel column and row count; must be zero or greater + @return created SkImageInfo + */ + SkImageInfo makeDimensions(SkISize newSize) const { + return Make(newSize, fColorInfo); + } + + /** Creates SkImageInfo with same SkColorType, SkColorSpace, width, and height, + with SkAlphaType set to newAlphaType. + + Created SkImageInfo contains newAlphaType even if it is incompatible with + SkColorType, in which case SkAlphaType in SkImageInfo is ignored. + + @return created SkImageInfo + */ + SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const { + return Make(fDimensions, fColorInfo.makeAlphaType(newAlphaType)); + } + + /** Creates SkImageInfo with same SkAlphaType, SkColorSpace, width, and height, + with SkColorType set to newColorType. + + @return created SkImageInfo + */ + SkImageInfo makeColorType(SkColorType newColorType) const { + return Make(fDimensions, fColorInfo.makeColorType(newColorType)); + } + + /** Creates SkImageInfo with same SkAlphaType, SkColorType, width, and height, + with SkColorSpace set to cs. + + @param cs range of colors; may be nullptr + @return created SkImageInfo + */ + SkImageInfo makeColorSpace(sk_sp cs) const; + + /** Returns number of bytes per pixel required by SkColorType. + Returns zero if colorType( is kUnknown_SkColorType. + + @return bytes in pixel + */ + int bytesPerPixel() const { return fColorInfo.bytesPerPixel(); } + + /** Returns bit shift converting row bytes to row pixels. + Returns zero for kUnknown_SkColorType. + + @return one of: 0, 1, 2, 3; left shift to convert pixels to bytes + */ + int shiftPerPixel() const { return fColorInfo.shiftPerPixel(); } + + /** Returns minimum bytes per row, computed from pixel width() and SkColorType, which + specifies bytesPerPixel(). SkBitmap maximum value for row bytes must fit + in 31 bits. + + @return width() times bytesPerPixel() as unsigned 64-bit integer + */ + uint64_t minRowBytes64() const { + return (uint64_t)sk_64_mul(this->width(), this->bytesPerPixel()); + } + + /** Returns minimum bytes per row, computed from pixel width() and SkColorType, which + specifies bytesPerPixel(). SkBitmap maximum value for row bytes must fit + in 31 bits. + + @return width() times bytesPerPixel() as size_t + */ + size_t minRowBytes() const { + uint64_t minRowBytes = this->minRowBytes64(); + if (!SkTFitsIn(minRowBytes)) { + return 0; + } + return (size_t)minRowBytes; + } + + /** Returns byte offset of pixel from pixel base address. + + Asserts in debug build if x or y is outside of bounds. Does not assert if + rowBytes is smaller than minRowBytes(), even though result may be incorrect. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @param rowBytes size of pixel row or larger + @return offset within pixel array + + example: https://fiddle.skia.org/c/@ImageInfo_computeOffset + */ + size_t computeOffset(int x, int y, size_t rowBytes) const; + + /** Compares SkImageInfo with other, and returns true if width, height, SkColorType, + SkAlphaType, and SkColorSpace are equivalent. + + @param other SkImageInfo to compare + @return true if SkImageInfo equals other + */ + bool operator==(const SkImageInfo& other) const { + return fDimensions == other.fDimensions && fColorInfo == other.fColorInfo; + } + + /** Compares SkImageInfo with other, and returns true if width, height, SkColorType, + SkAlphaType, and SkColorSpace are not equivalent. + + @param other SkImageInfo to compare + @return true if SkImageInfo is not equal to other + */ + bool operator!=(const SkImageInfo& other) const { + return !(*this == other); + } + + /** Returns storage required by pixel array, given SkImageInfo dimensions, SkColorType, + and rowBytes. rowBytes is assumed to be at least as large as minRowBytes(). + + Returns zero if height is zero. + Returns SIZE_MAX if answer exceeds the range of size_t. + + @param rowBytes size of pixel row or larger + @return memory required by pixel buffer + + example: https://fiddle.skia.org/c/@ImageInfo_computeByteSize + */ + size_t computeByteSize(size_t rowBytes) const; + + /** Returns storage required by pixel array, given SkImageInfo dimensions, and + SkColorType. Uses minRowBytes() to compute bytes for pixel row. + + Returns zero if height is zero. + Returns SIZE_MAX if answer exceeds the range of size_t. + + @return least memory required by pixel buffer + */ + size_t computeMinByteSize() const { + return this->computeByteSize(this->minRowBytes()); + } + + /** Returns true if byteSize equals SIZE_MAX. computeByteSize() and + computeMinByteSize() return SIZE_MAX if size_t can not hold buffer size. + + @param byteSize result of computeByteSize() or computeMinByteSize() + @return true if computeByteSize() or computeMinByteSize() result exceeds size_t + */ + static bool ByteSizeOverflowed(size_t byteSize) { + return SIZE_MAX == byteSize; + } + + /** Returns true if rowBytes is valid for this SkImageInfo. + + @param rowBytes size of pixel row including padding + @return true if rowBytes is large enough to contain pixel row and is properly + aligned + */ + bool validRowBytes(size_t rowBytes) const { + if (rowBytes < this->minRowBytes64()) { + return false; + } + int shift = this->shiftPerPixel(); + size_t alignedRowBytes = rowBytes >> shift << shift; + return alignedRowBytes == rowBytes; + } + + /** Creates an empty SkImageInfo with kUnknown_SkColorType, kUnknown_SkAlphaType, + a width and height of zero, and no SkColorSpace. + */ + void reset() { *this = {}; } + + /** Asserts if internal values are illegal or inconsistent. Only available if + SK_DEBUG is defined at compile time. + */ + SkDEBUGCODE(void validate() const;) + +private: + SkColorInfo fColorInfo; + SkISize fDimensions = {0, 0}; + + SkImageInfo(SkISize dimensions, const SkColorInfo& colorInfo) + : fColorInfo(colorInfo), fDimensions(dimensions) {} + + SkImageInfo(SkISize dimensions, SkColorInfo&& colorInfo) + : fColorInfo(std::move(colorInfo)), fDimensions(dimensions) {} +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkM44.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkM44.h new file mode 100644 index 00000000000000..11a06a15b1a6d4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkM44.h @@ -0,0 +1,438 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkM44_DEFINED +#define SkM44_DEFINED + +#include "include/core/SkMatrix.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" + +struct SK_API SkV2 { + float x, y; + + bool operator==(const SkV2 v) const { return x == v.x && y == v.y; } + bool operator!=(const SkV2 v) const { return !(*this == v); } + + static SkScalar Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; } + static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; } + static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); } + + SkV2 operator-() const { return {-x, -y}; } + SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; } + SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; } + + SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; } + friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; } + friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; } + friend SkV2 operator/(SkV2 v, SkScalar s) { return {v.x/s, v.y/s}; } + friend SkV2 operator/(SkScalar s, SkV2 v) { return {s/v.x, s/v.y}; } + + void operator+=(SkV2 v) { *this = *this + v; } + void operator-=(SkV2 v) { *this = *this - v; } + void operator*=(SkV2 v) { *this = *this * v; } + void operator*=(SkScalar s) { *this = *this * s; } + void operator/=(SkScalar s) { *this = *this / s; } + + SkScalar lengthSquared() const { return Dot(*this, *this); } + SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); } + + SkScalar dot(SkV2 v) const { return Dot(*this, v); } + SkScalar cross(SkV2 v) const { return Cross(*this, v); } + SkV2 normalize() const { return Normalize(*this); } + + const float* ptr() const { return &x; } + float* ptr() { return &x; } +}; + +struct SK_API SkV3 { + float x, y, z; + + bool operator==(const SkV3& v) const { + return x == v.x && y == v.y && z == v.z; + } + bool operator!=(const SkV3& v) const { return !(*this == v); } + + static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; } + static SkV3 Cross(const SkV3& a, const SkV3& b) { + return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x }; + } + static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); } + + SkV3 operator-() const { return {-x, -y, -z}; } + SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; } + SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; } + + SkV3 operator*(const SkV3& v) const { + return { x*v.x, y*v.y, z*v.z }; + } + friend SkV3 operator*(const SkV3& v, SkScalar s) { + return { v.x*s, v.y*s, v.z*s }; + } + friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; } + + void operator+=(SkV3 v) { *this = *this + v; } + void operator-=(SkV3 v) { *this = *this - v; } + void operator*=(SkV3 v) { *this = *this * v; } + void operator*=(SkScalar s) { *this = *this * s; } + + SkScalar lengthSquared() const { return Dot(*this, *this); } + SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); } + + SkScalar dot(const SkV3& v) const { return Dot(*this, v); } + SkV3 cross(const SkV3& v) const { return Cross(*this, v); } + SkV3 normalize() const { return Normalize(*this); } + + const float* ptr() const { return &x; } + float* ptr() { return &x; } +}; + +struct SK_API SkV4 { + float x, y, z, w; + + bool operator==(const SkV4& v) const { + return x == v.x && y == v.y && z == v.z && w == v.w; + } + bool operator!=(const SkV4& v) const { return !(*this == v); } + + static SkScalar Dot(const SkV4& a, const SkV4& b) { + return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; + } + static SkV4 Normalize(const SkV4& v) { return v * (1.0f / v.length()); } + + SkV4 operator-() const { return {-x, -y, -z, -w}; } + SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; } + SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; } + + SkV4 operator*(const SkV4& v) const { + return { x*v.x, y*v.y, z*v.z, w*v.w }; + } + friend SkV4 operator*(const SkV4& v, SkScalar s) { + return { v.x*s, v.y*s, v.z*s, v.w*s }; + } + friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; } + + SkScalar lengthSquared() const { return Dot(*this, *this); } + SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); } + + SkScalar dot(const SkV4& v) const { return Dot(*this, v); } + SkV4 normalize() const { return Normalize(*this); } + + const float* ptr() const { return &x; } + float* ptr() { return &x; } + + float operator[](int i) const { + SkASSERT(i >= 0 && i < 4); + return this->ptr()[i]; + } + float& operator[](int i) { + SkASSERT(i >= 0 && i < 4); + return this->ptr()[i]; + } +}; + +/** + * 4x4 matrix used by SkCanvas and other parts of Skia. + * + * Skia assumes a right-handed coordinate system: + * +X goes to the right + * +Y goes down + * +Z goes into the screen (away from the viewer) + */ +class SK_API SkM44 { +public: + SkM44(const SkM44& src) = default; + SkM44& operator=(const SkM44& src) = default; + + constexpr SkM44() + : fMat{1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1} + {} + + SkM44(const SkM44& a, const SkM44& b) { + this->setConcat(a, b); + } + + enum Uninitialized_Constructor { + kUninitialized_Constructor + }; + SkM44(Uninitialized_Constructor) {} + + enum NaN_Constructor { + kNaN_Constructor + }; + constexpr SkM44(NaN_Constructor) + : fMat{SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, + SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, + SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, + SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN} + {} + + /** + * The constructor parameters are in row-major order. + */ + constexpr SkM44(SkScalar m0, SkScalar m4, SkScalar m8, SkScalar m12, + SkScalar m1, SkScalar m5, SkScalar m9, SkScalar m13, + SkScalar m2, SkScalar m6, SkScalar m10, SkScalar m14, + SkScalar m3, SkScalar m7, SkScalar m11, SkScalar m15) + // fMat is column-major order in memory. + : fMat{m0, m1, m2, m3, + m4, m5, m6, m7, + m8, m9, m10, m11, + m12, m13, m14, m15} + {} + + static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) { + SkM44 m(kUninitialized_Constructor); + m.setRow(0, r0); + m.setRow(1, r1); + m.setRow(2, r2); + m.setRow(3, r3); + return m; + } + static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) { + SkM44 m(kUninitialized_Constructor); + m.setCol(0, c0); + m.setCol(1, c1); + m.setCol(2, c2); + m.setCol(3, c3); + return m; + } + + static SkM44 RowMajor(const SkScalar r[16]) { + return SkM44(r[ 0], r[ 1], r[ 2], r[ 3], + r[ 4], r[ 5], r[ 6], r[ 7], + r[ 8], r[ 9], r[10], r[11], + r[12], r[13], r[14], r[15]); + } + static SkM44 ColMajor(const SkScalar c[16]) { + return SkM44(c[0], c[4], c[ 8], c[12], + c[1], c[5], c[ 9], c[13], + c[2], c[6], c[10], c[14], + c[3], c[7], c[11], c[15]); + } + + static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) { + return SkM44(1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1); + } + + static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) { + return SkM44(x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1); + } + + static SkM44 Rotate(SkV3 axis, SkScalar radians) { + SkM44 m(kUninitialized_Constructor); + m.setRotate(axis, radians); + return m; + } + + // Scales and translates 'src' to fill 'dst' exactly. + static SkM44 RectToRect(const SkRect& src, const SkRect& dst); + + static SkM44 LookAt(const SkV3& eye, const SkV3& center, const SkV3& up); + static SkM44 Perspective(float near, float far, float angle); + + bool operator==(const SkM44& other) const; + bool operator!=(const SkM44& other) const { + return !(other == *this); + } + + void getColMajor(SkScalar v[]) const { + memcpy(v, fMat, sizeof(fMat)); + } + void getRowMajor(SkScalar v[]) const; + + SkScalar rc(int r, int c) const { + SkASSERT(r >= 0 && r <= 3); + SkASSERT(c >= 0 && c <= 3); + return fMat[c*4 + r]; + } + void setRC(int r, int c, SkScalar value) { + SkASSERT(r >= 0 && r <= 3); + SkASSERT(c >= 0 && c <= 3); + fMat[c*4 + r] = value; + } + + SkV4 row(int i) const { + SkASSERT(i >= 0 && i <= 3); + return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]}; + } + SkV4 col(int i) const { + SkASSERT(i >= 0 && i <= 3); + return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]}; + } + + void setRow(int i, const SkV4& v) { + SkASSERT(i >= 0 && i <= 3); + fMat[i + 0] = v.x; + fMat[i + 4] = v.y; + fMat[i + 8] = v.z; + fMat[i + 12] = v.w; + } + void setCol(int i, const SkV4& v) { + SkASSERT(i >= 0 && i <= 3); + memcpy(&fMat[i*4], v.ptr(), sizeof(v)); + } + + SkM44& setIdentity() { + *this = { 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 }; + return *this; + } + + SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) { + *this = { 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 }; + return *this; + } + + SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) { + *this = { x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 }; + return *this; + } + + /** + * Set this matrix to rotate about the specified unit-length axis vector, + * by an angle specified by its sin() and cos(). + * + * This does not attempt to verify that axis.length() == 1 or that the sin,cos values + * are correct. + */ + SkM44& setRotateUnitSinCos(SkV3 axis, SkScalar sinAngle, SkScalar cosAngle); + + /** + * Set this matrix to rotate about the specified unit-length axis vector, + * by an angle specified in radians. + * + * This does not attempt to verify that axis.length() == 1. + */ + SkM44& setRotateUnit(SkV3 axis, SkScalar radians) { + return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians)); + } + + /** + * Set this matrix to rotate about the specified axis vector, + * by an angle specified in radians. + * + * Note: axis is not assumed to be unit-length, so it will be normalized internally. + * If axis is already unit-length, call setRotateAboutUnitRadians() instead. + */ + SkM44& setRotate(SkV3 axis, SkScalar radians); + + SkM44& setConcat(const SkM44& a, const SkM44& b); + + friend SkM44 operator*(const SkM44& a, const SkM44& b) { + return SkM44(a, b); + } + + SkM44& preConcat(const SkM44& m) { + return this->setConcat(*this, m); + } + + SkM44& postConcat(const SkM44& m) { + return this->setConcat(m, *this); + } + + /** + * A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 0, 1]. + * For most uses, a bottom row of [0, 0, 0, X] behaves like a non-perspective matrix, though + * it will be categorized as perspective. Calling normalizePerspective() will change the + * matrix such that, if its bottom row was [0, 0, 0, X], it will be changed to [0, 0, 0, 1] + * by scaling the rest of the matrix by 1/X. + * + * | A B C D | | A/X B/X C/X D/X | + * | E F G H | -> | E/X F/X G/X H/X | for X != 0 + * | I J K L | | I/X J/X K/X L/X | + * | 0 0 0 X | | 0 0 0 1 | + */ + void normalizePerspective(); + + /** Returns true if all elements of the matrix are finite. Returns false if any + element is infinity, or NaN. + + @return true if matrix has only finite elements + */ + bool isFinite() const { return SkScalarsAreFinite(fMat, 16); } + + /** If this is invertible, return that in inverse and return true. If it is + * not invertible, return false and leave the inverse parameter unchanged. + */ + bool SK_WARN_UNUSED_RESULT invert(SkM44* inverse) const; + + SkM44 SK_WARN_UNUSED_RESULT transpose() const; + + void dump() const; + + //////////// + + SkV4 map(float x, float y, float z, float w) const; + SkV4 operator*(const SkV4& v) const { + return this->map(v.x, v.y, v.z, v.w); + } + SkV3 operator*(SkV3 v) const { + auto v4 = this->map(v.x, v.y, v.z, 0); + return {v4.x, v4.y, v4.z}; + } + ////////////////////// Converting to/from SkMatrix + + /* When converting from SkM44 to SkMatrix, the third row and + * column is dropped. When converting from SkMatrix to SkM44 + * the third row and column remain as identity: + * [ a b c ] [ a b 0 c ] + * [ d e f ] -> [ d e 0 f ] + * [ g h i ] [ 0 0 1 0 ] + * [ g h 0 i ] + */ + SkMatrix asM33() const { + return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12], + fMat[1], fMat[5], fMat[13], + fMat[3], fMat[7], fMat[15]); + } + + explicit SkM44(const SkMatrix& src) + : SkM44(src[SkMatrix::kMScaleX], src[SkMatrix::kMSkewX], 0, src[SkMatrix::kMTransX], + src[SkMatrix::kMSkewY], src[SkMatrix::kMScaleY], 0, src[SkMatrix::kMTransY], + 0, 0, 1, 0, + src[SkMatrix::kMPersp0], src[SkMatrix::kMPersp1], 0, src[SkMatrix::kMPersp2]) + {} + + SkM44& preTranslate(SkScalar x, SkScalar y, SkScalar z = 0); + SkM44& postTranslate(SkScalar x, SkScalar y, SkScalar z = 0); + + SkM44& preScale(SkScalar x, SkScalar y); + SkM44& preScale(SkScalar x, SkScalar y, SkScalar z); + SkM44& preConcat(const SkMatrix&); + +private: + /* Stored in column-major. + * Indices + * 0 4 8 12 1 0 0 trans_x + * 1 5 9 13 e.g. 0 1 0 trans_y + * 2 6 10 14 0 0 1 trans_z + * 3 7 11 15 0 0 0 1 + */ + SkScalar fMat[16]; + + friend class SkMatrixPriv; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMallocPixelRef.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMallocPixelRef.h new file mode 100644 index 00000000000000..cce54b50f47478 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMallocPixelRef.h @@ -0,0 +1,42 @@ +/* + * Copyright 2008 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 SkMallocPixelRef_DEFINED +#define SkMallocPixelRef_DEFINED + +#include "include/core/SkPixelRef.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +class SkData; +struct SkImageInfo; + +/** We explicitly use the same allocator for our pixels that SkMask does, + so that we can freely assign memory allocated by one class to the other. +*/ +namespace SkMallocPixelRef { + /** + * Return a new SkMallocPixelRef, automatically allocating storage for the + * pixels. If rowBytes are 0, an optimal value will be chosen automatically. + * If rowBytes is > 0, then it will be respected, or NULL will be returned + * if rowBytes is invalid for the specified info. + * + * All pixel bytes are zeroed. + * + * Returns NULL on failure. + */ + SK_API sk_sp MakeAllocate(const SkImageInfo&, size_t rowBytes); + + /** + * Return a new SkMallocPixelRef that will use the provided SkData and + * rowBytes as pixel storage. The SkData will be ref()ed and on + * destruction of the PixelRef, the SkData will be unref()ed. + * + * Returns NULL on failure. + */ + SK_API sk_sp MakeWithData(const SkImageInfo&, size_t rowBytes, sk_sp data); +} // namespace SkMallocPixelRef +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMaskFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMaskFilter.h new file mode 100644 index 00000000000000..9d03e98c0c5f81 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMaskFilter.h @@ -0,0 +1,53 @@ +/* + * 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 SkMaskFilter_DEFINED +#define SkMaskFilter_DEFINED + +#include "include/core/SkFlattenable.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include + +enum SkBlurStyle : int; +struct SkDeserialProcs; +struct SkRect; + +/** \class SkMaskFilter + + SkMaskFilter is the base class for object that perform transformations on + the mask before drawing it. An example subclass is Blur. +*/ +class SK_API SkMaskFilter : public SkFlattenable { +public: + /** Create a blur maskfilter. + * @param style The SkBlurStyle to use + * @param sigma Standard deviation of the Gaussian blur to apply. Must be > 0. + * @param respectCTM if true the blur's sigma is modified by the CTM. + * @return The new blur maskfilter + */ + static sk_sp MakeBlur(SkBlurStyle style, SkScalar sigma, + bool respectCTM = true); + + /** + * Returns the approximate bounds that would result from filtering the src rect. + * The actual result may be different, but it should be contained within the + * returned bounds. + */ + SkRect approximateFilteredBounds(const SkRect& src) const; + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr); + +private: + static void RegisterFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMatrix.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMatrix.h new file mode 100644 index 00000000000000..cf84d26228b60c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMatrix.h @@ -0,0 +1,1996 @@ +/* + * 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 SkMatrix_DEFINED +#define SkMatrix_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkMacros.h" +#include "include/private/base/SkTo.h" + +#include +#include + +struct SkPoint3; +struct SkRSXform; +struct SkSize; + +// Remove when clients are updated to live without this +#define SK_SUPPORT_LEGACY_MATRIX_RECTTORECT + +/** + * When we transform points through a matrix containing perspective (the bottom row is something + * other than 0,0,1), the bruteforce math can produce confusing results (since we might divide + * by 0, or a negative w value). By default, methods that map rects and paths will apply + * perspective clipping, but this can be changed by specifying kYes to those methods. + */ +enum class SkApplyPerspectiveClip { + kNo, //!< Don't pre-clip the geometry before applying the (perspective) matrix + kYes, //!< Do pre-clip the geometry before applying the (perspective) matrix +}; + +/** \class SkMatrix + SkMatrix holds a 3x3 matrix for transforming coordinates. This allows mapping + SkPoint and vectors with translation, scaling, skewing, rotation, and + perspective. + + SkMatrix elements are in row major order. + SkMatrix constexpr default constructs to identity. + + SkMatrix includes a hidden variable that classifies the type of matrix to + improve performance. SkMatrix is not thread safe unless getType() is called first. + + example: https://fiddle.skia.org/c/@Matrix_063 +*/ +SK_BEGIN_REQUIRE_DENSE +class SK_API SkMatrix { +public: + + /** Creates an identity SkMatrix: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + */ + constexpr SkMatrix() : SkMatrix(1,0,0, 0,1,0, 0,0,1, kIdentity_Mask | kRectStaysRect_Mask) {} + + /** Sets SkMatrix to scale by (sx, sy). Returned matrix is: + + | sx 0 0 | + | 0 sy 0 | + | 0 0 1 | + + @param sx horizontal scale factor + @param sy vertical scale factor + @return SkMatrix with scale + */ + static SkMatrix SK_WARN_UNUSED_RESULT Scale(SkScalar sx, SkScalar sy) { + SkMatrix m; + m.setScale(sx, sy); + return m; + } + + /** Sets SkMatrix to translate by (dx, dy). Returned matrix is: + + | 1 0 dx | + | 0 1 dy | + | 0 0 1 | + + @param dx horizontal translation + @param dy vertical translation + @return SkMatrix with translation + */ + static SkMatrix SK_WARN_UNUSED_RESULT Translate(SkScalar dx, SkScalar dy) { + SkMatrix m; + m.setTranslate(dx, dy); + return m; + } + static SkMatrix SK_WARN_UNUSED_RESULT Translate(SkVector t) { return Translate(t.x(), t.y()); } + static SkMatrix SK_WARN_UNUSED_RESULT Translate(SkIVector t) { return Translate(t.x(), t.y()); } + + /** Sets SkMatrix to rotate by |deg| about a pivot point at (0, 0). + + @param deg rotation angle in degrees (positive rotates clockwise) + @return SkMatrix with rotation + */ + static SkMatrix SK_WARN_UNUSED_RESULT RotateDeg(SkScalar deg) { + SkMatrix m; + m.setRotate(deg); + return m; + } + static SkMatrix SK_WARN_UNUSED_RESULT RotateDeg(SkScalar deg, SkPoint pt) { + SkMatrix m; + m.setRotate(deg, pt.x(), pt.y()); + return m; + } + static SkMatrix SK_WARN_UNUSED_RESULT RotateRad(SkScalar rad) { + return RotateDeg(SkRadiansToDegrees(rad)); + } + + /** Sets SkMatrix to skew by (kx, ky) about pivot point (0, 0). + + @param kx horizontal skew factor + @param ky vertical skew factor + @return SkMatrix with skew + */ + static SkMatrix SK_WARN_UNUSED_RESULT Skew(SkScalar kx, SkScalar ky) { + SkMatrix m; + m.setSkew(kx, ky); + return m; + } + + /** \enum SkMatrix::ScaleToFit + ScaleToFit describes how SkMatrix is constructed to map one SkRect to another. + ScaleToFit may allow SkMatrix to have unequal horizontal and vertical scaling, + or may restrict SkMatrix to square scaling. If restricted, ScaleToFit specifies + how SkMatrix maps to the side or center of the destination SkRect. + */ + enum ScaleToFit { + kFill_ScaleToFit, //!< scales in x and y to fill destination SkRect + kStart_ScaleToFit, //!< scales and aligns to left and top + kCenter_ScaleToFit, //!< scales and aligns to center + kEnd_ScaleToFit, //!< scales and aligns to right and bottom + }; + + /** Returns SkMatrix set to scale and translate src to dst. ScaleToFit selects + whether mapping completely fills dst or preserves the aspect ratio, and how to + align src within dst. Returns the identity SkMatrix if src is empty. If dst is + empty, returns SkMatrix set to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @param mode How to handle the mapping + @return SkMatrix mapping src to dst + */ + static SkMatrix SK_WARN_UNUSED_RESULT RectToRect(const SkRect& src, const SkRect& dst, + ScaleToFit mode = kFill_ScaleToFit) { + return MakeRectToRect(src, dst, mode); + } + + /** Sets SkMatrix to: + + | scaleX skewX transX | + | skewY scaleY transY | + | pers0 pers1 pers2 | + + @param scaleX horizontal scale factor + @param skewX horizontal skew factor + @param transX horizontal translation + @param skewY vertical skew factor + @param scaleY vertical scale factor + @param transY vertical translation + @param pers0 input x-axis perspective factor + @param pers1 input y-axis perspective factor + @param pers2 perspective scale factor + @return SkMatrix constructed from parameters + */ + static SkMatrix SK_WARN_UNUSED_RESULT MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, + SkScalar skewY, SkScalar scaleY, SkScalar transY, + SkScalar pers0, SkScalar pers1, SkScalar pers2) { + SkMatrix m; + m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2); + return m; + } + + /** \enum SkMatrix::TypeMask + Enum of bit fields for mask returned by getType(). + Used to identify the complexity of SkMatrix, to optimize performance. + */ + enum TypeMask { + kIdentity_Mask = 0, //!< identity SkMatrix; all bits clear + kTranslate_Mask = 0x01, //!< translation SkMatrix + kScale_Mask = 0x02, //!< scale SkMatrix + kAffine_Mask = 0x04, //!< skew or rotate SkMatrix + kPerspective_Mask = 0x08, //!< perspective SkMatrix + }; + + /** Returns a bit field describing the transformations the matrix may + perform. The bit field is computed conservatively, so it may include + false positives. For example, when kPerspective_Mask is set, all + other bits are set. + + @return kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask, + kAffine_Mask, kPerspective_Mask + */ + TypeMask getType() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + // only return the public masks + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if SkMatrix is identity. Identity matrix is: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + @return true if SkMatrix has no effect + */ + bool isIdentity() const { + return this->getType() == 0; + } + + /** Returns true if SkMatrix at most scales and translates. SkMatrix may be identity, + contain only scale elements, only translate elements, or both. SkMatrix form is: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + @return true if SkMatrix is identity; or scales, translates, or both + */ + bool isScaleTranslate() const { + return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); + } + + /** Returns true if SkMatrix is identity, or translates. SkMatrix form is: + + | 1 0 translate-x | + | 0 1 translate-y | + | 0 0 1 | + + @return true if SkMatrix is identity, or translates + */ + bool isTranslate() const { return !(this->getType() & ~(kTranslate_Mask)); } + + /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, + or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all + cases, SkMatrix may also have translation. SkMatrix form is either: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + or + + | 0 rotate-x translate-x | + | rotate-y 0 translate-y | + | 0 0 1 | + + for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. + + Also called preservesAxisAlignment(); use the one that provides better inline + documentation. + + @return true if SkMatrix maps one SkRect into another + */ + bool rectStaysRect() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + return (fTypeMask & kRectStaysRect_Mask) != 0; + } + + /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, + or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all + cases, SkMatrix may also have translation. SkMatrix form is either: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + or + + | 0 rotate-x translate-x | + | rotate-y 0 translate-y | + | 0 0 1 | + + for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. + + Also called rectStaysRect(); use the one that provides better inline + documentation. + + @return true if SkMatrix maps one SkRect into another + */ + bool preservesAxisAlignment() const { return this->rectStaysRect(); } + + /** Returns true if the matrix contains perspective elements. SkMatrix form is: + + | -- -- -- | + | -- -- -- | + | perspective-x perspective-y perspective-scale | + + where perspective-x or perspective-y is non-zero, or perspective-scale is + not one. All other elements may have any value. + + @return true if SkMatrix is in most general form + */ + bool hasPerspective() const { + return SkToBool(this->getPerspectiveTypeMaskOnly() & + kPerspective_Mask); + } + + /** Returns true if SkMatrix contains only translation, rotation, reflection, and + uniform scale. + Returns false if SkMatrix contains different scales, skewing, perspective, or + degenerate forms that collapse to a line or point. + + Describes that the SkMatrix makes rendering with and without the matrix are + visually alike; a transformed circle remains a circle. Mathematically, this is + referred to as similarity of a Euclidean space, or a similarity transformation. + + Preserves right angles, keeping the arms of the angle equal lengths. + + @param tol to be deprecated + @return true if SkMatrix only rotates, uniformly scales, translates + + example: https://fiddle.skia.org/c/@Matrix_isSimilarity + */ + bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; + + /** Returns true if SkMatrix contains only translation, rotation, reflection, and + scale. Scale may differ along rotated axes. + Returns false if SkMatrix skewing, perspective, or degenerate forms that collapse + to a line or point. + + Preserves right angles, but not requiring that the arms of the angle + retain equal lengths. + + @param tol to be deprecated + @return true if SkMatrix only rotates, scales, translates + + example: https://fiddle.skia.org/c/@Matrix_preservesRightAngles + */ + bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; + + /** SkMatrix organizes its values in row-major order. These members correspond to + each value in SkMatrix. + */ + static constexpr int kMScaleX = 0; //!< horizontal scale factor + static constexpr int kMSkewX = 1; //!< horizontal skew factor + static constexpr int kMTransX = 2; //!< horizontal translation + static constexpr int kMSkewY = 3; //!< vertical skew factor + static constexpr int kMScaleY = 4; //!< vertical scale factor + static constexpr int kMTransY = 5; //!< vertical translation + static constexpr int kMPersp0 = 6; //!< input x perspective factor + static constexpr int kMPersp1 = 7; //!< input y perspective factor + static constexpr int kMPersp2 = 8; //!< perspective bias + + /** Affine arrays are in column-major order to match the matrix used by + PDF and XPS. + */ + static constexpr int kAScaleX = 0; //!< horizontal scale factor + static constexpr int kASkewY = 1; //!< vertical skew factor + static constexpr int kASkewX = 2; //!< horizontal skew factor + static constexpr int kAScaleY = 3; //!< vertical scale factor + static constexpr int kATransX = 4; //!< horizontal translation + static constexpr int kATransY = 5; //!< vertical translation + + /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is + defined. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return value corresponding to index + */ + SkScalar operator[](int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is + defined. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return value corresponding to index + */ + SkScalar get(int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + /** Returns one matrix value from a particular row/column. Asserts if index is out + of range and SK_DEBUG is defined. + + @param r matrix row to fetch + @param c matrix column to fetch + @return value at the given matrix position + */ + SkScalar rc(int r, int c) const { + SkASSERT(r >= 0 && r <= 2); + SkASSERT(c >= 0 && c <= 2); + return fMat[r*3 + c]; + } + + /** Returns scale factor multiplied by x-axis input, contributing to x-axis output. + With mapPoints(), scales SkPoint along the x-axis. + + @return horizontal scale factor + */ + SkScalar getScaleX() const { return fMat[kMScaleX]; } + + /** Returns scale factor multiplied by y-axis input, contributing to y-axis output. + With mapPoints(), scales SkPoint along the y-axis. + + @return vertical scale factor + */ + SkScalar getScaleY() const { return fMat[kMScaleY]; } + + /** Returns scale factor multiplied by x-axis input, contributing to y-axis output. + With mapPoints(), skews SkPoint along the y-axis. + Skewing both axes can rotate SkPoint. + + @return vertical skew factor + */ + SkScalar getSkewY() const { return fMat[kMSkewY]; } + + /** Returns scale factor multiplied by y-axis input, contributing to x-axis output. + With mapPoints(), skews SkPoint along the x-axis. + Skewing both axes can rotate SkPoint. + + @return horizontal scale factor + */ + SkScalar getSkewX() const { return fMat[kMSkewX]; } + + /** Returns translation contributing to x-axis output. + With mapPoints(), moves SkPoint along the x-axis. + + @return horizontal translation factor + */ + SkScalar getTranslateX() const { return fMat[kMTransX]; } + + /** Returns translation contributing to y-axis output. + With mapPoints(), moves SkPoint along the y-axis. + + @return vertical translation factor + */ + SkScalar getTranslateY() const { return fMat[kMTransY]; } + + /** Returns factor scaling input x-axis relative to input y-axis. + + @return input x-axis perspective factor + */ + SkScalar getPerspX() const { return fMat[kMPersp0]; } + + /** Returns factor scaling input y-axis relative to input x-axis. + + @return input y-axis perspective factor + */ + SkScalar getPerspY() const { return fMat[kMPersp1]; } + + /** Returns writable SkMatrix value. Asserts if index is out of range and SK_DEBUG is + defined. Clears internal cache anticipating that caller will change SkMatrix value. + + Next call to read SkMatrix state may recompute cache; subsequent writes to SkMatrix + value must be followed by dirtyMatrixTypeCache(). + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return writable value corresponding to index + */ + SkScalar& operator[](int index) { + SkASSERT((unsigned)index < 9); + this->setTypeMask(kUnknown_Mask); + return fMat[index]; + } + + /** Sets SkMatrix value. Asserts if index is out of range and SK_DEBUG is + defined. Safer than operator[]; internal cache is always maintained. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @param value scalar to store in SkMatrix + */ + SkMatrix& set(int index, SkScalar value) { + SkASSERT((unsigned)index < 9); + fMat[index] = value; + this->setTypeMask(kUnknown_Mask); + return *this; + } + + /** Sets horizontal scale factor. + + @param v horizontal scale factor to store + */ + SkMatrix& setScaleX(SkScalar v) { return this->set(kMScaleX, v); } + + /** Sets vertical scale factor. + + @param v vertical scale factor to store + */ + SkMatrix& setScaleY(SkScalar v) { return this->set(kMScaleY, v); } + + /** Sets vertical skew factor. + + @param v vertical skew factor to store + */ + SkMatrix& setSkewY(SkScalar v) { return this->set(kMSkewY, v); } + + /** Sets horizontal skew factor. + + @param v horizontal skew factor to store + */ + SkMatrix& setSkewX(SkScalar v) { return this->set(kMSkewX, v); } + + /** Sets horizontal translation. + + @param v horizontal translation to store + */ + SkMatrix& setTranslateX(SkScalar v) { return this->set(kMTransX, v); } + + /** Sets vertical translation. + + @param v vertical translation to store + */ + SkMatrix& setTranslateY(SkScalar v) { return this->set(kMTransY, v); } + + /** Sets input x-axis perspective factor, which causes mapXY() to vary input x-axis values + inversely proportional to input y-axis values. + + @param v perspective factor + */ + SkMatrix& setPerspX(SkScalar v) { return this->set(kMPersp0, v); } + + /** Sets input y-axis perspective factor, which causes mapXY() to vary input y-axis values + inversely proportional to input x-axis values. + + @param v perspective factor + */ + SkMatrix& setPerspY(SkScalar v) { return this->set(kMPersp1, v); } + + /** Sets all values from parameters. Sets matrix to: + + | scaleX skewX transX | + | skewY scaleY transY | + | persp0 persp1 persp2 | + + @param scaleX horizontal scale factor to store + @param skewX horizontal skew factor to store + @param transX horizontal translation to store + @param skewY vertical skew factor to store + @param scaleY vertical scale factor to store + @param transY vertical translation to store + @param persp0 input x-axis values perspective factor to store + @param persp1 input y-axis values perspective factor to store + @param persp2 perspective scale factor to store + */ + SkMatrix& setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, + SkScalar skewY, SkScalar scaleY, SkScalar transY, + SkScalar persp0, SkScalar persp1, SkScalar persp2) { + fMat[kMScaleX] = scaleX; + fMat[kMSkewX] = skewX; + fMat[kMTransX] = transX; + fMat[kMSkewY] = skewY; + fMat[kMScaleY] = scaleY; + fMat[kMTransY] = transY; + fMat[kMPersp0] = persp0; + fMat[kMPersp1] = persp1; + fMat[kMPersp2] = persp2; + this->setTypeMask(kUnknown_Mask); + return *this; + } + + /** Copies nine scalar values contained by SkMatrix into buffer, in member value + ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2. + + @param buffer storage for nine scalar values + */ + void get9(SkScalar buffer[9]) const { + memcpy(buffer, fMat, 9 * sizeof(SkScalar)); + } + + /** Sets SkMatrix to nine scalar values in buffer, in member value ascending order: + kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1, + kMPersp2. + + Sets matrix to: + + | buffer[0] buffer[1] buffer[2] | + | buffer[3] buffer[4] buffer[5] | + | buffer[6] buffer[7] buffer[8] | + + In the future, set9 followed by get9 may not return the same values. Since SkMatrix + maps non-homogeneous coordinates, scaling all nine values produces an equivalent + transformation, possibly improving precision. + + @param buffer nine scalar values + */ + SkMatrix& set9(const SkScalar buffer[9]); + + /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + Also called setIdentity(); use the one that provides better inline + documentation. + */ + SkMatrix& reset(); + + /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + Also called reset(); use the one that provides better inline + documentation. + */ + SkMatrix& setIdentity() { return this->reset(); } + + /** Sets SkMatrix to translate by (dx, dy). + + @param dx horizontal translation + @param dy vertical translation + */ + SkMatrix& setTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to translate by (v.fX, v.fY). + + @param v vector containing horizontal and vertical translation + */ + SkMatrix& setTranslate(const SkVector& v) { return this->setTranslate(v.fX, v.fY); } + + /** Sets SkMatrix to scale by sx and sy, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + + /** Sets SkMatrix to scale by sx and sy about at pivot point at (0, 0). + + @param sx horizontal scale factor + @param sy vertical scale factor + */ + SkMatrix& setScale(SkScalar sx, SkScalar sy); + + /** Sets SkMatrix to rotate by degrees about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + Positive degrees rotates clockwise. + + @param degrees angle of axes relative to upright axes + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setRotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Sets SkMatrix to rotate by degrees about a pivot point at (0, 0). + Positive degrees rotates clockwise. + + @param degrees angle of axes relative to upright axes + */ + SkMatrix& setRotate(SkScalar degrees); + + /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). + Vector length specifies scale. + + @param sinValue rotation vector x-axis component + @param cosValue rotation vector y-axis component + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue, + SkScalar px, SkScalar py); + + /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (0, 0). + + Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). + Vector length specifies scale. + + @param sinValue rotation vector x-axis component + @param cosValue rotation vector y-axis component + */ + SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue); + + /** Sets SkMatrix to rotate, scale, and translate using a compressed matrix form. + + Vector (rsxForm.fSSin, rsxForm.fSCos) describes the angle of rotation relative + to (0, 1). Vector length specifies scale. Mapped point is rotated and scaled + by vector, then translated by (rsxForm.fTx, rsxForm.fTy). + + @param rsxForm compressed SkRSXform matrix + @return reference to SkMatrix + + example: https://fiddle.skia.org/c/@Matrix_setRSXform + */ + SkMatrix& setRSXform(const SkRSXform& rsxForm); + + /** Sets SkMatrix to skew by kx and ky, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + + /** Sets SkMatrix to skew by kx and ky, about a pivot point at (0, 0). + + @param kx horizontal skew factor + @param ky vertical skew factor + */ + SkMatrix& setSkew(SkScalar kx, SkScalar ky); + + /** Sets SkMatrix to SkMatrix a multiplied by SkMatrix b. Either a or b may be this. + + Given: + + | A B C | | J K L | + a = | D E F |, b = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param a SkMatrix on left side of multiply expression + @param b SkMatrix on right side of multiply expression + */ + SkMatrix& setConcat(const SkMatrix& a, const SkMatrix& b); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from translation (dx, dy). + This can be thought of as moving the point to be mapped before applying SkMatrix. + + Given: + + | A B C | | 1 0 dx | + Matrix = | D E F |, T(dx, dy) = | 0 1 dy | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | 1 0 dx | | A B A*dx+B*dy+C | + Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F | + | G H I | | 0 0 1 | | G H G*dx+H*dy+I | + + @param dx x-axis translation before applying SkMatrix + @param dy y-axis translation before applying SkMatrix + */ + SkMatrix& preTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) + about pivot point (px, py). + This can be thought of as scaling about a pivot point before applying SkMatrix. + + Given: + + | A B C | | sx 0 dx | + Matrix = | D E F |, S(sx, sy, px, py) = | 0 sy dy | + | G H I | | 0 0 1 | + + where + + dx = px - sx * px + dy = py - sy * py + + sets SkMatrix to: + + | A B C | | sx 0 dx | | A*sx B*sy A*dx+B*dy+C | + Matrix * S(sx, sy, px, py) = | D E F | | 0 sy dy | = | D*sx E*sy D*dx+E*dy+F | + | G H I | | 0 0 1 | | G*sx H*sy G*dx+H*dy+I | + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) + about pivot point (0, 0). + This can be thought of as scaling about the origin before applying SkMatrix. + + Given: + + | A B C | | sx 0 0 | + Matrix = | D E F |, S(sx, sy) = | 0 sy 0 | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | sx 0 0 | | A*sx B*sy C | + Matrix * S(sx, sy) = | D E F | | 0 sy 0 | = | D*sx E*sy F | + | G H I | | 0 0 1 | | G*sx H*sy I | + + @param sx horizontal scale factor + @param sy vertical scale factor + */ + SkMatrix& preScale(SkScalar sx, SkScalar sy); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees + about pivot point (px, py). + This can be thought of as rotating about a pivot point before applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | A B C | | c -s dx | + Matrix = | D E F |, R(degrees, px, py) = | s c dy | + | G H I | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + dx = s * py + (1 - c) * px + dy = -s * px + (1 - c) * py + + sets SkMatrix to: + + | A B C | | c -s dx | | Ac+Bs -As+Bc A*dx+B*dy+C | + Matrix * R(degrees, px, py) = | D E F | | s c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F | + | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc G*dx+H*dy+I | + + @param degrees angle of axes relative to upright axes + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& preRotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees + about pivot point (0, 0). + This can be thought of as rotating about the origin before applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | A B C | | c -s 0 | + Matrix = | D E F |, R(degrees, px, py) = | s c 0 | + | G H I | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + + sets SkMatrix to: + + | A B C | | c -s 0 | | Ac+Bs -As+Bc C | + Matrix * R(degrees, px, py) = | D E F | | s c 0 | = | Dc+Es -Ds+Ec F | + | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc I | + + @param degrees angle of axes relative to upright axes + */ + SkMatrix& preRotate(SkScalar degrees); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) + about pivot point (px, py). + This can be thought of as skewing about a pivot point before applying SkMatrix. + + Given: + + | A B C | | 1 kx dx | + Matrix = | D E F |, K(kx, ky, px, py) = | ky 1 dy | + | G H I | | 0 0 1 | + + where + + dx = -kx * py + dy = -ky * px + + sets SkMatrix to: + + | A B C | | 1 kx dx | | A+B*ky A*kx+B A*dx+B*dy+C | + Matrix * K(kx, ky, px, py) = | D E F | | ky 1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F | + | G H I | | 0 0 1 | | G+H*ky G*kx+H G*dx+H*dy+I | + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) + about pivot point (0, 0). + This can be thought of as skewing about the origin before applying SkMatrix. + + Given: + + | A B C | | 1 kx 0 | + Matrix = | D E F |, K(kx, ky) = | ky 1 0 | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | 1 kx 0 | | A+B*ky A*kx+B C | + Matrix * K(kx, ky) = | D E F | | ky 1 0 | = | D+E*ky D*kx+E F | + | G H I | | 0 0 1 | | G+H*ky G*kx+H I | + + @param kx horizontal skew factor + @param ky vertical skew factor + */ + SkMatrix& preSkew(SkScalar kx, SkScalar ky); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix other. + This can be thought of mapping by other before applying SkMatrix. + + Given: + + | A B C | | J K L | + Matrix = | D E F |, other = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param other SkMatrix on right side of multiply expression + */ + SkMatrix& preConcat(const SkMatrix& other); + + /** Sets SkMatrix to SkMatrix constructed from translation (dx, dy) multiplied by SkMatrix. + This can be thought of as moving the point to be mapped after applying SkMatrix. + + Given: + + | J K L | | 1 0 dx | + Matrix = | M N O |, T(dx, dy) = | 0 1 dy | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | 1 0 dx | | J K L | | J+dx*P K+dx*Q L+dx*R | + T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R | + | 0 0 1 | | P Q R | | P Q R | + + @param dx x-axis translation after applying SkMatrix + @param dy y-axis translation after applying SkMatrix + */ + SkMatrix& postTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as scaling about a pivot point after applying SkMatrix. + + Given: + + | J K L | | sx 0 dx | + Matrix = | M N O |, S(sx, sy, px, py) = | 0 sy dy | + | P Q R | | 0 0 1 | + + where + + dx = px - sx * px + dy = py - sy * py + + sets SkMatrix to: + + | sx 0 dx | | J K L | | sx*J+dx*P sx*K+dx*Q sx*L+dx+R | + S(sx, sy, px, py) * Matrix = | 0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R | + | 0 0 1 | | P Q R | | P Q R | + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as scaling about the origin after applying SkMatrix. + + Given: + + | J K L | | sx 0 0 | + Matrix = | M N O |, S(sx, sy) = | 0 sy 0 | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | sx 0 0 | | J K L | | sx*J sx*K sx*L | + S(sx, sy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O | + | 0 0 1 | | P Q R | | P Q R | + + @param sx horizontal scale factor + @param sy vertical scale factor + */ + SkMatrix& postScale(SkScalar sx, SkScalar sy); + + /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as rotating about a pivot point after applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | J K L | | c -s dx | + Matrix = | M N O |, R(degrees, px, py) = | s c dy | + | P Q R | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + dx = s * py + (1 - c) * px + dy = -s * px + (1 - c) * py + + sets SkMatrix to: + + |c -s dx| |J K L| |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R| + R(degrees, px, py) * Matrix = |s c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R| + |0 0 1| |P Q R| | P Q R| + + @param degrees angle of axes relative to upright axes + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& postRotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as rotating about the origin after applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | J K L | | c -s 0 | + Matrix = | M N O |, R(degrees, px, py) = | s c 0 | + | P Q R | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + + sets SkMatrix to: + + | c -s dx | | J K L | | cJ-sM cK-sN cL-sO | + R(degrees, px, py) * Matrix = | s c dy | | M N O | = | sJ+cM sK+cN sL+cO | + | 0 0 1 | | P Q R | | P Q R | + + @param degrees angle of axes relative to upright axes + */ + SkMatrix& postRotate(SkScalar degrees); + + /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as skewing about a pivot point after applying SkMatrix. + + Given: + + | J K L | | 1 kx dx | + Matrix = | M N O |, K(kx, ky, px, py) = | ky 1 dy | + | P Q R | | 0 0 1 | + + where + + dx = -kx * py + dy = -ky * px + + sets SkMatrix to: + + | 1 kx dx| |J K L| |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R| + K(kx, ky, px, py) * Matrix = |ky 1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R| + | 0 0 1| |P Q R| | P Q R| + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as skewing about the origin after applying SkMatrix. + + Given: + + | J K L | | 1 kx 0 | + Matrix = | M N O |, K(kx, ky) = | ky 1 0 | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | 1 kx 0 | | J K L | | J+kx*M K+kx*N L+kx*O | + K(kx, ky) * Matrix = | ky 1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O | + | 0 0 1 | | P Q R | | P Q R | + + @param kx horizontal skew factor + @param ky vertical skew factor + */ + SkMatrix& postSkew(SkScalar kx, SkScalar ky); + + /** Sets SkMatrix to SkMatrix other multiplied by SkMatrix. + This can be thought of mapping by other after applying SkMatrix. + + Given: + + | J K L | | A B C | + Matrix = | M N O |, other = | D E F | + | P Q R | | G H I | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param other SkMatrix on left side of multiply expression + */ + SkMatrix& postConcat(const SkMatrix& other); + +#ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT +private: +#endif + /** Sets SkMatrix to scale and translate src SkRect to dst SkRect. stf selects whether + mapping completely fills dst or preserves the aspect ratio, and how to align + src within dst. Returns false if src is empty, and sets SkMatrix to identity. + Returns true if dst is empty, and sets SkMatrix to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @return true if SkMatrix can represent SkRect mapping + + example: https://fiddle.skia.org/c/@Matrix_setRectToRect + */ + bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); + + /** Returns SkMatrix set to scale and translate src SkRect to dst SkRect. stf selects + whether mapping completely fills dst or preserves the aspect ratio, and how to + align src within dst. Returns the identity SkMatrix if src is empty. If dst is + empty, returns SkMatrix set to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @return SkMatrix mapping src to dst + */ + static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) { + SkMatrix m; + m.setRectToRect(src, dst, stf); + return m; + } +#ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT +public: +#endif + + /** Sets SkMatrix to map src to dst. count must be zero or greater, and four or less. + + If count is zero, sets SkMatrix to identity and returns true. + If count is one, sets SkMatrix to translate and returns true. + If count is two or more, sets SkMatrix to map SkPoint if possible; returns false + if SkMatrix cannot be constructed. If count is four, SkMatrix may include + perspective. + + @param src SkPoint to map from + @param dst SkPoint to map to + @param count number of SkPoint in src and dst + @return true if SkMatrix was constructed successfully + + example: https://fiddle.skia.org/c/@Matrix_setPolyToPoly + */ + bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); + + /** Sets inverse to reciprocal matrix, returning true if SkMatrix can be inverted. + Geometrically, if SkMatrix maps from source to destination, inverse SkMatrix + maps from destination to source. If SkMatrix can not be inverted, inverse is + unchanged. + + @param inverse storage for inverted SkMatrix; may be nullptr + @return true if SkMatrix can be inverted + */ + bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const { + // Allow the trivial case to be inlined. + if (this->isIdentity()) { + if (inverse) { + inverse->reset(); + } + return true; + } + return this->invertNonIdentity(inverse); + } + + /** Fills affine with identity values in column major order. + Sets affine to: + + | 1 0 0 | + | 0 1 0 | + + Affine 3 by 2 matrices in column major order are used by OpenGL and XPS. + + @param affine storage for 3 by 2 affine matrix + + example: https://fiddle.skia.org/c/@Matrix_SetAffineIdentity + */ + static void SetAffineIdentity(SkScalar affine[6]); + + /** Fills affine in column major order. Sets affine to: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + + If SkMatrix contains perspective, returns false and leaves affine unchanged. + + @param affine storage for 3 by 2 affine matrix; may be nullptr + @return true if SkMatrix does not contain perspective + */ + bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const; + + /** Sets SkMatrix to affine values, passed in column major order. Given affine, + column, then row, as: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + + SkMatrix is set, row, then column, to: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + | 0 0 1 | + + @param affine 3 by 2 affine matrix + */ + SkMatrix& setAffine(const SkScalar affine[6]); + + /** + * A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 1]. + * However, for most uses (e.g. mapPoints) a bottom row of [0, 0, X] behaves like a + * non-perspective matrix, though it will be categorized as perspective. Calling + * normalizePerspective() will change the matrix such that, if its bottom row was [0, 0, X], + * it will be changed to [0, 0, 1] by scaling the rest of the matrix by 1/X. + * + * | A B C | | A/X B/X C/X | + * | D E F | -> | D/X E/X F/X | for X != 0 + * | 0 0 X | | 0 0 1 | + */ + void normalizePerspective() { + if (fMat[8] != 1) { + this->doNormalizePerspective(); + } + } + + /** Maps src SkPoint array of length count to dst SkPoint array of equal or greater + length. SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = src[i].fX + y = src[i].fY + } + + each dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + src and dst may point to the same storage. + + @param dst storage for mapped SkPoint + @param src SkPoint to transform + @param count number of SkPoint to transform + + example: https://fiddle.skia.org/c/@Matrix_mapPoints + */ + void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; + + /** Maps pts SkPoint array of length count in place. SkPoint are mapped by multiplying + each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = pts[i].fX + y = pts[i].fY + } + + each resulting pts SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param pts storage for mapped SkPoint + @param count number of SkPoint to transform + */ + void mapPoints(SkPoint pts[], int count) const { + this->mapPoints(pts, pts, count); + } + + /** Maps src SkPoint3 array of length count to dst SkPoint3 array, which must of length count or + greater. SkPoint3 array is mapped by multiplying each SkPoint3 by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, src = | y | + | G H I | | z | + + each resulting dst SkPoint is computed as: + + |A B C| |x| + Matrix * src = |D E F| |y| = |Ax+By+Cz Dx+Ey+Fz Gx+Hy+Iz| + |G H I| |z| + + @param dst storage for mapped SkPoint3 array + @param src SkPoint3 array to transform + @param count items in SkPoint3 array to transform + + example: https://fiddle.skia.org/c/@Matrix_mapHomogeneousPoints + */ + void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const; + + /** + * Returns homogeneous points, starting with 2D src points (with implied w = 1). + */ + void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const; + + /** Returns SkPoint pt multiplied by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param p SkPoint to map + @return mapped SkPoint + */ + SkPoint mapPoint(SkPoint pt) const { + SkPoint result; + this->mapXY(pt.x(), pt.y(), &result); + return result; + } + + /** Maps SkPoint (x, y) to result. SkPoint is mapped by multiplying by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param x x-axis value of SkPoint to map + @param y y-axis value of SkPoint to map + @param result storage for mapped SkPoint + + example: https://fiddle.skia.org/c/@Matrix_mapXY + */ + void mapXY(SkScalar x, SkScalar y, SkPoint* result) const; + + /** Returns SkPoint (x, y) multiplied by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param x x-axis value of SkPoint to map + @param y y-axis value of SkPoint to map + @return mapped SkPoint + */ + SkPoint mapXY(SkScalar x, SkScalar y) const { + SkPoint result; + this->mapXY(x,y, &result); + return result; + } + + + /** Returns (0, 0) multiplied by SkMatrix. Given: + + | A B C | | 0 | + Matrix = | D E F |, pt = | 0 | + | G H I | | 1 | + + result is computed as: + + |A B C| |0| C F + Matrix * pt = |D E F| |0| = |C F I| = - , - + |G H I| |1| I I + + @return mapped (0, 0) + */ + SkPoint mapOrigin() const { + SkScalar x = this->getTranslateX(), + y = this->getTranslateY(); + if (this->hasPerspective()) { + SkScalar w = fMat[kMPersp2]; + if (w) { w = 1 / w; } + x *= w; + y *= w; + } + return {x, y}; + } + + /** Maps src vector array of length count to vector SkPoint array of equal or greater + length. Vectors are mapped by multiplying each vector by SkMatrix, treating + SkMatrix translation as zero. Given: + + | A B 0 | | x | + Matrix = | D E 0 |, src = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = src[i].fX + y = src[i].fY + } + + each dst vector is computed as: + + |A B 0| |x| Ax+By Dx+Ey + Matrix * src = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + src and dst may point to the same storage. + + @param dst storage for mapped vectors + @param src vectors to transform + @param count number of vectors to transform + + example: https://fiddle.skia.org/c/@Matrix_mapVectors + */ + void mapVectors(SkVector dst[], const SkVector src[], int count) const; + + /** Maps vecs vector array of length count in place, multiplying each vector by + SkMatrix, treating SkMatrix translation as zero. Given: + + | A B 0 | | x | + Matrix = | D E 0 |, vec = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = vecs[i].fX + y = vecs[i].fY + } + + each result vector is computed as: + + |A B 0| |x| Ax+By Dx+Ey + Matrix * vec = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param vecs vectors to transform, and storage for mapped vectors + @param count number of vectors to transform + */ + void mapVectors(SkVector vecs[], int count) const { + this->mapVectors(vecs, vecs, count); + } + + /** Maps vector (dx, dy) to result. Vector is mapped by multiplying by SkMatrix, + treating SkMatrix translation as zero. Given: + + | A B 0 | | dx | + Matrix = | D E 0 |, vec = | dy | + | G H I | | 1 | + + each result vector is computed as: + + |A B 0| |dx| A*dx+B*dy D*dx+E*dy + Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- + |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I + + @param dx x-axis value of vector to map + @param dy y-axis value of vector to map + @param result storage for mapped vector + */ + void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const { + SkVector vec = { dx, dy }; + this->mapVectors(result, &vec, 1); + } + + /** Returns vector (dx, dy) multiplied by SkMatrix, treating SkMatrix translation as zero. + Given: + + | A B 0 | | dx | + Matrix = | D E 0 |, vec = | dy | + | G H I | | 1 | + + each result vector is computed as: + + |A B 0| |dx| A*dx+B*dy D*dx+E*dy + Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- + |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I + + @param dx x-axis value of vector to map + @param dy y-axis value of vector to map + @return mapped vector + */ + SkVector mapVector(SkScalar dx, SkScalar dy) const { + SkVector vec = { dx, dy }; + this->mapVectors(&vec, &vec, 1); + return vec; + } + + /** Sets dst to bounds of src corners mapped by SkMatrix. + Returns true if mapped corners are dst corners. + + Returned value is the same as calling rectStaysRect(). + + @param dst storage for bounds of mapped SkPoint + @param src SkRect to map + @param pc whether to apply perspective clipping + @return true if dst is equivalent to mapped src + + example: https://fiddle.skia.org/c/@Matrix_mapRect + */ + bool mapRect(SkRect* dst, const SkRect& src, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const; + + /** Sets rect to bounds of rect corners mapped by SkMatrix. + Returns true if mapped corners are computed rect corners. + + Returned value is the same as calling rectStaysRect(). + + @param rect rectangle to map, and storage for bounds of mapped corners + @param pc whether to apply perspective clipping + @return true if result is equivalent to mapped rect + */ + bool mapRect(SkRect* rect, SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { + return this->mapRect(rect, *rect, pc); + } + + /** Returns bounds of src corners mapped by SkMatrix. + + @param src rectangle to map + @return mapped bounds + */ + SkRect mapRect(const SkRect& src, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { + SkRect dst; + (void)this->mapRect(&dst, src, pc); + return dst; + } + + /** Maps four corners of rect to dst. SkPoint are mapped by multiplying each + rect corner by SkMatrix. rect corner is processed in this order: + (rect.fLeft, rect.fTop), (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), + (rect.fLeft, rect.fBottom). + + rect may be empty: rect.fLeft may be greater than or equal to rect.fRight; + rect.fTop may be greater than or equal to rect.fBottom. + + Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where pt is initialized from each of (rect.fLeft, rect.fTop), + (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), (rect.fLeft, rect.fBottom), + each dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param dst storage for mapped corner SkPoint + @param rect SkRect to map + + Note: this does not perform perspective clipping (as that might result in more than + 4 points, so results are suspect if the matrix contains perspective. + */ + void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const { + // This could potentially be faster if we only transformed each x and y of the rect once. + rect.toQuad(dst); + this->mapPoints(dst, 4); + } + + /** Sets dst to bounds of src corners mapped by SkMatrix. If matrix contains + elements other than scale or translate: asserts if SK_DEBUG is defined; + otherwise, results are undefined. + + @param dst storage for bounds of mapped SkPoint + @param src SkRect to map + + example: https://fiddle.skia.org/c/@Matrix_mapRectScaleTranslate + */ + void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const; + + /** Returns geometric mean radius of ellipse formed by constructing circle of + size radius, and mapping constructed circle with SkMatrix. The result squared is + equal to the major axis length times the minor axis length. + Result is not meaningful if SkMatrix contains perspective elements. + + @param radius circle size to map + @return average mapped radius + + example: https://fiddle.skia.org/c/@Matrix_mapRadius + */ + SkScalar mapRadius(SkScalar radius) const; + + /** Compares a and b; returns true if a and b are numerically equal. Returns true + even if sign of zero values are different. Returns false if either SkMatrix + contains NaN, even if the other SkMatrix also contains NaN. + + @param a SkMatrix to compare + @param b SkMatrix to compare + @return true if SkMatrix a and SkMatrix b are numerically equal + */ + friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b); + + /** Compares a and b; returns true if a and b are not numerically equal. Returns false + even if sign of zero values are different. Returns true if either SkMatrix + contains NaN, even if the other SkMatrix also contains NaN. + + @param a SkMatrix to compare + @param b SkMatrix to compare + @return true if SkMatrix a and SkMatrix b are numerically not equal + */ + friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) { + return !(a == b); + } + + /** Writes text representation of SkMatrix to standard output. Floating point values + are written with limited precision; it may not be possible to reconstruct + original SkMatrix from output. + + example: https://fiddle.skia.org/c/@Matrix_dump + */ + void dump() const; + + /** Returns the minimum scaling factor of SkMatrix by decomposing the scaling and + skewing elements. + Returns -1 if scale factor overflows or SkMatrix contains perspective. + + @return minimum scale factor + + example: https://fiddle.skia.org/c/@Matrix_getMinScale + */ + SkScalar getMinScale() const; + + /** Returns the maximum scaling factor of SkMatrix by decomposing the scaling and + skewing elements. + Returns -1 if scale factor overflows or SkMatrix contains perspective. + + @return maximum scale factor + + example: https://fiddle.skia.org/c/@Matrix_getMaxScale + */ + SkScalar getMaxScale() const; + + /** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the + maximum scaling factor. Scaling factors are computed by decomposing + the SkMatrix scaling and skewing elements. + + Returns true if scaleFactors are found; otherwise, returns false and sets + scaleFactors to undefined values. + + @param scaleFactors storage for minimum and maximum scale factors + @return true if scale factors were computed correctly + */ + bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const; + + /** Decomposes SkMatrix into scale components and whatever remains. Returns false if + SkMatrix could not be decomposed. + + Sets scale to portion of SkMatrix that scale axes. Sets remaining to SkMatrix + with scaling factored out. remaining may be passed as nullptr + to determine if SkMatrix can be decomposed without computing remainder. + + Returns true if scale components are found. scale and remaining are + unchanged if SkMatrix contains perspective; scale factors are not finite, or + are nearly zero. + + On success: Matrix = Remaining * scale. + + @param scale axes scaling factors; may be nullptr + @param remaining SkMatrix without scaling; may be nullptr + @return true if scale can be computed + + example: https://fiddle.skia.org/c/@Matrix_decomposeScale + */ + bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const; + + /** Returns reference to const identity SkMatrix. Returned SkMatrix is set to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + @return const identity SkMatrix + + example: https://fiddle.skia.org/c/@Matrix_I + */ + static const SkMatrix& I(); + + /** Returns reference to a const SkMatrix with invalid values. Returned SkMatrix is set + to: + + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + + @return const invalid SkMatrix + + example: https://fiddle.skia.org/c/@Matrix_InvalidMatrix + */ + static const SkMatrix& InvalidMatrix(); + + /** Returns SkMatrix a multiplied by SkMatrix b. + + Given: + + | A B C | | J K L | + a = | D E F |, b = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param a SkMatrix on left side of multiply expression + @param b SkMatrix on right side of multiply expression + @return SkMatrix computed from a times b + */ + static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) { + SkMatrix result; + result.setConcat(a, b); + return result; + } + + friend SkMatrix operator*(const SkMatrix& a, const SkMatrix& b) { + return Concat(a, b); + } + + /** Sets internal cache to unknown state. Use to force update after repeated + modifications to SkMatrix element reference returned by operator[](int index). + */ + void dirtyMatrixTypeCache() { + this->setTypeMask(kUnknown_Mask); + } + + /** Initializes SkMatrix with scale and translate elements. + + | sx 0 tx | + | 0 sy ty | + | 0 0 1 | + + @param sx horizontal scale factor to store + @param sy vertical scale factor to store + @param tx horizontal translation to store + @param ty vertical translation to store + */ + void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) { + fMat[kMScaleX] = sx; + fMat[kMSkewX] = 0; + fMat[kMTransX] = tx; + + fMat[kMSkewY] = 0; + fMat[kMScaleY] = sy; + fMat[kMTransY] = ty; + + fMat[kMPersp0] = 0; + fMat[kMPersp1] = 0; + fMat[kMPersp2] = 1; + + int mask = 0; + if (sx != 1 || sy != 1) { + mask |= kScale_Mask; + } + if (tx != 0.0f || ty != 0.0f) { + mask |= kTranslate_Mask; + } + if (sx != 0 && sy != 0) { + mask |= kRectStaysRect_Mask; + } + this->setTypeMask(mask); + } + + /** Returns true if all elements of the matrix are finite. Returns false if any + element is infinity, or NaN. + + @return true if matrix has only finite elements + */ + bool isFinite() const { return SkScalarsAreFinite(fMat, 9); } + +private: + /** Set if the matrix will map a rectangle to another rectangle. This + can be true if the matrix is scale-only, or rotates a multiple of + 90 degrees. + + This bit will be set on identity matrices + */ + static constexpr int kRectStaysRect_Mask = 0x10; + + /** Set if the perspective bit is valid even though the rest of + the matrix is Unknown. + */ + static constexpr int kOnlyPerspectiveValid_Mask = 0x40; + + static constexpr int kUnknown_Mask = 0x80; + + static constexpr int kORableMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask; + + static constexpr int kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask; + + SkScalar fMat[9]; + mutable int32_t fTypeMask; + + constexpr SkMatrix(SkScalar sx, SkScalar kx, SkScalar tx, + SkScalar ky, SkScalar sy, SkScalar ty, + SkScalar p0, SkScalar p1, SkScalar p2, int typeMask) + : fMat{sx, kx, tx, + ky, sy, ty, + p0, p1, p2} + , fTypeMask(typeMask) {} + + static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp); + + uint8_t computeTypeMask() const; + uint8_t computePerspectiveTypeMask() const; + + void setTypeMask(int mask) { + // allow kUnknown or a valid mask + SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || + ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) + == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); + fTypeMask = mask; + } + + void orTypeMask(int mask) { + SkASSERT((mask & kORableMasks) == mask); + fTypeMask |= mask; + } + + void clearTypeMask(int mask) { + // only allow a valid mask + SkASSERT((mask & kAllMasks) == mask); + fTypeMask &= ~mask; + } + + TypeMask getPerspectiveTypeMaskOnly() const { + if ((fTypeMask & kUnknown_Mask) && + !(fTypeMask & kOnlyPerspectiveValid_Mask)) { + fTypeMask = this->computePerspectiveTypeMask(); + } + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if we already know that the matrix is identity; + false otherwise. + */ + bool isTriviallyIdentity() const { + if (fTypeMask & kUnknown_Mask) { + return false; + } + return ((fTypeMask & 0xF) == 0); + } + + inline void updateTranslateMask() { + if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) { + fTypeMask |= kTranslate_Mask; + } else { + fTypeMask &= ~kTranslate_Mask; + } + } + + typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, + SkPoint* result); + + static MapXYProc GetMapXYProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapXYProcs[mask & kAllMasks]; + } + + MapXYProc getMapXYProc() const { + return GetMapXYProc(this->getType()); + } + + typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], + const SkPoint src[], int count); + + static MapPtsProc GetMapPtsProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapPtsProcs[mask & kAllMasks]; + } + + MapPtsProc getMapPtsProc() const { + return GetMapPtsProc(this->getType()); + } + + bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; + + static bool Poly2Proc(const SkPoint[], SkMatrix*); + static bool Poly3Proc(const SkPoint[], SkMatrix*); + static bool Poly4Proc(const SkPoint[], SkMatrix*); + + static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + + static const MapXYProc gMapXYProcs[]; + + static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); + static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], + int count); + static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + + static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + + static const MapPtsProc gMapPtsProcs[]; + + // return the number of bytes written, whether or not buffer is null + size_t writeToMemory(void* buffer) const; + /** + * Reads data from the buffer parameter + * + * @param buffer Memory to read from + * @param length Amount of memory available in the buffer + * @return number of bytes read (must be a multiple of 4) or + * 0 if there was not enough memory available + */ + size_t readFromMemory(const void* buffer, size_t length); + + // legacy method -- still needed? why not just postScale(1/divx, ...)? + bool postIDiv(int divx, int divy); + void doNormalizePerspective(); + + friend class SkPerspIter; + friend class SkMatrixPriv; + friend class SerializationTest; +}; +SK_END_REQUIRE_DENSE + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMesh.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMesh.h new file mode 100644 index 00000000000000..360a039e7f531f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMesh.h @@ -0,0 +1,423 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMesh_DEFINED +#define SkMesh_DEFINED + +#include "include/core/SkTypes.h" + +#ifdef SK_ENABLE_SKSL +#include "include/core/SkAlphaType.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSpan.h" +#include "include/core/SkString.h" +#include "include/effects/SkRuntimeEffect.h" + +#include +#include +#include + +class GrDirectContext; +class SkColorSpace; +class SkData; + +namespace SkSL { struct Program; } + +/** + * A specification for custom meshes. Specifies the vertex buffer attributes and stride, the + * vertex program that produces a user-defined set of varyings, and a fragment program that ingests + * the interpolated varyings and produces local coordinates for shading and optionally a color. + * + * The varyings must include a float2 named "position". If the passed varyings does not + * contain such a varying then one is implicitly added to the final specification and the SkSL + * Varyings struct described below. It is an error to have a varying named "position" that has a + * type other than float2. + * + * The provided attributes and varyings are used to create Attributes and Varyings structs in SkSL + * that are used by the shaders. Each attribute from the Attribute span becomes a member of the + * SkSL Attributes struct and likewise for the varyings. + * + * The signature of the vertex program must be: + * Varyings main(const Attributes). + * + * The signature of the fragment program must be either: + * float2 main(const Varyings) + * or + * float2 main(const Varyings, out (half4|float4) color) + * + * where the return value is the local coordinates that will be used to access SkShader. If the + * color variant is used, the returned color will be blended with SkPaint's SkShader (or SkPaint + * color in absence of a SkShader) using the SkBlender passed to SkCanvas drawMesh(). To use + * interpolated local space positions as the shader coordinates, equivalent to how SkPaths are + * shaded, return the position field from the Varying struct as the coordinates. + * + * The vertex and fragment programs may both contain uniforms. Uniforms with the same name are + * assumed to be shared between stages. It is an error to specify uniforms in the vertex and + * fragment program with the same name but different types, dimensionality, or layouts. + */ +class SkMeshSpecification : public SkNVRefCnt { +public: + /** These values are enforced when creating a specification. */ + static constexpr size_t kMaxStride = 1024; + static constexpr size_t kMaxAttributes = 8; + static constexpr size_t kStrideAlignment = 4; + static constexpr size_t kOffsetAlignment = 4; + static constexpr size_t kMaxVaryings = 6; + + struct Attribute { + enum class Type : uint32_t { // CPU representation Shader Type + kFloat, // float float + kFloat2, // two floats float2 + kFloat3, // three floats float3 + kFloat4, // four floats float4 + kUByte4_unorm, // four bytes half4 + + kLast = kUByte4_unorm + }; + Type type; + size_t offset; + SkString name; + }; + + struct Varying { + enum class Type : uint32_t { + kFloat, // "float" + kFloat2, // "float2" + kFloat3, // "float3" + kFloat4, // "float4" + kHalf, // "half" + kHalf2, // "half2" + kHalf3, // "half3" + kHalf4, // "half4" + + kLast = kHalf4 + }; + Type type; + SkString name; + }; + + using Uniform = SkRuntimeEffect::Uniform; + + ~SkMeshSpecification(); + + struct Result { + sk_sp specification; + SkString error; + }; + + /** + * If successful the return is a specification and an empty error string. Otherwise, it is a + * null specification a non-empty error string. + * + * @param attributes The vertex attributes that will be consumed by 'vs'. Attributes need + * not be tightly packed but attribute offsets must be aligned to + * kOffsetAlignment and offset + size may not be greater than + * 'vertexStride'. At least one attribute is required. + * @param vertexStride The offset between successive attribute values. This must be aligned to + * kStrideAlignment. + * @param varyings The varyings that will be written by 'vs' and read by 'fs'. This may + * be empty. + * @param vs The vertex shader code that computes a vertex position and the varyings + * from the attributes. + * @param fs The fragment code that computes a local coordinate and optionally a + * color from the varyings. The local coordinate is used to sample + * SkShader. + * @param cs The colorspace of the color produced by 'fs'. Ignored if 'fs's main() + * function does not have a color out param. + * @param at The alpha type of the color produced by 'fs'. Ignored if 'fs's main() + * function does not have a color out param. Cannot be kUnknown. + */ + static Result Make(SkSpan attributes, + size_t vertexStride, + SkSpan varyings, + const SkString& vs, + const SkString& fs); + static Result Make(SkSpan attributes, + size_t vertexStride, + SkSpan varyings, + const SkString& vs, + const SkString& fs, + sk_sp cs); + static Result Make(SkSpan attributes, + size_t vertexStride, + SkSpan varyings, + const SkString& vs, + const SkString& fs, + sk_sp cs, + SkAlphaType at); + + SkSpan attributes() const { return SkSpan(fAttributes); } + + /** + * Combined size of all 'uniform' variables. When creating a SkMesh with this specification + * provide an SkData of this size, containing values for all of those variables. Use uniforms() + * to get the offset of each uniform within the SkData. + */ + size_t uniformSize() const; + + /** + * Provides info about individual uniforms including the offset into an SkData where each + * uniform value should be placed. + */ + SkSpan uniforms() const { return SkSpan(fUniforms); } + + /** Returns pointer to the named uniform variable's description, or nullptr if not found. */ + const Uniform* findUniform(std::string_view name) const; + + /** Returns pointer to the named attribute, or nullptr if not found. */ + const Attribute* findAttribute(std::string_view name) const; + + /** Returns pointer to the named varying, or nullptr if not found. */ + const Varying* findVarying(std::string_view name) const; + + size_t stride() const { return fStride; } + +private: + friend struct SkMeshSpecificationPriv; + + enum class ColorType { + kNone, + kHalf4, + kFloat4, + }; + + static Result MakeFromSourceWithStructs(SkSpan attributes, + size_t stride, + SkSpan varyings, + const SkString& vs, + const SkString& fs, + sk_sp cs, + SkAlphaType at); + + SkMeshSpecification(SkSpan, + size_t, + SkSpan, + int passthroughLocalCoordsVaryingIndex, + uint32_t deadVaryingMask, + std::vector uniforms, + std::unique_ptr, + std::unique_ptr, + ColorType, + sk_sp, + SkAlphaType); + + SkMeshSpecification(const SkMeshSpecification&) = delete; + SkMeshSpecification(SkMeshSpecification&&) = delete; + + SkMeshSpecification& operator=(const SkMeshSpecification&) = delete; + SkMeshSpecification& operator=(SkMeshSpecification&&) = delete; + + const std::vector fAttributes; + const std::vector fVaryings; + const std::vector fUniforms; + const std::unique_ptr fVS; + const std::unique_ptr fFS; + const size_t fStride; + uint32_t fHash; + const int fPassthroughLocalCoordsVaryingIndex; + const uint32_t fDeadVaryingMask; + const ColorType fColorType; + const sk_sp fColorSpace; + const SkAlphaType fAlphaType; +}; + +/** + * A vertex buffer, a topology, optionally an index buffer, and a compatible SkMeshSpecification. + * + * The data in the vertex buffer is expected to contain the attributes described by the spec + * for vertexCount vertices beginning at vertexOffset. vertexOffset must be aligned to the + * SkMeshSpecification's vertex stride. The size of the buffer must be at least vertexOffset + + * spec->stride()*vertexCount (even if vertex attributes contains pad at the end of the stride). If + * the specified bounds does not contain all the points output by the spec's vertex program when + * applied to the vertices in the custom mesh then the result is undefined. + * + * MakeIndexed may be used to create an indexed mesh. indexCount indices are read from the index + * buffer at the specified offset which must be aligned to 2. The indices are always unsigned 16bit + * integers. The index count must be at least 3. + * + * If Make() is used the implicit index sequence is 0, 1, 2, 3, ... and vertexCount must be at least + * 3. + * + * Both Make() and MakeIndexed() take a SkData with the uniform values. See + * SkMeshSpecification::uniformSize() and SkMeshSpecification::uniforms() for sizing and packing + * uniforms into the SkData. + */ +class SkMesh { +public: + class IndexBuffer : public SkRefCnt { + public: + virtual size_t size() const = 0; + + /** + * Modifies the data in the IndexBuffer by copying size bytes from data into the buffer + * at offset. Fails if offset + size > this->size() or if either offset or size is not + * aligned to 4 bytes. The GrDirectContext* must match that used to create the buffer. We + * take it as a parameter to emphasize that the context must be used to update the data and + * thus the context must be valid for the current thread. + */ + bool update(GrDirectContext*, const void* data, size_t offset, size_t size); + + private: + virtual bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) = 0; + }; + + class VertexBuffer : public SkRefCnt { + public: + virtual size_t size() const = 0; + + /** + * Modifies the data in the IndexBuffer by copying size bytes from data into the buffer + * at offset. Fails if offset + size > this->size() or if either offset or size is not + * aligned to 4 bytes. The GrDirectContext* must match that used to create the buffer. We + * take it as a parameter to emphasize that the context must be used to update the data and + * thus the context must be valid for the current thread. + */ + bool update(GrDirectContext*, const void* data, size_t offset, size_t size); + + private: + virtual bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) = 0; + }; + + SkMesh(); + ~SkMesh(); + + SkMesh(const SkMesh&); + SkMesh(SkMesh&&); + + SkMesh& operator=(const SkMesh&); + SkMesh& operator=(SkMesh&&); + + /** + * Makes an index buffer to be used with SkMeshes. The buffer may be CPU- or GPU-backed + * depending on whether GrDirectContext* is nullptr. + * + * @param GrDirectContext* If nullptr a CPU-backed object is returned. Otherwise, the data is + * uploaded to the GPU and a GPU-backed buffer is returned. It may + * only be used to draw into SkSurfaces that are backed by the passed + * GrDirectContext. + * @param data The data used to populate the buffer, or nullptr to create a zero- + * initialized buffer. + * @param size Both the size of the data in 'data' and the size of the resulting + * buffer. + */ + static sk_sp MakeIndexBuffer(GrDirectContext*, const void* data, size_t size); + + /** + * Makes a copy of an index buffer. The implementation currently only supports a CPU-backed + * source buffer. + */ + static sk_sp CopyIndexBuffer(GrDirectContext*, sk_sp); + + /** + * Makes a vertex buffer to be used with SkMeshes. The buffer may be CPU- or GPU-backed + * depending on whether GrDirectContext* is nullptr. + * + * @param GrDirectContext* If nullptr a CPU-backed object is returned. Otherwise, the data is + * uploaded to the GPU and a GPU-backed buffer is returned. It may + * only be used to draw into SkSurfaces that are backed by the passed + * GrDirectContext. + * @param data The data used to populate the buffer, or nullptr to create a zero- + * initialized buffer. + * @param size Both the size of the data in 'data' and the size of the resulting + * buffer. + */ + static sk_sp MakeVertexBuffer(GrDirectContext*, const void*, size_t size); + + /** + * Makes a copy of a vertex buffer. The implementation currently only supports a CPU-backed + * source buffer. + */ + static sk_sp CopyVertexBuffer(GrDirectContext*, sk_sp); + + enum class Mode { kTriangles, kTriangleStrip }; + + struct Result; + + /** + * Creates a non-indexed SkMesh. The returned SkMesh can be tested for validity using + * SkMesh::isValid(). An invalid mesh simply fails to draws if passed to SkCanvas::drawMesh(). + * If the mesh is invalid the returned string give contain the reason for the failure (e.g. the + * vertex buffer was null or uniform data too small). + */ + static Result Make(sk_sp, + Mode, + sk_sp, + size_t vertexCount, + size_t vertexOffset, + sk_sp uniforms, + const SkRect& bounds); + + /** + * Creates an indexed SkMesh. The returned SkMesh can be tested for validity using + * SkMesh::isValid(). A invalid mesh simply fails to draw if passed to SkCanvas::drawMesh(). + * If the mesh is invalid the returned string give contain the reason for the failure (e.g. the + * index buffer was null or uniform data too small). + */ + static Result MakeIndexed(sk_sp, + Mode, + sk_sp, + size_t vertexCount, + size_t vertexOffset, + sk_sp, + size_t indexCount, + size_t indexOffset, + sk_sp uniforms, + const SkRect& bounds); + + sk_sp refSpec() const { return fSpec; } + SkMeshSpecification* spec() const { return fSpec.get(); } + + Mode mode() const { return fMode; } + + sk_sp refVertexBuffer() const { return fVB; } + VertexBuffer* vertexBuffer() const { return fVB.get(); } + + size_t vertexOffset() const { return fVOffset; } + size_t vertexCount() const { return fVCount; } + + sk_sp refIndexBuffer() const { return fIB; } + IndexBuffer* indexBuffer() const { return fIB.get(); } + + size_t indexOffset() const { return fIOffset; } + size_t indexCount() const { return fICount; } + + sk_sp refUniforms() const { return fUniforms; } + const SkData* uniforms() const { return fUniforms.get(); } + + SkRect bounds() const { return fBounds; } + + bool isValid() const; + +private: + friend struct SkMeshPriv; + + std::tuple validate() const; + + sk_sp fSpec; + + sk_sp fVB; + sk_sp fIB; + + sk_sp fUniforms; + + size_t fVOffset = 0; // Must be a multiple of spec->stride() + size_t fVCount = 0; + + size_t fIOffset = 0; // Must be a multiple of sizeof(uint16_t) + size_t fICount = 0; + + Mode fMode = Mode::kTriangles; + + SkRect fBounds = SkRect::MakeEmpty(); +}; + +struct SkMesh::Result { SkMesh mesh; SkString error; }; + +#endif // SK_ENABLE_SKSL + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMilestone.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMilestone.h new file mode 100644 index 00000000000000..398de57d0c59fa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkMilestone.h @@ -0,0 +1,9 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SK_MILESTONE +#define SK_MILESTONE 114 +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkOpenTypeSVGDecoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkOpenTypeSVGDecoder.h new file mode 100644 index 00000000000000..5a2e48a9df11aa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkOpenTypeSVGDecoder.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOpenTypeSVGDecoder_DEFINED +#define SkOpenTypeSVGDecoder_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkSpan.h" +#include "include/core/SkTypes.h" + +#include + +class SkCanvas; + +class SkOpenTypeSVGDecoder { +public: + /** Each instance probably owns an SVG DOM. + * The instance may be cached so needs to report how much memory it retains. + */ + virtual size_t approximateSize() = 0; + virtual bool render(SkCanvas&, int upem, SkGlyphID glyphId, + SkColor foregroundColor, SkSpan palette) = 0; + virtual ~SkOpenTypeSVGDecoder() = default; +}; + +#endif // SkOpenTypeSVGDecoder_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkOverdrawCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkOverdrawCanvas.h new file mode 100644 index 00000000000000..f3ffc0655663c5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkOverdrawCanvas.h @@ -0,0 +1,69 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOverdrawCanvas_DEFINED +#define SkOverdrawCanvas_DEFINED + +#include "include/core/SkCanvasVirtualEnforcer.h" +#include "include/utils/SkNWayCanvas.h" + +/** + * Captures all drawing commands. Rather than draw the actual content, this device + * increments the alpha channel of each pixel every time it would have been touched + * by a draw call. This is useful for detecting overdraw. + */ +class SK_API SkOverdrawCanvas : public SkCanvasVirtualEnforcer { +public: + /* Does not take ownership of canvas */ + SkOverdrawCanvas(SkCanvas*); + + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override; + void onDrawGlyphRunList( + const sktext::GlyphRunList& glyphRunList, const SkPaint& paint) override; + void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&) override; + void onDrawPaint(const SkPaint&) override; + void onDrawBehind(const SkPaint& paint) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + + void onDrawImage2(const SkImage*, SkScalar, SkScalar, const SkSamplingOptions&, + const SkPaint*) override; + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, + const SkPaint*, SrcRectConstraint) override; + void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect&, SkFilterMode, + const SkPaint*) override; + void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override; + + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + + void onDrawAnnotation(const SkRect&, const char key[], SkData* value) override; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], SkCanvas::QuadAAFlags, const SkColor4f&, + SkBlendMode) override; + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int count, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&,const SkPaint*, SrcRectConstraint) override; + +private: + inline SkPaint overdrawPaint(const SkPaint& paint); + + SkPaint fPaint; + + using INHERITED = SkCanvasVirtualEnforcer; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPaint.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPaint.h new file mode 100644 index 00000000000000..157dbb59d8d6c2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPaint.h @@ -0,0 +1,695 @@ +/* + * 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 SkPaint_DEFINED +#define SkPaint_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" +#include "include/private/base/SkFloatingPoint.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" + +#include +#include +#include + +class SkBlender; +class SkColorFilter; +class SkColorSpace; +class SkImageFilter; +class SkMaskFilter; +class SkPathEffect; +class SkShader; +enum class SkBlendMode; +struct SkRect; + +/** \class SkPaint + SkPaint controls options applied when drawing. SkPaint collects all + options outside of the SkCanvas clip and SkCanvas matrix. + + Various options apply to strokes and fills, and images. + + SkPaint collects effects and filters that describe single-pass and multiple-pass + algorithms that alter the drawing geometry, color, and transparency. For instance, + SkPaint does not directly implement dashing or blur, but contains the objects that do so. +*/ +class SK_API SkPaint { +public: + + /** Constructs SkPaint with default values. + + @return default initialized SkPaint + + example: https://fiddle.skia.org/c/@Paint_empty_constructor + */ + SkPaint(); + + /** Constructs SkPaint with default values and the given color. + + Sets alpha and RGB used when stroking and filling. The color is four floating + point values, unpremultiplied. The color values are interpreted as being in + the colorSpace. If colorSpace is nullptr, then color is assumed to be in the + sRGB color space. + + @param color unpremultiplied RGBA + @param colorSpace SkColorSpace describing the encoding of color + @return SkPaint with the given color + */ + explicit SkPaint(const SkColor4f& color, SkColorSpace* colorSpace = nullptr); + + /** Makes a shallow copy of SkPaint. SkPathEffect, SkShader, + SkMaskFilter, SkColorFilter, and SkImageFilter are shared + between the original paint and the copy. Objects containing SkRefCnt increment + their references by one. + + The referenced objects SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, + and SkImageFilter cannot be modified after they are created. + This prevents objects with SkRefCnt from being modified once SkPaint refers to them. + + @param paint original to copy + @return shallow copy of paint + + example: https://fiddle.skia.org/c/@Paint_copy_const_SkPaint + */ + SkPaint(const SkPaint& paint); + + /** Implements a move constructor to avoid increasing the reference counts + of objects referenced by the paint. + + After the call, paint is undefined, and can be safely destructed. + + @param paint original to move + @return content of paint + + example: https://fiddle.skia.org/c/@Paint_move_SkPaint + */ + SkPaint(SkPaint&& paint); + + /** Decreases SkPaint SkRefCnt of owned objects: SkPathEffect, SkShader, + SkMaskFilter, SkColorFilter, and SkImageFilter. If the + objects containing SkRefCnt go to zero, they are deleted. + */ + ~SkPaint(); + + /** Makes a shallow copy of SkPaint. SkPathEffect, SkShader, + SkMaskFilter, SkColorFilter, and SkImageFilter are shared + between the original paint and the copy. Objects containing SkRefCnt in the + prior destination are decreased by one, and the referenced objects are deleted if the + resulting count is zero. Objects containing SkRefCnt in the parameter paint + are increased by one. paint is unmodified. + + @param paint original to copy + @return content of paint + + example: https://fiddle.skia.org/c/@Paint_copy_operator + */ + SkPaint& operator=(const SkPaint& paint); + + /** Moves the paint to avoid increasing the reference counts + of objects referenced by the paint parameter. Objects containing SkRefCnt in the + prior destination are decreased by one; those objects are deleted if the resulting count + is zero. + + After the call, paint is undefined, and can be safely destructed. + + @param paint original to move + @return content of paint + + example: https://fiddle.skia.org/c/@Paint_move_operator + */ + SkPaint& operator=(SkPaint&& paint); + + /** Compares a and b, and returns true if a and b are equivalent. May return false + if SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, + or SkImageFilter have identical contents but different pointers. + + @param a SkPaint to compare + @param b SkPaint to compare + @return true if SkPaint pair are equivalent + */ + SK_API friend bool operator==(const SkPaint& a, const SkPaint& b); + + /** Compares a and b, and returns true if a and b are not equivalent. May return true + if SkPathEffect, SkShader, SkMaskFilter, SkColorFilter, + or SkImageFilter have identical contents but different pointers. + + @param a SkPaint to compare + @param b SkPaint to compare + @return true if SkPaint pair are not equivalent + */ + friend bool operator!=(const SkPaint& a, const SkPaint& b) { + return !(a == b); + } + + /** Sets all SkPaint contents to their initial values. This is equivalent to replacing + SkPaint with the result of SkPaint(). + + example: https://fiddle.skia.org/c/@Paint_reset + */ + void reset(); + + /** Returns true if pixels on the active edges of SkPath may be drawn with partial transparency. + @return antialiasing state + */ + bool isAntiAlias() const { + return SkToBool(fBitfields.fAntiAlias); + } + + /** Requests, but does not require, that edge pixels draw opaque or with + partial transparency. + @param aa setting for antialiasing + */ + void setAntiAlias(bool aa) { fBitfields.fAntiAlias = static_cast(aa); } + + /** Returns true if color error may be distributed to smooth color transition. + @return dithering state + */ + bool isDither() const { + return SkToBool(fBitfields.fDither); + } + + /** Requests, but does not require, to distribute color error. + @param dither setting for ditering + */ + void setDither(bool dither) { fBitfields.fDither = static_cast(dither); } + + /** \enum SkPaint::Style + Set Style to fill, stroke, or both fill and stroke geometry. + The stroke and fill + share all paint attributes; for instance, they are drawn with the same color. + + Use kStrokeAndFill_Style to avoid hitting the same pixels twice with a stroke draw and + a fill draw. + */ + enum Style : uint8_t { + kFill_Style, //!< set to fill geometry + kStroke_Style, //!< set to stroke geometry + kStrokeAndFill_Style, //!< sets to stroke and fill geometry + }; + + /** May be used to verify that SkPaint::Style is a legal value. + */ + static constexpr int kStyleCount = kStrokeAndFill_Style + 1; + + /** Returns whether the geometry is filled, stroked, or filled and stroked. + */ + Style getStyle() const { return (Style)fBitfields.fStyle; } + + /** Sets whether the geometry is filled, stroked, or filled and stroked. + Has no effect if style is not a legal SkPaint::Style value. + + example: https://fiddle.skia.org/c/@Paint_setStyle + example: https://fiddle.skia.org/c/@Stroke_Width + */ + void setStyle(Style style); + + /** + * Set paint's style to kStroke if true, or kFill if false. + */ + void setStroke(bool); + + /** Retrieves alpha and RGB, unpremultiplied, packed into 32 bits. + Use helpers SkColorGetA(), SkColorGetR(), SkColorGetG(), and SkColorGetB() to extract + a color component. + + @return unpremultiplied ARGB + */ + SkColor getColor() const { return fColor4f.toSkColor(); } + + /** Retrieves alpha and RGB, unpremultiplied, as four floating point values. RGB are + extended sRGB values (sRGB gamut, and encoded with the sRGB transfer function). + + @return unpremultiplied RGBA + */ + SkColor4f getColor4f() const { return fColor4f; } + + /** Sets alpha and RGB used when stroking and filling. The color is a 32-bit value, + unpremultiplied, packing 8-bit components for alpha, red, blue, and green. + + @param color unpremultiplied ARGB + + example: https://fiddle.skia.org/c/@Paint_setColor + */ + void setColor(SkColor color); + + /** Sets alpha and RGB used when stroking and filling. The color is four floating + point values, unpremultiplied. The color values are interpreted as being in + the colorSpace. If colorSpace is nullptr, then color is assumed to be in the + sRGB color space. + + @param color unpremultiplied RGBA + @param colorSpace SkColorSpace describing the encoding of color + */ + void setColor(const SkColor4f& color, SkColorSpace* colorSpace = nullptr); + + void setColor4f(const SkColor4f& color, SkColorSpace* colorSpace = nullptr) { + this->setColor(color, colorSpace); + } + + /** Retrieves alpha from the color used when stroking and filling. + + @return alpha ranging from zero, fully transparent, to one, fully opaque + */ + float getAlphaf() const { return fColor4f.fA; } + + // Helper that scales the alpha by 255. + uint8_t getAlpha() const { + return static_cast(sk_float_round2int(this->getAlphaf() * 255)); + } + + /** Replaces alpha, leaving RGB + unchanged. An out of range value triggers an assert in the debug + build. a is a value from 0.0 to 1.0. + a set to zero makes color fully transparent; a set to 1.0 makes color + fully opaque. + + @param a alpha component of color + */ + void setAlphaf(float a); + + // Helper that accepts an int between 0 and 255, and divides it by 255.0 + void setAlpha(U8CPU a) { + this->setAlphaf(a * (1.0f / 255)); + } + + /** Sets color used when drawing solid fills. The color components range from 0 to 255. + The color is unpremultiplied; alpha sets the transparency independent of RGB. + + @param a amount of alpha, from fully transparent (0) to fully opaque (255) + @param r amount of red, from no red (0) to full red (255) + @param g amount of green, from no green (0) to full green (255) + @param b amount of blue, from no blue (0) to full blue (255) + + example: https://fiddle.skia.org/c/@Paint_setARGB + */ + void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); + + /** Returns the thickness of the pen used by SkPaint to + outline the shape. + + @return zero for hairline, greater than zero for pen thickness + */ + SkScalar getStrokeWidth() const { return fWidth; } + + /** Sets the thickness of the pen used by the paint to outline the shape. + A stroke-width of zero is treated as "hairline" width. Hairlines are always exactly one + pixel wide in device space (their thickness does not change as the canvas is scaled). + Negative stroke-widths are invalid; setting a negative width will have no effect. + + @param width zero thickness for hairline; greater than zero for pen thickness + + example: https://fiddle.skia.org/c/@Miter_Limit + example: https://fiddle.skia.org/c/@Paint_setStrokeWidth + */ + void setStrokeWidth(SkScalar width); + + /** Returns the limit at which a sharp corner is drawn beveled. + + @return zero and greater miter limit + */ + SkScalar getStrokeMiter() const { return fMiterLimit; } + + /** Sets the limit at which a sharp corner is drawn beveled. + Valid values are zero and greater. + Has no effect if miter is less than zero. + + @param miter zero and greater miter limit + + example: https://fiddle.skia.org/c/@Paint_setStrokeMiter + */ + void setStrokeMiter(SkScalar miter); + + /** \enum SkPaint::Cap + Cap draws at the beginning and end of an open path contour. + */ + enum Cap { + kButt_Cap, //!< no stroke extension + kRound_Cap, //!< adds circle + kSquare_Cap, //!< adds square + kLast_Cap = kSquare_Cap, //!< largest Cap value + kDefault_Cap = kButt_Cap, //!< equivalent to kButt_Cap + }; + + /** May be used to verify that SkPaint::Cap is a legal value. + */ + static constexpr int kCapCount = kLast_Cap + 1; + + /** \enum SkPaint::Join + Join specifies how corners are drawn when a shape is stroked. Join + affects the four corners of a stroked rectangle, and the connected segments in a + stroked path. + + Choose miter join to draw sharp corners. Choose round join to draw a circle with a + radius equal to the stroke width on top of the corner. Choose bevel join to minimally + connect the thick strokes. + + The fill path constructed to describe the stroked path respects the join setting but may + not contain the actual join. For instance, a fill path constructed with round joins does + not necessarily include circles at each connected segment. + */ + enum Join : uint8_t { + kMiter_Join, //!< extends to miter limit + kRound_Join, //!< adds circle + kBevel_Join, //!< connects outside edges + kLast_Join = kBevel_Join, //!< equivalent to the largest value for Join + kDefault_Join = kMiter_Join, //!< equivalent to kMiter_Join + }; + + /** May be used to verify that SkPaint::Join is a legal value. + */ + static constexpr int kJoinCount = kLast_Join + 1; + + /** Returns the geometry drawn at the beginning and end of strokes. + */ + Cap getStrokeCap() const { return (Cap)fBitfields.fCapType; } + + /** Sets the geometry drawn at the beginning and end of strokes. + + example: https://fiddle.skia.org/c/@Paint_setStrokeCap_a + example: https://fiddle.skia.org/c/@Paint_setStrokeCap_b + */ + void setStrokeCap(Cap cap); + + /** Returns the geometry drawn at the corners of strokes. + */ + Join getStrokeJoin() const { return (Join)fBitfields.fJoinType; } + + /** Sets the geometry drawn at the corners of strokes. + + example: https://fiddle.skia.org/c/@Paint_setStrokeJoin + */ + void setStrokeJoin(Join join); + + /** Returns optional colors used when filling a path, such as a gradient. + + Does not alter SkShader SkRefCnt. + + @return SkShader if previously set, nullptr otherwise + */ + SkShader* getShader() const { return fShader.get(); } + + /** Returns optional colors used when filling a path, such as a gradient. + + Increases SkShader SkRefCnt by one. + + @return SkShader if previously set, nullptr otherwise + + example: https://fiddle.skia.org/c/@Paint_refShader + */ + sk_sp refShader() const; + + /** Sets optional colors used when filling a path, such as a gradient. + + Sets SkShader to shader, decreasing SkRefCnt of the previous SkShader. + Increments shader SkRefCnt by one. + + @param shader how geometry is filled with color; if nullptr, color is used instead + + example: https://fiddle.skia.org/c/@Color_Filter_Methods + example: https://fiddle.skia.org/c/@Paint_setShader + */ + void setShader(sk_sp shader); + + /** Returns SkColorFilter if set, or nullptr. + Does not alter SkColorFilter SkRefCnt. + + @return SkColorFilter if previously set, nullptr otherwise + */ + SkColorFilter* getColorFilter() const { return fColorFilter.get(); } + + /** Returns SkColorFilter if set, or nullptr. + Increases SkColorFilter SkRefCnt by one. + + @return SkColorFilter if set, or nullptr + + example: https://fiddle.skia.org/c/@Paint_refColorFilter + */ + sk_sp refColorFilter() const; + + /** Sets SkColorFilter to filter, decreasing SkRefCnt of the previous + SkColorFilter. Pass nullptr to clear SkColorFilter. + + Increments filter SkRefCnt by one. + + @param colorFilter SkColorFilter to apply to subsequent draw + + example: https://fiddle.skia.org/c/@Blend_Mode_Methods + example: https://fiddle.skia.org/c/@Paint_setColorFilter + */ + void setColorFilter(sk_sp colorFilter); + + /** If the current blender can be represented as a SkBlendMode enum, this returns that + * enum in the optional's value(). If it cannot, then the returned optional does not + * contain a value. + */ + std::optional asBlendMode() const; + + /** + * Queries the blender, and if it can be represented as a SkBlendMode, return that mode, + * else return the defaultMode provided. + */ + SkBlendMode getBlendMode_or(SkBlendMode defaultMode) const; + + /** Returns true iff the current blender claims to be equivalent to SkBlendMode::kSrcOver. + * + * Also returns true of the current blender is nullptr. + */ + bool isSrcOver() const; + + /** Helper method for calling setBlender(). + * + * This sets a blender that implements the specified blendmode enum. + */ + void setBlendMode(SkBlendMode mode); + + /** Returns the user-supplied blend function, if one has been set. + * Does not alter SkBlender's SkRefCnt. + * + * A nullptr blender signifies the default SrcOver behavior. + * + * @return the SkBlender assigned to this paint, otherwise nullptr + */ + SkBlender* getBlender() const { return fBlender.get(); } + + /** Returns the user-supplied blend function, if one has been set. + * Increments the SkBlender's SkRefCnt by one. + * + * A nullptr blender signifies the default SrcOver behavior. + * + * @return the SkBlender assigned to this paint, otherwise nullptr + */ + sk_sp refBlender() const; + + /** Sets the current blender, increasing its refcnt, and if a blender is already + * present, decreasing that object's refcnt. + * + * A nullptr blender signifies the default SrcOver behavior. + * + * For convenience, you can call setBlendMode() if the blend effect can be expressed + * as one of those values. + */ + void setBlender(sk_sp blender); + + /** Returns SkPathEffect if set, or nullptr. + Does not alter SkPathEffect SkRefCnt. + + @return SkPathEffect if previously set, nullptr otherwise + */ + SkPathEffect* getPathEffect() const { return fPathEffect.get(); } + + /** Returns SkPathEffect if set, or nullptr. + Increases SkPathEffect SkRefCnt by one. + + @return SkPathEffect if previously set, nullptr otherwise + + example: https://fiddle.skia.org/c/@Paint_refPathEffect + */ + sk_sp refPathEffect() const; + + /** Sets SkPathEffect to pathEffect, decreasing SkRefCnt of the previous + SkPathEffect. Pass nullptr to leave the path geometry unaltered. + + Increments pathEffect SkRefCnt by one. + + @param pathEffect replace SkPath with a modification when drawn + + example: https://fiddle.skia.org/c/@Mask_Filter_Methods + example: https://fiddle.skia.org/c/@Paint_setPathEffect + */ + void setPathEffect(sk_sp pathEffect); + + /** Returns SkMaskFilter if set, or nullptr. + Does not alter SkMaskFilter SkRefCnt. + + @return SkMaskFilter if previously set, nullptr otherwise + */ + SkMaskFilter* getMaskFilter() const { return fMaskFilter.get(); } + + /** Returns SkMaskFilter if set, or nullptr. + + Increases SkMaskFilter SkRefCnt by one. + + @return SkMaskFilter if previously set, nullptr otherwise + + example: https://fiddle.skia.org/c/@Paint_refMaskFilter + */ + sk_sp refMaskFilter() const; + + /** Sets SkMaskFilter to maskFilter, decreasing SkRefCnt of the previous + SkMaskFilter. Pass nullptr to clear SkMaskFilter and leave SkMaskFilter effect on + mask alpha unaltered. + + Increments maskFilter SkRefCnt by one. + + @param maskFilter modifies clipping mask generated from drawn geometry + + example: https://fiddle.skia.org/c/@Paint_setMaskFilter + example: https://fiddle.skia.org/c/@Typeface_Methods + */ + void setMaskFilter(sk_sp maskFilter); + + /** Returns SkImageFilter if set, or nullptr. + Does not alter SkImageFilter SkRefCnt. + + @return SkImageFilter if previously set, nullptr otherwise + */ + SkImageFilter* getImageFilter() const { return fImageFilter.get(); } + + /** Returns SkImageFilter if set, or nullptr. + Increases SkImageFilter SkRefCnt by one. + + @return SkImageFilter if previously set, nullptr otherwise + + example: https://fiddle.skia.org/c/@Paint_refImageFilter + */ + sk_sp refImageFilter() const; + + /** Sets SkImageFilter to imageFilter, decreasing SkRefCnt of the previous + SkImageFilter. Pass nullptr to clear SkImageFilter, and remove SkImageFilter effect + on drawing. + + Increments imageFilter SkRefCnt by one. + + @param imageFilter how SkImage is sampled when transformed + + example: https://fiddle.skia.org/c/@Paint_setImageFilter + */ + void setImageFilter(sk_sp imageFilter); + + /** Returns true if SkPaint prevents all drawing; + otherwise, the SkPaint may or may not allow drawing. + + Returns true if, for example, SkBlendMode combined with alpha computes a + new alpha of zero. + + @return true if SkPaint prevents all drawing + + example: https://fiddle.skia.org/c/@Paint_nothingToDraw + */ + bool nothingToDraw() const; + + /** (to be made private) + Returns true if SkPaint does not include elements requiring extensive computation + to compute SkBaseDevice bounds of drawn geometry. For instance, SkPaint with SkPathEffect + always returns false. + + @return true if SkPaint allows for fast computation of bounds + */ + bool canComputeFastBounds() const; + + /** (to be made private) + Only call this if canComputeFastBounds() returned true. This takes a + raw rectangle (the raw bounds of a shape), and adjusts it for stylistic + effects in the paint (e.g. stroking). If needed, it uses the storage + parameter. It returns the adjusted bounds that can then be used + for SkCanvas::quickReject tests. + + The returned SkRect will either be orig or storage, thus the caller + should not rely on storage being set to the result, but should always + use the returned value. It is legal for orig and storage to be the same + SkRect. + For example: + if (!path.isInverseFillType() && paint.canComputeFastBounds()) { + SkRect storage; + if (canvas->quickReject(paint.computeFastBounds(path.getBounds(), &storage))) { + return; // do not draw the path + } + } + // draw the path + + @param orig geometry modified by SkPaint when drawn + @param storage computed bounds of geometry; may not be nullptr + @return fast computed bounds + */ + const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const; + + /** (to be made private) + + @param orig geometry modified by SkPaint when drawn + @param storage computed bounds of geometry + @return fast computed bounds + */ + const SkRect& computeFastStrokeBounds(const SkRect& orig, + SkRect* storage) const { + return this->doComputeFastBounds(orig, storage, kStroke_Style); + } + + /** (to be made private) + Computes the bounds, overriding the SkPaint SkPaint::Style. This can be used to + account for additional width required by stroking orig, without + altering SkPaint::Style set to fill. + + @param orig geometry modified by SkPaint when drawn + @param storage computed bounds of geometry + @param style overrides SkPaint::Style + @return fast computed bounds + */ + const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage, + Style style) const; + + using sk_is_trivially_relocatable = std::true_type; + +private: + sk_sp fPathEffect; + sk_sp fShader; + sk_sp fMaskFilter; + sk_sp fColorFilter; + sk_sp fImageFilter; + sk_sp fBlender; + + SkColor4f fColor4f; + SkScalar fWidth; + SkScalar fMiterLimit; + union { + struct { + unsigned fAntiAlias : 1; + unsigned fDither : 1; + unsigned fCapType : 2; + unsigned fJoinType : 2; + unsigned fStyle : 2; + unsigned fPadding : 24; // 24 == 32 -1-1-2-2-2 + } fBitfields; + uint32_t fBitfieldsUInt; + }; + + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + + friend class SkPaintPriv; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPath.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPath.h new file mode 100644 index 00000000000000..0b69dd2b6fd95b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPath.h @@ -0,0 +1,1901 @@ +/* + * 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 SkPath_DEFINED +#define SkPath_DEFINED + +#include "include/core/SkMatrix.h" +#include "include/core/SkPathTypes.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" + +#include +#include +#include +#include +#include +#include + +class SkData; +class SkPathRef; +class SkRRect; +class SkWStream; +enum class SkPathConvexity; +enum class SkPathFirstDirection; +struct SkPathVerbAnalysis; + +// WIP -- define this locally, and fix call-sites to use SkPathBuilder (skbug.com/9000) +//#define SK_HIDE_PATH_EDIT_METHODS + +/** \class SkPath + SkPath contain geometry. SkPath may be empty, or contain one or more verbs that + outline a figure. SkPath always starts with a move verb to a Cartesian coordinate, + and may be followed by additional verbs that add lines or curves. + Adding a close verb makes the geometry into a continuous loop, a closed contour. + SkPath may contain any number of contours, each beginning with a move verb. + + SkPath contours may contain only a move verb, or may also contain lines, + quadratic beziers, conics, and cubic beziers. SkPath contours may be open or + closed. + + When used to draw a filled area, SkPath describes whether the fill is inside or + outside the geometry. SkPath also describes the winding rule used to fill + overlapping contours. + + Internally, SkPath lazily computes metrics likes bounds and convexity. Call + SkPath::updateBoundsCache to make SkPath thread safe. +*/ +class SK_API SkPath { +public: + /** + * Create a new path with the specified segments. + * + * The points and weights arrays are read in order, based on the sequence of verbs. + * + * Move 1 point + * Line 1 point + * Quad 2 points + * Conic 2 points and 1 weight + * Cubic 3 points + * Close 0 points + * + * If an illegal sequence of verbs is encountered, or the specified number of points + * or weights is not sufficient given the verbs, an empty Path is returned. + * + * A legal sequence of verbs consists of any number of Contours. A contour always begins + * with a Move verb, followed by 0 or more segments: Line, Quad, Conic, Cubic, followed + * by an optional Close. + */ + static SkPath Make(const SkPoint[], int pointCount, + const uint8_t[], int verbCount, + const SkScalar[], int conicWeightCount, + SkPathFillType, bool isVolatile = false); + + static SkPath Rect(const SkRect&, SkPathDirection = SkPathDirection::kCW, + unsigned startIndex = 0); + static SkPath Oval(const SkRect&, SkPathDirection = SkPathDirection::kCW); + static SkPath Oval(const SkRect&, SkPathDirection, unsigned startIndex); + static SkPath Circle(SkScalar center_x, SkScalar center_y, SkScalar radius, + SkPathDirection dir = SkPathDirection::kCW); + static SkPath RRect(const SkRRect&, SkPathDirection dir = SkPathDirection::kCW); + static SkPath RRect(const SkRRect&, SkPathDirection, unsigned startIndex); + static SkPath RRect(const SkRect& bounds, SkScalar rx, SkScalar ry, + SkPathDirection dir = SkPathDirection::kCW); + + static SkPath Polygon(const SkPoint pts[], int count, bool isClosed, + SkPathFillType = SkPathFillType::kWinding, + bool isVolatile = false); + + static SkPath Polygon(const std::initializer_list& list, bool isClosed, + SkPathFillType fillType = SkPathFillType::kWinding, + bool isVolatile = false) { + return Polygon(list.begin(), SkToInt(list.size()), isClosed, fillType, isVolatile); + } + + static SkPath Line(const SkPoint a, const SkPoint b) { + return Polygon({a, b}, false); + } + + /** Constructs an empty SkPath. By default, SkPath has no verbs, no SkPoint, and no weights. + FillType is set to kWinding. + + @return empty SkPath + + example: https://fiddle.skia.org/c/@Path_empty_constructor + */ + SkPath(); + + /** Constructs a copy of an existing path. + Copy constructor makes two paths identical by value. Internally, path and + the returned result share pointer values. The underlying verb array, SkPoint array + and weights are copied when modified. + + Creating a SkPath copy is very efficient and never allocates memory. + SkPath are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param path SkPath to copy by value + @return copy of SkPath + + example: https://fiddle.skia.org/c/@Path_copy_const_SkPath + */ + SkPath(const SkPath& path); + + /** Releases ownership of any shared data and deletes data if SkPath is sole owner. + + example: https://fiddle.skia.org/c/@Path_destructor + */ + ~SkPath(); + + /** Constructs a copy of an existing path. + SkPath assignment makes two paths identical by value. Internally, assignment + shares pointer values. The underlying verb array, SkPoint array and weights + are copied when modified. + + Copying SkPath by assignment is very efficient and never allocates memory. + SkPath are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param path verb array, SkPoint array, weights, and SkPath::FillType to copy + @return SkPath copied by value + + example: https://fiddle.skia.org/c/@Path_copy_operator + */ + SkPath& operator=(const SkPath& path); + + /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights + are equivalent. + + @param a SkPath to compare + @param b SkPath to compare + @return true if SkPath pair are equivalent + */ + friend SK_API bool operator==(const SkPath& a, const SkPath& b); + + /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights + are not equivalent. + + @param a SkPath to compare + @param b SkPath to compare + @return true if SkPath pair are not equivalent + */ + friend bool operator!=(const SkPath& a, const SkPath& b) { + return !(a == b); + } + + /** Returns true if SkPath contain equal verbs and equal weights. + If SkPath contain one or more conics, the weights must match. + + conicTo() may add different verbs depending on conic weight, so it is not + trivial to interpolate a pair of SkPath containing conics with different + conic weight values. + + @param compare SkPath to compare + @return true if SkPath verb array and weights are equivalent + + example: https://fiddle.skia.org/c/@Path_isInterpolatable + */ + bool isInterpolatable(const SkPath& compare) const; + + /** Interpolates between SkPath with SkPoint array of equal size. + Copy verb array and weights to out, and set out SkPoint array to a weighted + average of this SkPoint array and ending SkPoint array, using the formula: + (Path Point * weight) + ending Point * (1 - weight). + + weight is most useful when between zero (ending SkPoint array) and + one (this Point_Array); will work with values outside of this + range. + + interpolate() returns false and leaves out unchanged if SkPoint array is not + the same size as ending SkPoint array. Call isInterpolatable() to check SkPath + compatibility prior to calling interpolate(). + + @param ending SkPoint array averaged with this SkPoint array + @param weight contribution of this SkPoint array, and + one minus contribution of ending SkPoint array + @param out SkPath replaced by interpolated averages + @return true if SkPath contain same number of SkPoint + + example: https://fiddle.skia.org/c/@Path_interpolate + */ + bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const; + + /** Returns SkPathFillType, the rule used to fill SkPath. + + @return current SkPathFillType setting + */ + SkPathFillType getFillType() const { return (SkPathFillType)fFillType; } + + /** Sets FillType, the rule used to fill SkPath. While there is no check + that ft is legal, values outside of FillType are not supported. + */ + void setFillType(SkPathFillType ft) { + fFillType = SkToU8(ft); + } + + /** Returns if FillType describes area outside SkPath geometry. The inverse fill area + extends indefinitely. + + @return true if FillType is kInverseWinding or kInverseEvenOdd + */ + bool isInverseFillType() const { return SkPathFillType_IsInverse(this->getFillType()); } + + /** Replaces FillType with its inverse. The inverse of FillType describes the area + unmodified by the original FillType. + */ + void toggleInverseFillType() { + fFillType ^= 2; + } + + /** Returns true if the path is convex. If necessary, it will first compute the convexity. + */ + bool isConvex() const; + + /** Returns true if this path is recognized as an oval or circle. + + bounds receives bounds of oval. + + bounds is unmodified if oval is not found. + + @param bounds storage for bounding SkRect of oval; may be nullptr + @return true if SkPath is recognized as an oval or circle + + example: https://fiddle.skia.org/c/@Path_isOval + */ + bool isOval(SkRect* bounds) const; + + /** Returns true if path is representable as SkRRect. + Returns false if path is representable as oval, circle, or SkRect. + + rrect receives bounds of SkRRect. + + rrect is unmodified if SkRRect is not found. + + @param rrect storage for bounding SkRect of SkRRect; may be nullptr + @return true if SkPath contains only SkRRect + + example: https://fiddle.skia.org/c/@Path_isRRect + */ + bool isRRect(SkRRect* rrect) const; + + /** Sets SkPath to its initial state. + Removes verb array, SkPoint array, and weights, and sets FillType to kWinding. + Internal storage associated with SkPath is released. + + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_reset + */ + SkPath& reset(); + + /** Sets SkPath to its initial state, preserving internal storage. + Removes verb array, SkPoint array, and weights, and sets FillType to kWinding. + Internal storage associated with SkPath is retained. + + Use rewind() instead of reset() if SkPath storage will be reused and performance + is critical. + + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_rewind + */ + SkPath& rewind(); + + /** Returns if SkPath is empty. + Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight. + SkPath() constructs empty SkPath; reset() and rewind() make SkPath empty. + + @return true if the path contains no SkPath::Verb array + */ + bool isEmpty() const; + + /** Returns if contour is closed. + Contour is closed if SkPath SkPath::Verb array was last modified by close(). When stroked, + closed contour draws SkPaint::Join instead of SkPaint::Cap at first and last SkPoint. + + @return true if the last contour ends with a kClose_Verb + + example: https://fiddle.skia.org/c/@Path_isLastContourClosed + */ + bool isLastContourClosed() const; + + /** Returns true for finite SkPoint array values between negative SK_ScalarMax and + positive SK_ScalarMax. Returns false for any SkPoint array value of + SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN. + + @return true if all SkPoint values are finite + */ + bool isFinite() const; + + /** Returns true if the path is volatile; it will not be altered or discarded + by the caller after it is drawn. SkPath by default have volatile set false, allowing + SkSurface to attach a cache of data which speeds repeated drawing. If true, SkSurface + may not speed repeated drawing. + + @return true if caller will alter SkPath after drawing + */ + bool isVolatile() const { + return SkToBool(fIsVolatile); + } + + /** Specifies whether SkPath is volatile; whether it will be altered or discarded + by the caller after it is drawn. SkPath by default have volatile set false, allowing + SkBaseDevice to attach a cache of data which speeds repeated drawing. + + Mark temporary paths, discarded or modified after use, as volatile + to inform SkBaseDevice that the path need not be cached. + + Mark animating SkPath volatile to improve performance. + Mark unchanging SkPath non-volatile to improve repeated rendering. + + raster surface SkPath draws are affected by volatile for some shadows. + GPU surface SkPath draws are affected by volatile for some shadows and concave geometries. + + @param isVolatile true if caller will alter SkPath after drawing + @return reference to SkPath + */ + SkPath& setIsVolatile(bool isVolatile) { + fIsVolatile = isVolatile; + return *this; + } + + /** Tests if line between SkPoint pair is degenerate. + Line with no length or that moves a very short distance is degenerate; it is + treated as a point. + + exact changes the equality test. If true, returns true only if p1 equals p2. + If false, returns true if p1 equals or nearly equals p2. + + @param p1 line start point + @param p2 line end point + @param exact if false, allow nearly equals + @return true if line is degenerate; its length is effectively zero + + example: https://fiddle.skia.org/c/@Path_IsLineDegenerate + */ + static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact); + + /** Tests if quad is degenerate. + Quad with no length or that moves a very short distance is degenerate; it is + treated as a point. + + @param p1 quad start point + @param p2 quad control point + @param p3 quad end point + @param exact if true, returns true only if p1, p2, and p3 are equal; + if false, returns true if p1, p2, and p3 are equal or nearly equal + @return true if quad is degenerate; its length is effectively zero + */ + static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, + const SkPoint& p3, bool exact); + + /** Tests if cubic is degenerate. + Cubic with no length or that moves a very short distance is degenerate; it is + treated as a point. + + @param p1 cubic start point + @param p2 cubic control point 1 + @param p3 cubic control point 2 + @param p4 cubic end point + @param exact if true, returns true only if p1, p2, p3, and p4 are equal; + if false, returns true if p1, p2, p3, and p4 are equal or nearly equal + @return true if cubic is degenerate; its length is effectively zero + */ + static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, + const SkPoint& p3, const SkPoint& p4, bool exact); + + /** Returns true if SkPath contains only one line; + SkPath::Verb array has two entries: kMove_Verb, kLine_Verb. + If SkPath contains one line and line is not nullptr, line is set to + line start point and line end point. + Returns false if SkPath is not one line; line is unaltered. + + @param line storage for line. May be nullptr + @return true if SkPath contains exactly one line + + example: https://fiddle.skia.org/c/@Path_isLine + */ + bool isLine(SkPoint line[2]) const; + + /** Returns the number of points in SkPath. + SkPoint count is initially zero. + + @return SkPath SkPoint array length + + example: https://fiddle.skia.org/c/@Path_countPoints + */ + int countPoints() const; + + /** Returns SkPoint at index in SkPoint array. Valid range for index is + 0 to countPoints() - 1. + Returns (0, 0) if index is out of range. + + @param index SkPoint array element selector + @return SkPoint array value or (0, 0) + + example: https://fiddle.skia.org/c/@Path_getPoint + */ + SkPoint getPoint(int index) const; + + /** Returns number of points in SkPath. Up to max points are copied. + points may be nullptr; then, max must be zero. + If max is greater than number of points, excess points storage is unaltered. + + @param points storage for SkPath SkPoint array. May be nullptr + @param max maximum to copy; must be greater than or equal to zero + @return SkPath SkPoint array length + + example: https://fiddle.skia.org/c/@Path_getPoints + */ + int getPoints(SkPoint points[], int max) const; + + /** Returns the number of verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb, + kCubic_Verb, and kClose_Verb; added to SkPath. + + @return length of verb array + + example: https://fiddle.skia.org/c/@Path_countVerbs + */ + int countVerbs() const; + + /** Returns the number of verbs in the path. Up to max verbs are copied. The + verbs are copied as one byte per verb. + + @param verbs storage for verbs, may be nullptr + @param max maximum number to copy into verbs + @return the actual number of verbs in the path + + example: https://fiddle.skia.org/c/@Path_getVerbs + */ + int getVerbs(uint8_t verbs[], int max) const; + + /** Returns the approximate byte size of the SkPath in memory. + + @return approximate size + */ + size_t approximateBytesUsed() const; + + /** Exchanges the verb array, SkPoint array, weights, and SkPath::FillType with other. + Cached state is also exchanged. swap() internally exchanges pointers, so + it is lightweight and does not allocate memory. + + swap() usage has largely been replaced by operator=(const SkPath& path). + SkPath do not copy their content on assignment until they are written to, + making assignment as efficient as swap(). + + @param other SkPath exchanged by value + + example: https://fiddle.skia.org/c/@Path_swap + */ + void swap(SkPath& other); + + /** Returns minimum and maximum axes values of SkPoint array. + Returns (0, 0, 0, 0) if SkPath contains no points. Returned bounds width and height may + be larger or smaller than area affected when SkPath is drawn. + + SkRect returned includes all SkPoint added to SkPath, including SkPoint associated with + kMove_Verb that define empty contours. + + @return bounds of all SkPoint in SkPoint array + */ + const SkRect& getBounds() const; + + /** Updates internal bounds so that subsequent calls to getBounds() are instantaneous. + Unaltered copies of SkPath may also access cached bounds through getBounds(). + + For now, identical to calling getBounds() and ignoring the returned value. + + Call to prepare SkPath subsequently drawn from multiple threads, + to avoid a race condition where each draw separately computes the bounds. + */ + void updateBoundsCache() const { + // for now, just calling getBounds() is sufficient + this->getBounds(); + } + + /** Returns minimum and maximum axes values of the lines and curves in SkPath. + Returns (0, 0, 0, 0) if SkPath contains no points. + Returned bounds width and height may be larger or smaller than area affected + when SkPath is drawn. + + Includes SkPoint associated with kMove_Verb that define empty + contours. + + Behaves identically to getBounds() when SkPath contains + only lines. If SkPath contains curves, computed bounds includes + the maximum extent of the quad, conic, or cubic; is slower than getBounds(); + and unlike getBounds(), does not cache the result. + + @return tight bounds of curves in SkPath + + example: https://fiddle.skia.org/c/@Path_computeTightBounds + */ + SkRect computeTightBounds() const; + + /** Returns true if rect is contained by SkPath. + May return false when rect is contained by SkPath. + + For now, only returns true if SkPath has one contour and is convex. + rect may share points and edges with SkPath and be contained. + Returns true if rect is empty, that is, it has zero width or height; and + the SkPoint or line described by rect is contained by SkPath. + + @param rect SkRect, line, or SkPoint checked for containment + @return true if rect is contained + + example: https://fiddle.skia.org/c/@Path_conservativelyContainsRect + */ + bool conservativelyContainsRect(const SkRect& rect) const; + + /** Grows SkPath verb array and SkPoint array to contain extraPtCount additional SkPoint. + May improve performance and use less memory by + reducing the number and size of allocations when creating SkPath. + + @param extraPtCount number of additional SkPoint to allocate + + example: https://fiddle.skia.org/c/@Path_incReserve + */ + void incReserve(int extraPtCount); + +#ifdef SK_HIDE_PATH_EDIT_METHODS +private: +#endif + + /** Adds beginning of contour at SkPoint (x, y). + + @param x x-axis value of contour start + @param y y-axis value of contour start + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_moveTo + */ + SkPath& moveTo(SkScalar x, SkScalar y); + + /** Adds beginning of contour at SkPoint p. + + @param p contour start + @return reference to SkPath + */ + SkPath& moveTo(const SkPoint& p) { + return this->moveTo(p.fX, p.fY); + } + + /** Adds beginning of contour relative to last point. + If SkPath is empty, starts contour at (dx, dy). + Otherwise, start contour at last point offset by (dx, dy). + Function name stands for "relative move to". + + @param dx offset from last point to contour start on x-axis + @param dy offset from last point to contour start on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_rMoveTo + */ + SkPath& rMoveTo(SkScalar dx, SkScalar dy); + + /** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. + + lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint array. + + @param x end of added line on x-axis + @param y end of added line on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_lineTo + */ + SkPath& lineTo(SkScalar x, SkScalar y); + + /** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. + + lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint array. + + @param p end SkPoint of added line + @return reference to SkPath + */ + SkPath& lineTo(const SkPoint& p) { + return this->lineTo(p.fX, p.fY); + } + + /** Adds line from last point to vector (dx, dy). If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kLine_Verb to verb array and line end to SkPoint array. + Line end is last point plus vector (dx, dy). + Function name stands for "relative line to". + + @param dx offset from last point to line end on x-axis + @param dy offset from last point to line end on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_rLineTo + example: https://fiddle.skia.org/c/@Quad_a + example: https://fiddle.skia.org/c/@Quad_b + */ + SkPath& rLineTo(SkScalar dx, SkScalar dy); + + /** Adds quad from last point towards (x1, y1), to (x2, y2). + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding quad. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2) + to SkPoint array. + + @param x1 control SkPoint of quad on x-axis + @param y1 control SkPoint of quad on y-axis + @param x2 end SkPoint of quad on x-axis + @param y2 end SkPoint of quad on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_quadTo + */ + SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); + + /** Adds quad from last point towards SkPoint p1, to SkPoint p2. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding quad. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kQuad_Verb to verb array; and SkPoint p1, p2 + to SkPoint array. + + @param p1 control SkPoint of added quad + @param p2 end SkPoint of added quad + @return reference to SkPath + */ + SkPath& quadTo(const SkPoint& p1, const SkPoint& p2) { + return this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); + } + + /** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2). + If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding quad. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, + if needed; then appends kQuad_Verb to verb array; and appends quad + control and quad end to SkPoint array. + Quad control is last point plus vector (dx1, dy1). + Quad end is last point plus vector (dx2, dy2). + Function name stands for "relative quad to". + + @param dx1 offset from last point to quad control on x-axis + @param dy1 offset from last point to quad control on y-axis + @param dx2 offset from last point to quad end on x-axis + @param dy2 offset from last point to quad end on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Conic_Weight_a + example: https://fiddle.skia.org/c/@Conic_Weight_b + example: https://fiddle.skia.org/c/@Conic_Weight_c + example: https://fiddle.skia.org/c/@Path_rQuadTo + */ + SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); + + /** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + + If w is finite and not one, appends kConic_Verb to verb array; + and (x1, y1), (x2, y2) to SkPoint array; and w to conic weights. + + If w is one, appends kQuad_Verb to verb array, and + (x1, y1), (x2, y2) to SkPoint array. + + If w is not finite, appends kLine_Verb twice to verb array, and + (x1, y1), (x2, y2) to SkPoint array. + + @param x1 control SkPoint of conic on x-axis + @param y1 control SkPoint of conic on y-axis + @param x2 end SkPoint of conic on x-axis + @param y2 end SkPoint of conic on y-axis + @param w weight of added conic + @return reference to SkPath + */ + SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar w); + + /** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + + If w is finite and not one, appends kConic_Verb to verb array; + and SkPoint p1, p2 to SkPoint array; and w to conic weights. + + If w is one, appends kQuad_Verb to verb array, and SkPoint p1, p2 + to SkPoint array. + + If w is not finite, appends kLine_Verb twice to verb array, and + SkPoint p1, p2 to SkPoint array. + + @param p1 control SkPoint of added conic + @param p2 end SkPoint of added conic + @param w weight of added conic + @return reference to SkPath + */ + SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { + return this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); + } + + /** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2), + weighted by w. If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, + if needed. + + If w is finite and not one, next appends kConic_Verb to verb array, + and w is recorded as conic weight; otherwise, if w is one, appends + kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb + twice to verb array. + + In all cases appends SkPoint control and end to SkPoint array. + control is last point plus vector (dx1, dy1). + end is last point plus vector (dx2, dy2). + + Function name stands for "relative conic to". + + @param dx1 offset from last point to conic control on x-axis + @param dy1 offset from last point to conic control on y-axis + @param dx2 offset from last point to conic end on x-axis + @param dy2 offset from last point to conic end on y-axis + @param w weight of added conic + @return reference to SkPath + */ + SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, + SkScalar w); + + /** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at + (x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to + (0, 0) before adding cubic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3) + to SkPoint array. + + @param x1 first control SkPoint of cubic on x-axis + @param y1 first control SkPoint of cubic on y-axis + @param x2 second control SkPoint of cubic on x-axis + @param y2 second control SkPoint of cubic on y-axis + @param x3 end SkPoint of cubic on x-axis + @param y3 end SkPoint of cubic on y-axis + @return reference to SkPath + */ + SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar x3, SkScalar y3); + + /** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at + SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to + (0, 0) before adding cubic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3 + to SkPoint array. + + @param p1 first control SkPoint of cubic + @param p2 second control SkPoint of cubic + @param p3 end SkPoint of cubic + @return reference to SkPath + */ + SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { + return this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); + } + + /** Adds cubic from last point towards vector (dx1, dy1), then towards + vector (dx2, dy2), to vector (dx3, dy3). + If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding cubic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, + if needed; then appends kCubic_Verb to verb array; and appends cubic + control and cubic end to SkPoint array. + Cubic control is last point plus vector (dx1, dy1). + Cubic end is last point plus vector (dx2, dy2). + Function name stands for "relative cubic to". + + @param dx1 offset from last point to first cubic control on x-axis + @param dy1 offset from last point to first cubic control on y-axis + @param dx2 offset from last point to second cubic control on x-axis + @param dy2 offset from last point to second cubic control on y-axis + @param dx3 offset from last point to cubic end on x-axis + @param dy3 offset from last point to cubic end on y-axis + @return reference to SkPath + */ + SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, + SkScalar dx3, SkScalar dy3); + + /** Appends arc to SkPath. Arc added is part of ellipse + bounded by oval, from startAngle through sweepAngle. Both startAngle and + sweepAngle are measured in degrees, where zero degrees is aligned with the + positive x-axis, and positive sweeps extends arc clockwise. + + arcTo() adds line connecting SkPath last SkPoint to initial arc SkPoint if forceMoveTo + is false and SkPath is not empty. Otherwise, added contour begins with first point + of arc. Angles greater than -360 and less than 360 are treated modulo 360. + + @param oval bounds of ellipse containing arc + @param startAngle starting angle of arc in degrees + @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 + @param forceMoveTo true to start a new contour with arc + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_arcTo + */ + SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo); + + /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic + weighted to describe part of circle. Arc is contained by tangent from + last SkPath point to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc + is part of circle sized to radius, positioned so it touches both tangent lines. + + If last Path Point does not start Arc, arcTo appends connecting Line to Path. + The length of Vector from (x1, y1) to (x2, y2) does not affect Arc. + + Arc sweep is always less than 180 degrees. If radius is zero, or if + tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1). + + arcTo appends at most one Line and one conic. + arcTo implements the functionality of PostScript arct and HTML Canvas arcTo. + + @param x1 x-axis value common to pair of tangents + @param y1 y-axis value common to pair of tangents + @param x2 x-axis value end of second tangent + @param y2 y-axis value end of second tangent + @param radius distance from arc to circle center + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_arcTo_2_a + example: https://fiddle.skia.org/c/@Path_arcTo_2_b + example: https://fiddle.skia.org/c/@Path_arcTo_2_c + */ + SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius); + + /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic + weighted to describe part of circle. Arc is contained by tangent from + last SkPath point to p1, and tangent from p1 to p2. Arc + is part of circle sized to radius, positioned so it touches both tangent lines. + + If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath. + The length of vector from p1 to p2 does not affect arc. + + Arc sweep is always less than 180 degrees. If radius is zero, or if + tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1. + + arcTo() appends at most one line and one conic. + arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo. + + @param p1 SkPoint common to pair of tangents + @param p2 end of second tangent + @param radius distance from arc to circle center + @return reference to SkPath + */ + SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { + return this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); + } + + /** \enum SkPath::ArcSize + Four oval parts with radii (rx, ry) start at last SkPath SkPoint and ends at (x, y). + ArcSize and Direction select one of the four oval parts. + */ + enum ArcSize { + kSmall_ArcSize, //!< smaller of arc pair + kLarge_ArcSize, //!< larger of arc pair + }; + + /** Appends arc to SkPath. Arc is implemented by one or more conics weighted to + describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc + curves from last SkPath SkPoint to (x, y), choosing one of four possible routes: + clockwise or counterclockwise, and smaller or larger. + + Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if + either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii + (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but + too small. + + arcTo() appends up to four conic curves. + arcTo() implements the functionality of SVG arc, although SVG sweep-flag value + is opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, + while kCW_Direction cast to int is zero. + + @param rx radius on x-axis before x-axis rotation + @param ry radius on y-axis before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param x end of arc + @param y end of arc + @return reference to SkPath + */ + SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, + SkPathDirection sweep, SkScalar x, SkScalar y); + + /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe + part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves + from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes: + clockwise or counterclockwise, + and smaller or larger. + + Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either + radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to + fit last SkPath SkPoint and xy if both are greater than zero but too small to describe + an arc. + + arcTo() appends up to four conic curves. + arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is + opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while + kCW_Direction cast to int is zero. + + @param r radii on axes before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param xy end of arc + @return reference to SkPath + */ + SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep, + const SkPoint xy) { + return this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY); + } + + /** Appends arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or + more conic, weighted to describe part of oval with radii (rx, ry) rotated by + xAxisRotate degrees. Arc curves from last SkPath SkPoint to relative end SkPoint: + (dx, dy), choosing one of four possible routes: clockwise or + counterclockwise, and smaller or larger. If SkPath is empty, the start arc SkPoint + is (0, 0). + + Arc sweep is always less than 360 degrees. arcTo() appends line to end SkPoint + if either radii are zero, or if last SkPath SkPoint equals end SkPoint. + arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and end SkPoint if both are + greater than zero but too small to describe an arc. + + arcTo() appends up to four conic curves. + arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is + opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while + kCW_Direction cast to int is zero. + + @param rx radius before x-axis rotation + @param ry radius before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param dx x-axis offset end of arc from last SkPath SkPoint + @param dy y-axis offset end of arc from last SkPath SkPoint + @return reference to SkPath + */ + SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, + SkPathDirection sweep, SkScalar dx, SkScalar dy); + + /** Appends kClose_Verb to SkPath. A closed contour connects the first and last SkPoint + with line, forming a continuous loop. Open and closed contour draw the same + with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws + SkPaint::Cap at contour start and end; closed contour draws + SkPaint::Join at contour start and end. + + close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb. + + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_close + */ + SkPath& close(); + +#ifdef SK_HIDE_PATH_EDIT_METHODS +public: +#endif + + /** Approximates conic with quad array. Conic is constructed from start SkPoint p0, + control SkPoint p1, end SkPoint p2, and weight w. + Quad array is stored in pts; this storage is supplied by caller. + Maximum quad count is 2 to the pow2. + Every third point in array shares last SkPoint of previous quad and first SkPoint of + next quad. Maximum pts storage size is given by: + (1 + 2 * (1 << pow2)) * sizeof(SkPoint). + + Returns quad count used the approximation, which may be smaller + than the number requested. + + conic weight determines the amount of influence conic control point has on the curve. + w less than one represents an elliptical section. w greater than one represents + a hyperbolic section. w equal to one represents a parabolic section. + + Two quad curves are sufficient to approximate an elliptical conic with a sweep + of up to 90 degrees; in this case, set pow2 to one. + + @param p0 conic start SkPoint + @param p1 conic control SkPoint + @param p2 conic end SkPoint + @param w conic weight + @param pts storage for quad array + @param pow2 quad count, as power of two, normally 0 to 5 (1 to 32 quad curves) + @return number of quad curves written to pts + */ + static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, + SkScalar w, SkPoint pts[], int pow2); + + /** Returns true if SkPath is equivalent to SkRect when filled. + If false: rect, isClosed, and direction are unchanged. + If true: rect, isClosed, and direction are written to if not nullptr. + + rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points + that do not alter the area drawn by the returned rect. + + @param rect storage for bounds of SkRect; may be nullptr + @param isClosed storage set to true if SkPath is closed; may be nullptr + @param direction storage set to SkRect direction; may be nullptr + @return true if SkPath contains SkRect + + example: https://fiddle.skia.org/c/@Path_isRect + */ + bool isRect(SkRect* rect, bool* isClosed = nullptr, SkPathDirection* direction = nullptr) const; + +#ifdef SK_HIDE_PATH_EDIT_METHODS +private: +#endif + + /** Adds a new contour to the path, defined by the rect, and wound in the + specified direction. The verbs added to the path will be: + + kMove, kLine, kLine, kLine, kClose + + start specifies which corner to begin the contour: + 0: upper-left corner + 1: upper-right corner + 2: lower-right corner + 3: lower-left corner + + This start point also acts as the implied beginning of the subsequent, + contour, if it does not have an explicit moveTo(). e.g. + + path.addRect(...) + // if we don't say moveTo() here, we will use the rect's start point + path.lineTo(...) + + @param rect SkRect to add as a closed contour + @param dir SkPath::Direction to orient the new contour + @param start initial corner of SkRect to add + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addRect_2 + */ + SkPath& addRect(const SkRect& rect, SkPathDirection dir, unsigned start); + + SkPath& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { + return this->addRect(rect, dir, 0); + } + + SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, + SkPathDirection dir = SkPathDirection::kCW) { + return this->addRect({left, top, right, bottom}, dir, 0); + } + + /** Adds oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb. + Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width + and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues + clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. + + @param oval bounds of ellipse added + @param dir SkPath::Direction to wind ellipse + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addOval + */ + SkPath& addOval(const SkRect& oval, SkPathDirection dir = SkPathDirection::kCW); + + /** Adds oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb. + Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width + and half oval height. Oval begins at start and continues + clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. + + @param oval bounds of ellipse added + @param dir SkPath::Direction to wind ellipse + @param start index of initial point of ellipse + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addOval_2 + */ + SkPath& addOval(const SkRect& oval, SkPathDirection dir, unsigned start); + + /** Adds circle centered at (x, y) of size radius to SkPath, appending kMove_Verb, + four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing + clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction. + + Has no effect if radius is zero or negative. + + @param x center of circle + @param y center of circle + @param radius distance from center to edge + @param dir SkPath::Direction to wind circle + @return reference to SkPath + */ + SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius, + SkPathDirection dir = SkPathDirection::kCW); + + /** Appends arc to SkPath, as the start of new contour. Arc added is part of ellipse + bounded by oval, from startAngle through sweepAngle. Both startAngle and + sweepAngle are measured in degrees, where zero degrees is aligned with the + positive x-axis, and positive sweeps extends arc clockwise. + + If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly + zero, append oval instead of arc. Otherwise, sweepAngle values are treated + modulo 360, and arc may or may not draw depending on numeric rounding. + + @param oval bounds of ellipse containing arc + @param startAngle starting angle of arc in degrees + @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addArc + */ + SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); + + /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds + equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If + dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and + winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left + of the upper-left corner and winds counterclockwise. + + If either rx or ry is too large, rx and ry are scaled uniformly until the + corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends + SkRect rect to SkPath. + + After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect. + + @param rect bounds of SkRRect + @param rx x-axis radius of rounded corners on the SkRRect + @param ry y-axis radius of rounded corners on the SkRRect + @param dir SkPath::Direction to wind SkRRect + @return reference to SkPath + */ + SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, + SkPathDirection dir = SkPathDirection::kCW); + + /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds + equal to rect; each corner is 90 degrees of an ellipse with radii from the + array. + + @param rect bounds of SkRRect + @param radii array of 8 SkScalar values, a radius pair for each corner + @param dir SkPath::Direction to wind SkRRect + @return reference to SkPath + */ + SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[], + SkPathDirection dir = SkPathDirection::kCW); + + /** Adds rrect to SkPath, creating a new closed contour. If + dir is kCW_Direction, rrect starts at top-left of the lower-left corner and + winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left + of the upper-left corner and winds counterclockwise. + + After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect. + + @param rrect bounds and radii of rounded rectangle + @param dir SkPath::Direction to wind SkRRect + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addRRect + */ + SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW); + + /** Adds rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect + winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise. + start determines the first point of rrect to add. + + @param rrect bounds and radii of rounded rectangle + @param dir SkPath::Direction to wind SkRRect + @param start index of initial point of SkRRect + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addRRect_2 + */ + SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir, unsigned start); + + /** Adds contour created from line array, adding (count - 1) line segments. + Contour added starts at pts[0], then adds a line for every additional SkPoint + in pts array. If close is true, appends kClose_Verb to SkPath, connecting + pts[count - 1] and pts[0]. + + If count is zero, append kMove_Verb to path. + Has no effect if count is less than one. + + @param pts array of line sharing end and start SkPoint + @param count length of SkPoint array + @param close true to add line connecting contour end and start + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addPoly + */ + SkPath& addPoly(const SkPoint pts[], int count, bool close); + + /** Adds contour created from list. Contour added starts at list[0], then adds a line + for every additional SkPoint in list. If close is true, appends kClose_Verb to SkPath, + connecting last and first SkPoint in list. + + If list is empty, append kMove_Verb to path. + + @param list array of SkPoint + @param close true to add line connecting contour end and start + @return reference to SkPath + */ + SkPath& addPoly(const std::initializer_list& list, bool close) { + return this->addPoly(list.begin(), SkToInt(list.size()), close); + } + +#ifdef SK_HIDE_PATH_EDIT_METHODS +public: +#endif + + /** \enum SkPath::AddPathMode + AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend + the last contour or start a new contour. + */ + enum AddPathMode { + kAppend_AddPathMode, //!< appended to destination unaltered + kExtend_AddPathMode, //!< add line if prior contour is not closed + }; + + /** Appends src to SkPath, offset by (dx, dy). + + If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + verbs, SkPoint, and conic weights. + + @param src SkPath verbs, SkPoint, and conic weights to add + @param dx offset added to src SkPoint array x-axis coordinates + @param dy offset added to src SkPoint array y-axis coordinates + @param mode kAppend_AddPathMode or kExtend_AddPathMode + @return reference to SkPath + */ + SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy, + AddPathMode mode = kAppend_AddPathMode); + + /** Appends src to SkPath. + + If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + verbs, SkPoint, and conic weights. + + @param src SkPath verbs, SkPoint, and conic weights to add + @param mode kAppend_AddPathMode or kExtend_AddPathMode + @return reference to SkPath + */ + SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { + SkMatrix m; + m.reset(); + return this->addPath(src, m, mode); + } + + /** Appends src to SkPath, transformed by matrix. Transformed curves may have different + verbs, SkPoint, and conic weights. + + If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + verbs, SkPoint, and conic weights. + + @param src SkPath verbs, SkPoint, and conic weights to add + @param matrix transform applied to src + @param mode kAppend_AddPathMode or kExtend_AddPathMode + @return reference to SkPath + */ + SkPath& addPath(const SkPath& src, const SkMatrix& matrix, + AddPathMode mode = kAppend_AddPathMode); + + /** Appends src to SkPath, from back to front. + Reversed src always appends a new contour to SkPath. + + @param src SkPath verbs, SkPoint, and conic weights to add + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_reverseAddPath + */ + SkPath& reverseAddPath(const SkPath& src); + + /** Offsets SkPoint array by (dx, dy). Offset SkPath replaces dst. + If dst is nullptr, SkPath is replaced by offset data. + + @param dx offset added to SkPoint array x-axis coordinates + @param dy offset added to SkPoint array y-axis coordinates + @param dst overwritten, translated copy of SkPath; may be nullptr + + example: https://fiddle.skia.org/c/@Path_offset + */ + void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; + + /** Offsets SkPoint array by (dx, dy). SkPath is replaced by offset data. + + @param dx offset added to SkPoint array x-axis coordinates + @param dy offset added to SkPoint array y-axis coordinates + */ + void offset(SkScalar dx, SkScalar dy) { + this->offset(dx, dy, this); + } + + /** Transforms verb array, SkPoint array, and weight by matrix. + transform may change verbs and increase their number. + Transformed SkPath replaces dst; if dst is nullptr, original data + is replaced. + + @param matrix SkMatrix to apply to SkPath + @param dst overwritten, transformed copy of SkPath; may be nullptr + @param pc whether to apply perspective clipping + + example: https://fiddle.skia.org/c/@Path_transform + */ + void transform(const SkMatrix& matrix, SkPath* dst, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const; + + /** Transforms verb array, SkPoint array, and weight by matrix. + transform may change verbs and increase their number. + SkPath is replaced by transformed data. + + @param matrix SkMatrix to apply to SkPath + @param pc whether to apply perspective clipping + */ + void transform(const SkMatrix& matrix, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) { + this->transform(matrix, this, pc); + } + + SkPath makeTransform(const SkMatrix& m, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { + SkPath dst; + this->transform(m, &dst, pc); + return dst; + } + + SkPath makeScale(SkScalar sx, SkScalar sy) { + return this->makeTransform(SkMatrix::Scale(sx, sy), SkApplyPerspectiveClip::kNo); + } + + /** Returns last point on SkPath in lastPt. Returns false if SkPoint array is empty, + storing (0, 0) if lastPt is not nullptr. + + @param lastPt storage for final SkPoint in SkPoint array; may be nullptr + @return true if SkPoint array contains one or more SkPoint + + example: https://fiddle.skia.org/c/@Path_getLastPt + */ + bool getLastPt(SkPoint* lastPt) const; + + /** Sets last point to (x, y). If SkPoint array is empty, append kMove_Verb to + verb array and append (x, y) to SkPoint array. + + @param x set x-axis value of last point + @param y set y-axis value of last point + + example: https://fiddle.skia.org/c/@Path_setLastPt + */ + void setLastPt(SkScalar x, SkScalar y); + + /** Sets the last point on the path. If SkPoint array is empty, append kMove_Verb to + verb array and append p to SkPoint array. + + @param p set value of last point + */ + void setLastPt(const SkPoint& p) { + this->setLastPt(p.fX, p.fY); + } + + /** \enum SkPath::SegmentMask + SegmentMask constants correspond to each drawing Verb type in SkPath; for + instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set. + */ + enum SegmentMask { + kLine_SegmentMask = kLine_SkPathSegmentMask, + kQuad_SegmentMask = kQuad_SkPathSegmentMask, + kConic_SegmentMask = kConic_SkPathSegmentMask, + kCubic_SegmentMask = kCubic_SkPathSegmentMask, + }; + + /** Returns a mask, where each set bit corresponds to a SegmentMask constant + if SkPath contains one or more verbs of that type. + Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics. + + getSegmentMasks() returns a cached result; it is very fast. + + @return SegmentMask bits or zero + */ + uint32_t getSegmentMasks() const; + + /** \enum SkPath::Verb + Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight; + manage contour, and terminate SkPath. + */ + enum Verb { + kMove_Verb = static_cast(SkPathVerb::kMove), + kLine_Verb = static_cast(SkPathVerb::kLine), + kQuad_Verb = static_cast(SkPathVerb::kQuad), + kConic_Verb = static_cast(SkPathVerb::kConic), + kCubic_Verb = static_cast(SkPathVerb::kCubic), + kClose_Verb = static_cast(SkPathVerb::kClose), + kDone_Verb = kClose_Verb + 1 + }; + + /** \class SkPath::Iter + Iterates through verb array, and associated SkPoint array and conic weight. + Provides options to treat open contours as closed, and to ignore + degenerate data. + */ + class SK_API Iter { + public: + + /** Initializes SkPath::Iter with an empty SkPath. next() on SkPath::Iter returns + kDone_Verb. + Call setPath to initialize SkPath::Iter at a later time. + + @return SkPath::Iter of empty SkPath + + example: https://fiddle.skia.org/c/@Path_Iter_Iter + */ + Iter(); + + /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in + path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each + open contour. path is not altered. + + @param path SkPath to iterate + @param forceClose true if open contours generate kClose_Verb + @return SkPath::Iter of path + + example: https://fiddle.skia.org/c/@Path_Iter_const_SkPath + */ + Iter(const SkPath& path, bool forceClose); + + /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in + path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each + open contour. path is not altered. + + @param path SkPath to iterate + @param forceClose true if open contours generate kClose_Verb + + example: https://fiddle.skia.org/c/@Path_Iter_setPath + */ + void setPath(const SkPath& path, bool forceClose); + + /** Returns next SkPath::Verb in verb array, and advances SkPath::Iter. + When verb array is exhausted, returns kDone_Verb. + + Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb. + + @param pts storage for SkPoint data describing returned SkPath::Verb + @return next SkPath::Verb from verb array + + example: https://fiddle.skia.org/c/@Path_RawIter_next + */ + Verb next(SkPoint pts[4]); + + /** Returns conic weight if next() returned kConic_Verb. + + If next() has not been called, or next() did not return kConic_Verb, + result is undefined. + + @return conic weight for conic SkPoint returned by next() + */ + SkScalar conicWeight() const { return *fConicWeights; } + + /** Returns true if last kLine_Verb returned by next() was generated + by kClose_Verb. When true, the end point returned by next() is + also the start point of contour. + + If next() has not been called, or next() did not return kLine_Verb, + result is undefined. + + @return true if last kLine_Verb was generated by kClose_Verb + */ + bool isCloseLine() const { return SkToBool(fCloseLine); } + + /** Returns true if subsequent calls to next() return kClose_Verb before returning + kMove_Verb. if true, contour SkPath::Iter is processing may end with kClose_Verb, or + SkPath::Iter may have been initialized with force close set to true. + + @return true if contour is closed + + example: https://fiddle.skia.org/c/@Path_Iter_isClosedContour + */ + bool isClosedContour() const; + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + const SkScalar* fConicWeights; + SkPoint fMoveTo; + SkPoint fLastPt; + bool fForceClose; + bool fNeedClose; + bool fCloseLine; + + Verb autoClose(SkPoint pts[2]); + }; + +private: + /** \class SkPath::RangeIter + Iterates through a raw range of path verbs, points, and conics. All values are returned + unaltered. + + NOTE: This class will be moved into SkPathPriv once RangeIter is removed. + */ + class RangeIter { + public: + RangeIter() = default; + RangeIter(const uint8_t* verbs, const SkPoint* points, const SkScalar* weights) + : fVerb(verbs), fPoints(points), fWeights(weights) { + SkDEBUGCODE(fInitialPoints = fPoints;) + } + bool operator!=(const RangeIter& that) const { + return fVerb != that.fVerb; + } + bool operator==(const RangeIter& that) const { + return fVerb == that.fVerb; + } + RangeIter& operator++() { + auto verb = static_cast(*fVerb++); + fPoints += pts_advance_after_verb(verb); + if (verb == SkPathVerb::kConic) { + ++fWeights; + } + return *this; + } + RangeIter operator++(int) { + RangeIter copy = *this; + this->operator++(); + return copy; + } + SkPathVerb peekVerb() const { + return static_cast(*fVerb); + } + std::tuple operator*() const { + SkPathVerb verb = this->peekVerb(); + // We provide the starting point for beziers by peeking backwards from the current + // point, which works fine as long as there is always a kMove before any geometry. + // (SkPath::injectMoveToIfNeeded should have guaranteed this to be the case.) + int backset = pts_backset_for_verb(verb); + SkASSERT(fPoints + backset >= fInitialPoints); + return {verb, fPoints + backset, fWeights}; + } + private: + constexpr static int pts_advance_after_verb(SkPathVerb verb) { + switch (verb) { + case SkPathVerb::kMove: return 1; + case SkPathVerb::kLine: return 1; + case SkPathVerb::kQuad: return 2; + case SkPathVerb::kConic: return 2; + case SkPathVerb::kCubic: return 3; + case SkPathVerb::kClose: return 0; + } + SkUNREACHABLE; + } + constexpr static int pts_backset_for_verb(SkPathVerb verb) { + switch (verb) { + case SkPathVerb::kMove: return 0; + case SkPathVerb::kLine: return -1; + case SkPathVerb::kQuad: return -1; + case SkPathVerb::kConic: return -1; + case SkPathVerb::kCubic: return -1; + case SkPathVerb::kClose: return -1; + } + SkUNREACHABLE; + } + const uint8_t* fVerb = nullptr; + const SkPoint* fPoints = nullptr; + const SkScalar* fWeights = nullptr; + SkDEBUGCODE(const SkPoint* fInitialPoints = nullptr;) + }; +public: + + /** \class SkPath::RawIter + Use Iter instead. This class will soon be removed and RangeIter will be made private. + */ + class SK_API RawIter { + public: + + /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb. + Call setPath to initialize SkPath::Iter at a later time. + + @return RawIter of empty SkPath + */ + RawIter() {} + + /** Sets RawIter to return elements of verb array, SkPoint array, and conic weight in path. + + @param path SkPath to iterate + @return RawIter of path + */ + RawIter(const SkPath& path) { + setPath(path); + } + + /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in + path. + + @param path SkPath to iterate + */ + void setPath(const SkPath&); + + /** Returns next SkPath::Verb in verb array, and advances RawIter. + When verb array is exhausted, returns kDone_Verb. + Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb. + + @param pts storage for SkPoint data describing returned SkPath::Verb + @return next SkPath::Verb from verb array + */ + Verb next(SkPoint[4]); + + /** Returns next SkPath::Verb, but does not advance RawIter. + + @return next SkPath::Verb from verb array + */ + Verb peek() const { + return (fIter != fEnd) ? static_cast(std::get<0>(*fIter)) : kDone_Verb; + } + + /** Returns conic weight if next() returned kConic_Verb. + + If next() has not been called, or next() did not return kConic_Verb, + result is undefined. + + @return conic weight for conic SkPoint returned by next() + */ + SkScalar conicWeight() const { + return fConicWeight; + } + + private: + RangeIter fIter; + RangeIter fEnd; + SkScalar fConicWeight = 0; + friend class SkPath; + + }; + + /** Returns true if the point (x, y) is contained by SkPath, taking into + account FillType. + + @param x x-axis value of containment test + @param y y-axis value of containment test + @return true if SkPoint is in SkPath + + example: https://fiddle.skia.org/c/@Path_contains + */ + bool contains(SkScalar x, SkScalar y) const; + + /** Writes text representation of SkPath to stream. If stream is nullptr, writes to + standard output. Set dumpAsHex true to generate exact binary representations + of floating point numbers used in SkPoint array and conic weights. + + @param stream writable SkWStream receiving SkPath text representation; may be nullptr + @param dumpAsHex true if SkScalar values are written as hexadecimal + + example: https://fiddle.skia.org/c/@Path_dump + */ + void dump(SkWStream* stream, bool dumpAsHex) const; + + void dump() const { this->dump(nullptr, false); } + void dumpHex() const { this->dump(nullptr, true); } + + // Like dump(), but outputs for the SkPath::Make() factory + void dumpArrays(SkWStream* stream, bool dumpAsHex) const; + void dumpArrays() const { this->dumpArrays(nullptr, false); } + + /** Writes SkPath to buffer, returning the number of bytes written. + Pass nullptr to obtain the storage size. + + Writes SkPath::FillType, verb array, SkPoint array, conic weight, and + additionally writes computed information like SkPath::Convexity and bounds. + + Use only be used in concert with readFromMemory(); + the format used for SkPath in memory is not guaranteed. + + @param buffer storage for SkPath; may be nullptr + @return size of storage required for SkPath; always a multiple of 4 + + example: https://fiddle.skia.org/c/@Path_writeToMemory + */ + size_t writeToMemory(void* buffer) const; + + /** Writes SkPath to buffer, returning the buffer written to, wrapped in SkData. + + serialize() writes SkPath::FillType, verb array, SkPoint array, conic weight, and + additionally writes computed information like SkPath::Convexity and bounds. + + serialize() should only be used in concert with readFromMemory(). + The format used for SkPath in memory is not guaranteed. + + @return SkPath data wrapped in SkData buffer + + example: https://fiddle.skia.org/c/@Path_serialize + */ + sk_sp serialize() const; + + /** Initializes SkPath from buffer of size length. Returns zero if the buffer is + data is inconsistent, or the length is too small. + + Reads SkPath::FillType, verb array, SkPoint array, conic weight, and + additionally reads computed information like SkPath::Convexity and bounds. + + Used only in concert with writeToMemory(); + the format used for SkPath in memory is not guaranteed. + + @param buffer storage for SkPath + @param length buffer size in bytes; must be multiple of 4 + @return number of bytes read, or zero on failure + + example: https://fiddle.skia.org/c/@Path_readFromMemory + */ + size_t readFromMemory(const void* buffer, size_t length); + + /** (See Skia bug 1762.) + Returns a non-zero, globally unique value. A different value is returned + if verb array, SkPoint array, or conic weight changes. + + Setting SkPath::FillType does not change generation identifier. + + Each time the path is modified, a different generation identifier will be returned. + SkPath::FillType does affect generation identifier on Android framework. + + @return non-zero, globally unique value + + example: https://fiddle.skia.org/c/@Path_getGenerationID + */ + uint32_t getGenerationID() const; + + /** Returns if SkPath data is consistent. Corrupt SkPath data is detected if + internal values are out of range or internal storage does not match + array dimensions. + + @return true if SkPath data is consistent + */ + bool isValid() const; + + using sk_is_trivially_relocatable = std::true_type; + +private: + SkPath(sk_sp, SkPathFillType, bool isVolatile, SkPathConvexity, + SkPathFirstDirection firstDirection); + + sk_sp fPathRef; + int fLastMoveToIndex; + mutable std::atomic fConvexity; // SkPathConvexity + mutable std::atomic fFirstDirection; // SkPathFirstDirection + uint8_t fFillType : 2; + uint8_t fIsVolatile : 1; + + static_assert(::sk_is_trivially_relocatable::value); + + /** Resets all fields other than fPathRef to their initial 'empty' values. + * Assumes the caller has already emptied fPathRef. + * On Android increments fGenerationID without reseting it. + */ + void resetFields(); + + /** Sets all fields other than fPathRef to the values in 'that'. + * Assumes the caller has already set fPathRef. + * Doesn't change fGenerationID or fSourcePath on Android. + */ + void copyFields(const SkPath& that); + + size_t writeToMemoryAsRRect(void* buffer) const; + size_t readAsRRect(const void*, size_t); + size_t readFromMemory_EQ4Or5(const void*, size_t); + + friend class Iter; + friend class SkPathPriv; + friend class SkPathStroker; + + /* Append, in reverse order, the first contour of path, ignoring path's + last point. If no moveTo() call has been made for this contour, the + first point is automatically set to (0,0). + */ + SkPath& reversePathTo(const SkPath&); + + // called before we add points for lineTo, quadTo, cubicTo, checking to see + // if we need to inject a leading moveTo first + // + // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) + // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) + // + inline void injectMoveToIfNeeded(); + + inline bool hasOnlyMoveTos() const; + + SkPathConvexity computeConvexity() const; + + bool isValidImpl() const; + /** Asserts if SkPath data is inconsistent. + Debugging check intended for internal use only. + */ +#ifdef SK_DEBUG + void validate() const; + void validateRef() const; +#endif + + // called by stroker to see if all points (in the last contour) are equal and worthy of a cap + bool isZeroLengthSincePoint(int startPtIndex) const; + + /** Returns if the path can return a bound at no cost (true) or will have to + perform some computation (false). + */ + bool hasComputedBounds() const; + + // 'rect' needs to be sorted + void setBounds(const SkRect& rect); + + void setPt(int index, SkScalar x, SkScalar y); + + SkPath& dirtyAfterEdit(); + + // Bottlenecks for working with fConvexity and fFirstDirection. + // Notice the setters are const... these are mutable atomic fields. + void setConvexity(SkPathConvexity) const; + + void setFirstDirection(SkPathFirstDirection) const; + SkPathFirstDirection getFirstDirection() const; + + /** Returns the comvexity type, computing if needed. Never returns kUnknown. + @return path's convexity type (convex or concave) + */ + SkPathConvexity getConvexity() const; + + SkPathConvexity getConvexityOrUnknown() const; + + // Compares the cached value with a freshly computed one (computeConvexity()) + bool isConvexityAccurate() const; + + /** Stores a convexity type for this path. This is what will be returned if + * getConvexityOrUnknown() is called. If you pass kUnknown, then if getContexityType() + * is called, the real convexity will be computed. + * + * example: https://fiddle.skia.org/c/@Path_setConvexity + */ + void setConvexity(SkPathConvexity convexity); + + /** Shrinks SkPath verb array and SkPoint array storage to discard unused capacity. + * May reduce the heap overhead for SkPath known to be fully constructed. + * + * NOTE: This may relocate the underlying buffers, and thus any Iterators referencing + * this path should be discarded after calling shrinkToFit(). + */ + void shrinkToFit(); + + // Creates a new Path after the supplied arguments have been validated by + // sk_path_analyze_verbs(). + static SkPath MakeInternal(const SkPathVerbAnalysis& analsis, + const SkPoint points[], + const uint8_t verbs[], + int verbCount, + const SkScalar conics[], + SkPathFillType fillType, + bool isVolatile); + + friend class SkAutoPathBoundsUpdate; + friend class SkAutoDisableOvalCheck; + friend class SkAutoDisableDirectionCheck; + friend class SkPathBuilder; + friend class SkPathEdgeIter; + friend class SkPathWriter; + friend class SkOpBuilder; + friend class SkBench_AddPathTest; // perf test reversePathTo + friend class PathTest_Private; // unit test reversePathTo + friend class ForceIsRRect_Private; // unit test isRRect + friend class FuzzPath; // for legacy access to validateRef +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathBuilder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathBuilder.h new file mode 100644 index 00000000000000..247c08624c554b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathBuilder.h @@ -0,0 +1,271 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPathBuilder_DEFINED +#define SkPathBuilder_DEFINED + +#include "include/core/SkPath.h" +#include "include/core/SkPathTypes.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/SkPathRef.h" +#include "include/private/base/SkTo.h" + +#include + +class SkRRect; + +class SK_API SkPathBuilder { +public: + SkPathBuilder(); + SkPathBuilder(SkPathFillType); + SkPathBuilder(const SkPath&); + SkPathBuilder(const SkPathBuilder&) = default; + ~SkPathBuilder(); + + SkPathBuilder& operator=(const SkPath&); + SkPathBuilder& operator=(const SkPathBuilder&) = default; + + SkPathFillType fillType() const { return fFillType; } + SkRect computeBounds() const; + + SkPath snapshot() const; // the builder is unchanged after returning this path + SkPath detach(); // the builder is reset to empty after returning this path + + SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; } + SkPathBuilder& setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; return *this; } + + SkPathBuilder& reset(); + + SkPathBuilder& moveTo(SkPoint pt); + SkPathBuilder& moveTo(SkScalar x, SkScalar y) { return this->moveTo(SkPoint::Make(x, y)); } + + SkPathBuilder& lineTo(SkPoint pt); + SkPathBuilder& lineTo(SkScalar x, SkScalar y) { return this->lineTo(SkPoint::Make(x, y)); } + + SkPathBuilder& quadTo(SkPoint pt1, SkPoint pt2); + SkPathBuilder& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { + return this->quadTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2)); + } + SkPathBuilder& quadTo(const SkPoint pts[2]) { return this->quadTo(pts[0], pts[1]); } + + SkPathBuilder& conicTo(SkPoint pt1, SkPoint pt2, SkScalar w); + SkPathBuilder& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) { + return this->conicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), w); + } + SkPathBuilder& conicTo(const SkPoint pts[2], SkScalar w) { + return this->conicTo(pts[0], pts[1], w); + } + + SkPathBuilder& cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3); + SkPathBuilder& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) { + return this->cubicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), SkPoint::Make(x3, y3)); + } + SkPathBuilder& cubicTo(const SkPoint pts[3]) { + return this->cubicTo(pts[0], pts[1], pts[2]); + } + + SkPathBuilder& close(); + + // Append a series of lineTo(...) + SkPathBuilder& polylineTo(const SkPoint pts[], int count); + SkPathBuilder& polylineTo(const std::initializer_list& list) { + return this->polylineTo(list.begin(), SkToInt(list.size())); + } + + // Relative versions of segments, relative to the previous position. + + SkPathBuilder& rLineTo(SkPoint pt); + SkPathBuilder& rLineTo(SkScalar x, SkScalar y) { return this->rLineTo({x, y}); } + SkPathBuilder& rQuadTo(SkPoint pt1, SkPoint pt2); + SkPathBuilder& rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { + return this->rQuadTo({x1, y1}, {x2, y2}); + } + SkPathBuilder& rConicTo(SkPoint p1, SkPoint p2, SkScalar w); + SkPathBuilder& rConicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) { + return this->rConicTo({x1, y1}, {x2, y2}, w); + } + SkPathBuilder& rCubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3); + SkPathBuilder& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) { + return this->rCubicTo({x1, y1}, {x2, y2}, {x3, y3}); + } + + // Arcs + + /** Appends arc to the builder. Arc added is part of ellipse + bounded by oval, from startAngle through sweepAngle. Both startAngle and + sweepAngle are measured in degrees, where zero degrees is aligned with the + positive x-axis, and positive sweeps extends arc clockwise. + + arcTo() adds line connecting the builder's last point to initial arc point if forceMoveTo + is false and the builder is not empty. Otherwise, added contour begins with first point + of arc. Angles greater than -360 and less than 360 are treated modulo 360. + + @param oval bounds of ellipse containing arc + @param startAngleDeg starting angle of arc in degrees + @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360 + @param forceMoveTo true to start a new contour with arc + @return reference to the builder + */ + SkPathBuilder& arcTo(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg, + bool forceMoveTo); + + /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic + weighted to describe part of circle. Arc is contained by tangent from + last SkPath point to p1, and tangent from p1 to p2. Arc + is part of circle sized to radius, positioned so it touches both tangent lines. + + If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath. + The length of vector from p1 to p2 does not affect arc. + + Arc sweep is always less than 180 degrees. If radius is zero, or if + tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1. + + arcTo() appends at most one line and one conic. + arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo. + + @param p1 SkPoint common to pair of tangents + @param p2 end of second tangent + @param radius distance from arc to circle center + @return reference to SkPath + */ + SkPathBuilder& arcTo(SkPoint p1, SkPoint p2, SkScalar radius); + + enum ArcSize { + kSmall_ArcSize, //!< smaller of arc pair + kLarge_ArcSize, //!< larger of arc pair + }; + + /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe + part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves + from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes: + clockwise or counterclockwise, + and smaller or larger. + + Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either + radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to + fit last SkPath SkPoint and xy if both are greater than zero but too small to describe + an arc. + + arcTo() appends up to four conic curves. + arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is + opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while + kCW_Direction cast to int is zero. + + @param r radii on axes before x-axis rotation + @param xAxisRotate x-axis rotation in degrees; positive values are clockwise + @param largeArc chooses smaller or larger arc + @param sweep chooses clockwise or counterclockwise arc + @param xy end of arc + @return reference to SkPath + */ + SkPathBuilder& arcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep, + SkPoint xy); + + /** Appends arc to the builder, as the start of new contour. Arc added is part of ellipse + bounded by oval, from startAngle through sweepAngle. Both startAngle and + sweepAngle are measured in degrees, where zero degrees is aligned with the + positive x-axis, and positive sweeps extends arc clockwise. + + If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly + zero, append oval instead of arc. Otherwise, sweepAngle values are treated + modulo 360, and arc may or may not draw depending on numeric rounding. + + @param oval bounds of ellipse containing arc + @param startAngleDeg starting angle of arc in degrees + @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360 + @return reference to this builder + */ + SkPathBuilder& addArc(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg); + + // Add a new contour + + SkPathBuilder& addRect(const SkRect&, SkPathDirection, unsigned startIndex); + SkPathBuilder& addOval(const SkRect&, SkPathDirection, unsigned startIndex); + SkPathBuilder& addRRect(const SkRRect&, SkPathDirection, unsigned startIndex); + + SkPathBuilder& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { + return this->addRect(rect, dir, 0); + } + SkPathBuilder& addOval(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { + // legacy start index: 1 + return this->addOval(rect, dir, 1); + } + SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW) { + // legacy start indices: 6 (CW) and 7 (CCW) + return this->addRRect(rrect, dir, dir == SkPathDirection::kCW ? 6 : 7); + } + + SkPathBuilder& addCircle(SkScalar center_x, SkScalar center_y, SkScalar radius, + SkPathDirection dir = SkPathDirection::kCW); + + SkPathBuilder& addPolygon(const SkPoint pts[], int count, bool isClosed); + SkPathBuilder& addPolygon(const std::initializer_list& list, bool isClosed) { + return this->addPolygon(list.begin(), SkToInt(list.size()), isClosed); + } + + SkPathBuilder& addPath(const SkPath&); + + // Performance hint, to reserve extra storage for subsequent calls to lineTo, quadTo, etc. + + void incReserve(int extraPtCount, int extraVerbCount); + void incReserve(int extraPtCount) { + this->incReserve(extraPtCount, extraPtCount); + } + + SkPathBuilder& offset(SkScalar dx, SkScalar dy); + + SkPathBuilder& toggleInverseFillType() { + fFillType = (SkPathFillType)((unsigned)fFillType ^ 2); + return *this; + } + +private: + SkPathRef::PointsArray fPts; + SkPathRef::VerbsArray fVerbs; + SkPathRef::ConicWeightsArray fConicWeights; + + SkPathFillType fFillType; + bool fIsVolatile; + + unsigned fSegmentMask; + SkPoint fLastMovePoint; + int fLastMoveIndex; // only needed until SkPath is immutable + bool fNeedsMoveVerb; + + enum IsA { + kIsA_JustMoves, // we only have 0 or more moves + kIsA_MoreThanMoves, // we have verbs other than just move + kIsA_Oval, // we are 0 or more moves followed by an oval + kIsA_RRect, // we are 0 or more moves followed by a rrect + }; + IsA fIsA = kIsA_JustMoves; + int fIsAStart = -1; // tracks direction iff fIsA is not unknown + bool fIsACCW = false; // tracks direction iff fIsA is not unknown + + int countVerbs() const { return fVerbs.size(); } + + // called right before we add a (non-move) verb + void ensureMove() { + fIsA = kIsA_MoreThanMoves; + if (fNeedsMoveVerb) { + this->moveTo(fLastMovePoint); + } + } + + SkPath make(sk_sp) const; + + SkPathBuilder& privateReverseAddPath(const SkPath&); + + friend class SkPathPriv; +}; + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathEffect.h new file mode 100644 index 00000000000000..abb370c52af58e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathEffect.h @@ -0,0 +1,106 @@ +/* + * 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 SkPathEffect_DEFINED +#define SkPathEffect_DEFINED + +#include "include/core/SkFlattenable.h" +#include "include/core/SkScalar.h" +// not needed, but some of our clients need it (they don't IWYU) +#include "include/core/SkPath.h" + +class SkPath; +struct SkRect; +class SkStrokeRec; + +/** \class SkPathEffect + + SkPathEffect is the base class for objects in the SkPaint that affect + the geometry of a drawing primitive before it is transformed by the + canvas' matrix and drawn. + + Dashing is implemented as a subclass of SkPathEffect. +*/ +class SK_API SkPathEffect : public SkFlattenable { +public: + /** + * Returns a patheffect that apples each effect (first and second) to the original path, + * and returns a path with the sum of these. + * + * result = first(path) + second(path) + * + */ + static sk_sp MakeSum(sk_sp first, sk_sp second); + + /** + * Returns a patheffect that applies the inner effect to the path, and then applies the + * outer effect to the result of the inner's. + * + * result = outer(inner(path)) + */ + static sk_sp MakeCompose(sk_sp outer, sk_sp inner); + + static SkFlattenable::Type GetFlattenableType() { + return kSkPathEffect_Type; + } + + // move to base? + + enum DashType { + kNone_DashType, //!< ignores the info parameter + kDash_DashType, //!< fills in all of the info parameter + }; + + struct DashInfo { + DashInfo() : fIntervals(nullptr), fCount(0), fPhase(0) {} + DashInfo(SkScalar* intervals, int32_t count, SkScalar phase) + : fIntervals(intervals), fCount(count), fPhase(phase) {} + + SkScalar* fIntervals; //!< Length of on/off intervals for dashed lines + // Even values represent ons, and odds offs + int32_t fCount; //!< Number of intervals in the dash. Should be even number + SkScalar fPhase; //!< Offset into the dashed interval pattern + // mod the sum of all intervals + }; + + DashType asADash(DashInfo* info) const; + + /** + * Given a src path (input) and a stroke-rec (input and output), apply + * this effect to the src path, returning the new path in dst, and return + * true. If this effect cannot be applied, return false and ignore dst + * and stroke-rec. + * + * The stroke-rec specifies the initial request for stroking (if any). + * The effect can treat this as input only, or it can choose to change + * the rec as well. For example, the effect can decide to change the + * stroke's width or join, or the effect can change the rec from stroke + * to fill (or fill to stroke) in addition to returning a new (dst) path. + * + * If this method returns true, the caller will apply (as needed) the + * resulting stroke-rec to dst and then draw. + */ + bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR) const; + + /** Version of filterPath that can be called when the CTM is known. */ + bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR, + const SkMatrix& ctm) const; + + /** True if this path effect requires a valid CTM */ + bool needsCTM() const; + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr); + +private: + SkPathEffect() = default; + friend class SkPathEffectBase; + + using INHERITED = SkFlattenable; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathMeasure.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathMeasure.h new file mode 100644 index 00000000000000..167b18278d923d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathMeasure.h @@ -0,0 +1,88 @@ +/* + * 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 SkPathMeasure_DEFINED +#define SkPathMeasure_DEFINED + +#include "include/core/SkContourMeasure.h" +#include "include/core/SkPath.h" +#include "include/private/base/SkTDArray.h" + +class SK_API SkPathMeasure { +public: + SkPathMeasure(); + /** Initialize the pathmeasure with the specified path. The parts of the path that are needed + * are copied, so the client is free to modify/delete the path after this call. + * + * resScale controls the precision of the measure. values > 1 increase the + * precision (and possibly slow down the computation). + */ + SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale = 1); + ~SkPathMeasure(); + + /** Reset the pathmeasure with the specified path. The parts of the path that are needed + * are copied, so the client is free to modify/delete the path after this call.. + */ + void setPath(const SkPath*, bool forceClosed); + + /** Return the total length of the current contour, or 0 if no path + is associated (e.g. resetPath(null)) + */ + SkScalar getLength(); + + /** Pins distance to 0 <= distance <= getLength(), and then computes + the corresponding position and tangent. + Returns false if there is no path, or a zero-length path was specified, in which case + position and tangent are unchanged. + */ + bool SK_WARN_UNUSED_RESULT getPosTan(SkScalar distance, SkPoint* position, + SkVector* tangent); + + enum MatrixFlags { + kGetPosition_MatrixFlag = 0x01, + kGetTangent_MatrixFlag = 0x02, + kGetPosAndTan_MatrixFlag = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag + }; + + /** Pins distance to 0 <= distance <= getLength(), and then computes + the corresponding matrix (by calling getPosTan). + Returns false if there is no path, or a zero-length path was specified, in which case + matrix is unchanged. + */ + bool SK_WARN_UNUSED_RESULT getMatrix(SkScalar distance, SkMatrix* matrix, + MatrixFlags flags = kGetPosAndTan_MatrixFlag); + + /** Given a start and stop distance, return in dst the intervening segment(s). + If the segment is zero-length, return false, else return true. + startD and stopD are pinned to legal values (0..getLength()). If startD > stopD + then return false (and leave dst untouched). + Begin the segment with a moveTo if startWithMoveTo is true + */ + bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo); + + /** Return true if the current contour is closed() + */ + bool isClosed(); + + /** Move to the next contour in the path. Return true if one exists, or false if + we're done with the path. + */ + bool nextContour(); + +#ifdef SK_DEBUG + void dump(); +#endif + +private: + SkContourMeasureIter fIter; + sk_sp fContour; + + SkPathMeasure(const SkPathMeasure&) = delete; + SkPathMeasure& operator=(const SkPathMeasure&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathTypes.h new file mode 100644 index 00000000000000..963a6bda00b007 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathTypes.h @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPathTypes_DEFINED +#define SkPathTypes_DEFINED + +enum class SkPathFillType { + /** Specifies that "inside" is computed by a non-zero sum of signed edge crossings */ + kWinding, + /** Specifies that "inside" is computed by an odd number of edge crossings */ + kEvenOdd, + /** Same as Winding, but draws outside of the path, rather than inside */ + kInverseWinding, + /** Same as EvenOdd, but draws outside of the path, rather than inside */ + kInverseEvenOdd +}; + +static inline bool SkPathFillType_IsEvenOdd(SkPathFillType ft) { + return (static_cast(ft) & 1) != 0; +} + +static inline bool SkPathFillType_IsInverse(SkPathFillType ft) { + return (static_cast(ft) & 2) != 0; +} + +static inline SkPathFillType SkPathFillType_ConvertToNonInverse(SkPathFillType ft) { + return static_cast(static_cast(ft) & 1); +} + +enum class SkPathDirection { + /** clockwise direction for adding closed contours */ + kCW, + /** counter-clockwise direction for adding closed contours */ + kCCW, +}; + +enum SkPathSegmentMask { + kLine_SkPathSegmentMask = 1 << 0, + kQuad_SkPathSegmentMask = 1 << 1, + kConic_SkPathSegmentMask = 1 << 2, + kCubic_SkPathSegmentMask = 1 << 3, +}; + +enum class SkPathVerb { + kMove, //!< SkPath::RawIter returns 1 point + kLine, //!< SkPath::RawIter returns 2 points + kQuad, //!< SkPath::RawIter returns 3 points + kConic, //!< SkPath::RawIter returns 3 points + 1 weight + kCubic, //!< SkPath::RawIter returns 4 points + kClose //!< SkPath::RawIter returns 0 points +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathUtils.h new file mode 100644 index 00000000000000..6285da79960334 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPathUtils.h @@ -0,0 +1,42 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkPathUtils_DEFINED +#define SkPathUtils_DEFINED + +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkMatrix; +class SkPaint; +class SkPath; +struct SkRect; + +namespace skpathutils { + +/** Returns the filled equivalent of the stroked path. + + @param src SkPath read to create a filled version + @param paint SkPaint, from which attributes such as stroke cap, width, miter, and join, + as well as pathEffect will be used. + @param dst resulting SkPath; may be the same as src, but may not be nullptr + @param cullRect optional limit passed to SkPathEffect + @param resScale if > 1, increase precision, else if (0 < resScale < 1) reduce precision + to favor speed and size + @return true if the dst path was updated, false if it was not (e.g. if the path + represents hairline and cannot be filled). +*/ +SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, + const SkRect *cullRect, SkScalar resScale = 1); + +SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, + const SkRect *cullRect, const SkMatrix &ctm); + +SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst); + +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPicture.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPicture.h new file mode 100644 index 00000000000000..bb384dfab1b8cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPicture.h @@ -0,0 +1,278 @@ +/* + * Copyright 2007 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 SkPicture_DEFINED +#define SkPicture_DEFINED + +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkShader.h" +#include "include/core/SkTileMode.h" +#include "include/core/SkTypes.h" + +class SkCanvas; +class SkData; +struct SkDeserialProcs; +class SkImage; +class SkMatrix; +struct SkSerialProcs; +class SkStream; +class SkWStream; + +/** \class SkPicture + SkPicture records drawing commands made to SkCanvas. The command stream may be + played in whole or in part at a later time. + + SkPicture is an abstract class. SkPicture may be generated by SkPictureRecorder + or SkDrawable, or from SkPicture previously saved to SkData or SkStream. + + SkPicture may contain any SkCanvas drawing command, as well as one or more + SkCanvas matrix or SkCanvas clip. SkPicture has a cull SkRect, which is used as + a bounding box hint. To limit SkPicture bounds, use SkCanvas clip when + recording or drawing SkPicture. +*/ +class SK_API SkPicture : public SkRefCnt { +public: + ~SkPicture() override; + + /** Recreates SkPicture that was serialized into a stream. Returns constructed SkPicture + if successful; otherwise, returns nullptr. Fails if data does not permit + constructing valid SkPicture. + + procs->fPictureProc permits supplying a custom function to decode SkPicture. + If procs->fPictureProc is nullptr, default decoding is used. procs->fPictureCtx + may be used to provide user context to procs->fPictureProc; procs->fPictureProc + is called with a pointer to data, data byte length, and user context. + + @param stream container for serial data + @param procs custom serial data decoders; may be nullptr + @return SkPicture constructed from stream data + */ + static sk_sp MakeFromStream(SkStream* stream, + const SkDeserialProcs* procs = nullptr); + + /** Recreates SkPicture that was serialized into data. Returns constructed SkPicture + if successful; otherwise, returns nullptr. Fails if data does not permit + constructing valid SkPicture. + + procs->fPictureProc permits supplying a custom function to decode SkPicture. + If procs->fPictureProc is nullptr, default decoding is used. procs->fPictureCtx + may be used to provide user context to procs->fPictureProc; procs->fPictureProc + is called with a pointer to data, data byte length, and user context. + + @param data container for serial data + @param procs custom serial data decoders; may be nullptr + @return SkPicture constructed from data + */ + static sk_sp MakeFromData(const SkData* data, + const SkDeserialProcs* procs = nullptr); + + /** + + @param data pointer to serial data + @param size size of data + @param procs custom serial data decoders; may be nullptr + @return SkPicture constructed from data + */ + static sk_sp MakeFromData(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr); + + /** \class SkPicture::AbortCallback + AbortCallback is an abstract class. An implementation of AbortCallback may + passed as a parameter to SkPicture::playback, to stop it before all drawing + commands have been processed. + + If AbortCallback::abort returns true, SkPicture::playback is interrupted. + */ + class SK_API AbortCallback { + public: + /** Has no effect. + */ + virtual ~AbortCallback() = default; + + /** Stops SkPicture playback when some condition is met. A subclass of + AbortCallback provides an override for abort() that can stop SkPicture::playback. + + The part of SkPicture drawn when aborted is undefined. SkPicture instantiations are + free to stop drawing at different points during playback. + + If the abort happens inside one or more calls to SkCanvas::save(), stack + of SkCanvas matrix and SkCanvas clip values is restored to its state before + SkPicture::playback was called. + + @return true to stop playback + + example: https://fiddle.skia.org/c/@Picture_AbortCallback_abort + */ + virtual bool abort() = 0; + + protected: + AbortCallback() = default; + AbortCallback(const AbortCallback&) = delete; + AbortCallback& operator=(const AbortCallback&) = delete; + }; + + /** Replays the drawing commands on the specified canvas. In the case that the + commands are recorded, each command in the SkPicture is sent separately to canvas. + + To add a single command to draw SkPicture to recording canvas, call + SkCanvas::drawPicture instead. + + @param canvas receiver of drawing commands + @param callback allows interruption of playback + + example: https://fiddle.skia.org/c/@Picture_playback + */ + virtual void playback(SkCanvas* canvas, AbortCallback* callback = nullptr) const = 0; + + /** Returns cull SkRect for this picture, passed in when SkPicture was created. + Returned SkRect does not specify clipping SkRect for SkPicture; cull is hint + of SkPicture bounds. + + SkPicture is free to discard recorded drawing commands that fall outside + cull. + + @return bounds passed when SkPicture was created + + example: https://fiddle.skia.org/c/@Picture_cullRect + */ + virtual SkRect cullRect() const = 0; + + /** Returns a non-zero value unique among SkPicture in Skia process. + + @return identifier for SkPicture + */ + uint32_t uniqueID() const { return fUniqueID; } + + /** Returns storage containing SkData describing SkPicture, using optional custom + encoders. + + procs->fPictureProc permits supplying a custom function to encode SkPicture. + If procs->fPictureProc is nullptr, default encoding is used. procs->fPictureCtx + may be used to provide user context to procs->fPictureProc; procs->fPictureProc + is called with a pointer to SkPicture and user context. + + @param procs custom serial data encoders; may be nullptr + @return storage containing serialized SkPicture + + example: https://fiddle.skia.org/c/@Picture_serialize + */ + sk_sp serialize(const SkSerialProcs* procs = nullptr) const; + + /** Writes picture to stream, using optional custom encoders. + + procs->fPictureProc permits supplying a custom function to encode SkPicture. + If procs->fPictureProc is nullptr, default encoding is used. procs->fPictureCtx + may be used to provide user context to procs->fPictureProc; procs->fPictureProc + is called with a pointer to SkPicture and user context. + + @param stream writable serial data stream + @param procs custom serial data encoders; may be nullptr + + example: https://fiddle.skia.org/c/@Picture_serialize_2 + */ + void serialize(SkWStream* stream, const SkSerialProcs* procs = nullptr) const; + + /** Returns a placeholder SkPicture. Result does not draw, and contains only + cull SkRect, a hint of its bounds. Result is immutable; it cannot be changed + later. Result identifier is unique. + + Returned placeholder can be intercepted during playback to insert other + commands into SkCanvas draw stream. + + @param cull placeholder dimensions + @return placeholder with unique identifier + + example: https://fiddle.skia.org/c/@Picture_MakePlaceholder + */ + static sk_sp MakePlaceholder(SkRect cull); + + /** Returns the approximate number of operations in SkPicture. Returned value + may be greater or less than the number of SkCanvas calls + recorded: some calls may be recorded as more than one operation, other + calls may be optimized away. + + @param nested if true, include the op-counts of nested pictures as well, else + just return count the ops in the top-level picture. + @return approximate operation count + + example: https://fiddle.skia.org/c/@Picture_approximateOpCount + */ + virtual int approximateOpCount(bool nested = false) const = 0; + + /** Returns the approximate byte size of SkPicture. Does not include large objects + referenced by SkPicture. + + @return approximate size + + example: https://fiddle.skia.org/c/@Picture_approximateBytesUsed + */ + virtual size_t approximateBytesUsed() const = 0; + + /** Return a new shader that will draw with this picture. + * + * @param tmx The tiling mode to use when sampling in the x-direction. + * @param tmy The tiling mode to use when sampling in the y-direction. + * @param mode How to filter the tiles + * @param localMatrix Optional matrix used when sampling + * @param tile The tile rectangle in picture coordinates: this represents the subset + * (or superset) of the picture used when building a tile. It is not + * affected by localMatrix and does not imply scaling (only translation + * and cropping). If null, the tile rect is considered equal to the picture + * bounds. + * @return Returns a new shader object. Note: this function never returns null. + */ + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, + const SkMatrix* localMatrix, const SkRect* tileRect) const; + + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode) const { + return this->makeShader(tmx, tmy, mode, nullptr, nullptr); + } + +private: + // Allowed subclasses. + SkPicture(); + friend class SkBigPicture; + friend class SkEmptyPicture; + friend class SkPicturePriv; + + void serialize(SkWStream*, const SkSerialProcs*, class SkRefCntSet* typefaces, + bool textBlobsOnly=false) const; + static sk_sp MakeFromStreamPriv(SkStream*, const SkDeserialProcs*, + class SkTypefacePlayback*, + int recursionLimit); + friend class SkPictureData; + + /** Return true if the SkStream/Buffer represents a serialized picture, and + fills out SkPictInfo. After this function returns, the data source is not + rewound so it will have to be manually reset before passing to + MakeFromStream or MakeFromBuffer. Note, MakeFromStream and + MakeFromBuffer perform this check internally so these entry points are + intended for stand alone tools. + If false is returned, SkPictInfo is unmodified. + */ + static bool StreamIsSKP(SkStream*, struct SkPictInfo*); + static bool BufferIsSKP(class SkReadBuffer*, struct SkPictInfo*); + friend bool SkPicture_StreamIsSKP(SkStream*, struct SkPictInfo*); + + // Returns NULL if this is not an SkBigPicture. + virtual const class SkBigPicture* asSkBigPicture() const { return nullptr; } + + static bool IsValidPictInfo(const struct SkPictInfo& info); + static sk_sp Forwardport(const struct SkPictInfo&, + const class SkPictureData*, + class SkReadBuffer* buffer); + + struct SkPictInfo createHeader() const; + class SkPictureData* backport() const; + + uint32_t fUniqueID; + mutable std::atomic fAddedToCache{false}; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPictureRecorder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPictureRecorder.h new file mode 100644 index 00000000000000..d91d105000ef07 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPictureRecorder.h @@ -0,0 +1,115 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPictureRecorder_DEFINED +#define SkPictureRecorder_DEFINED + +#include "include/core/SkBBHFactory.h" +#include "include/core/SkPicture.h" +#include "include/core/SkRefCnt.h" + +#include + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK +namespace android { + class Picture; +}; +#endif + +class SkCanvas; +class SkDrawable; +class SkPictureRecord; +class SkRecord; +class SkRecorder; + +class SK_API SkPictureRecorder { +public: + SkPictureRecorder(); + ~SkPictureRecorder(); + + enum FinishFlags { + }; + + /** Returns the canvas that records the drawing commands. + @param bounds the cull rect used when recording this picture. Any drawing the falls outside + of this rect is undefined, and may be drawn or it may not. + @param bbh optional acceleration structure + @param recordFlags optional flags that control recording. + @return the canvas. + */ + SkCanvas* beginRecording(const SkRect& bounds, sk_sp bbh); + + SkCanvas* beginRecording(const SkRect& bounds, SkBBHFactory* bbhFactory = nullptr); + + SkCanvas* beginRecording(SkScalar width, SkScalar height, + SkBBHFactory* bbhFactory = nullptr) { + return this->beginRecording(SkRect::MakeWH(width, height), bbhFactory); + } + + /** Returns the recording canvas if one is active, or NULL if recording is + not active. This does not alter the refcnt on the canvas (if present). + */ + SkCanvas* getRecordingCanvas(); + + /** + * Signal that the caller is done recording. This invalidates the canvas returned by + * beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who + * must call unref() when they are done using it. + * + * The returned picture is immutable. If during recording drawables were added to the canvas, + * these will have been "drawn" into a recording canvas, so that this resulting picture will + * reflect their current state, but will not contain a live reference to the drawables + * themselves. + */ + sk_sp finishRecordingAsPicture(); + + /** + * Signal that the caller is done recording, and update the cull rect to use for bounding + * box hierarchy (BBH) generation. The behavior is the same as calling + * finishRecordingAsPicture(), except that this method updates the cull rect initially passed + * into beginRecording. + * @param cullRect the new culling rectangle to use as the overall bound for BBH generation + * and subsequent culling operations. + * @return the picture containing the recorded content. + */ + sk_sp finishRecordingAsPictureWithCull(const SkRect& cullRect); + + /** + * Signal that the caller is done recording. This invalidates the canvas returned by + * beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who + * must call unref() when they are done using it. + * + * Unlike finishRecordingAsPicture(), which returns an immutable picture, the returned drawable + * may contain live references to other drawables (if they were added to the recording canvas) + * and therefore this drawable will reflect the current state of those nested drawables anytime + * it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()). + */ + sk_sp finishRecordingAsDrawable(); + +private: + void reset(); + + /** Replay the current (partially recorded) operation stream into + canvas. This call doesn't close the current recording. + */ +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + friend class android::Picture; +#endif + friend class SkPictureRecorderReplayTester; // for unit testing + void partialReplay(SkCanvas* canvas) const; + + bool fActivelyRecording; + SkRect fCullRect; + sk_sp fBBH; + std::unique_ptr fRecorder; + sk_sp fRecord; + + SkPictureRecorder(SkPictureRecorder&&) = delete; + SkPictureRecorder& operator=(SkPictureRecorder&&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPixelRef.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPixelRef.h new file mode 100644 index 00000000000000..12779890f88592 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPixelRef.h @@ -0,0 +1,119 @@ +/* + * Copyright 2008 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 SkPixelRef_DEFINED +#define SkPixelRef_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/private/SkIDChangeListener.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include + +class SkDiscardableMemory; + +/** \class SkPixelRef + + This class is the smart container for pixel memory, and is used with SkBitmap. + This class can be shared/accessed between multiple threads. +*/ +class SK_API SkPixelRef : public SkRefCnt { +public: + SkPixelRef(int width, int height, void* addr, size_t rowBytes); + ~SkPixelRef() override; + + SkISize dimensions() const { return {fWidth, fHeight}; } + int width() const { return fWidth; } + int height() const { return fHeight; } + void* pixels() const { return fPixels; } + size_t rowBytes() const { return fRowBytes; } + + /** Returns a non-zero, unique value corresponding to the pixels in this + pixelref. Each time the pixels are changed (and notifyPixelsChanged is + called), a different generation ID will be returned. + */ + uint32_t getGenerationID() const; + + /** + * Call this if you have changed the contents of the pixels. This will in- + * turn cause a different generation ID value to be returned from + * getGenerationID(). + */ + void notifyPixelsChanged(); + + /** Returns true if this pixelref is marked as immutable, meaning that the + contents of its pixels will not change for the lifetime of the pixelref. + */ + bool isImmutable() const { return fMutability != kMutable; } + + /** Marks this pixelref is immutable, meaning that the contents of its + pixels will not change for the lifetime of the pixelref. This state can + be set on a pixelref, but it cannot be cleared once it is set. + */ + void setImmutable(); + + // Register a listener that may be called the next time our generation ID changes. + // + // We'll only call the listener if we're confident that we are the only SkPixelRef with this + // generation ID. If our generation ID changes and we decide not to call the listener, we'll + // never call it: you must add a new listener for each generation ID change. We also won't call + // the listener when we're certain no one knows what our generation ID is. + // + // This can be used to invalidate caches keyed by SkPixelRef generation ID. + // Takes ownership of listener. Threadsafe. + void addGenIDChangeListener(sk_sp listener); + + // Call when this pixelref is part of the key to a resourcecache entry. This allows the cache + // to know automatically those entries can be purged when this pixelref is changed or deleted. + void notifyAddedToCache() { + fAddedToCache.store(true); + } + + virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return nullptr; } + +protected: + void android_only_reset(int width, int height, size_t rowBytes); + +private: + int fWidth; + int fHeight; + void* fPixels; + size_t fRowBytes; + + // Bottom bit indicates the Gen ID is unique. + bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); } + mutable std::atomic fTaggedGenID; + + SkIDChangeListener::List fGenIDChangeListeners; + + // Set true by caches when they cache content that's derived from the current pixels. + std::atomic fAddedToCache; + + enum Mutability { + kMutable, // PixelRefs begin mutable. + kTemporarilyImmutable, // Considered immutable, but can revert to mutable. + kImmutable, // Once set to this state, it never leaves. + } fMutability : 8; // easily fits inside a byte + + void needsNewGenID(); + void callGenIDChangeListeners(); + + void setTemporarilyImmutable(); + void restoreMutability(); + friend class SkSurface_Raster; // For temporary immutable methods above. + + void setImmutableWithID(uint32_t genID); + friend void SkBitmapCache_setImmutableWithID(SkPixelRef*, uint32_t); + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPixmap.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPixmap.h new file mode 100644 index 00000000000000..ad4c7dd6d8464c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPixmap.h @@ -0,0 +1,732 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPixmap_DEFINED +#define SkPixmap_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkColorType.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkSize.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkAttributes.h" + +#include +#include + +class SkColorSpace; +enum SkAlphaType : int; +struct SkMask; + +/** \class SkPixmap + SkPixmap provides a utility to pair SkImageInfo with pixels and row bytes. + SkPixmap is a low level class which provides convenience functions to access + raster destinations. SkCanvas can not draw SkPixmap, nor does SkPixmap provide + a direct drawing destination. + + Use SkBitmap to draw pixels referenced by SkPixmap; use SkSurface to draw into + pixels referenced by SkPixmap. + + SkPixmap does not try to manage the lifetime of the pixel memory. Use SkPixelRef + to manage pixel memory; SkPixelRef is safe across threads. +*/ +class SK_API SkPixmap { +public: + + /** Creates an empty SkPixmap without pixels, with kUnknown_SkColorType, with + kUnknown_SkAlphaType, and with a width and height of zero. Use + reset() to associate pixels, SkColorType, SkAlphaType, width, and height + after SkPixmap has been created. + + @return empty SkPixmap + */ + SkPixmap() + : fPixels(nullptr), fRowBytes(0), fInfo(SkImageInfo::MakeUnknown(0, 0)) + {} + + /** Creates SkPixmap from info width, height, SkAlphaType, and SkColorType. + addr points to pixels, or nullptr. rowBytes should be info.width() times + info.bytesPerPixel(), or larger. + + No parameter checking is performed; it is up to the caller to ensure that + addr and rowBytes agree with info. + + The memory lifetime of pixels is managed by the caller. When SkPixmap goes + out of scope, addr is unaffected. + + SkPixmap may be later modified by reset() to change its size, pixel type, or + storage. + + @param info width, height, SkAlphaType, SkColorType of SkImageInfo + @param addr pointer to pixels allocated by caller; may be nullptr + @param rowBytes size of one row of addr; width times pixel size, or larger + @return initialized SkPixmap + */ + SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes) + : fPixels(addr), fRowBytes(rowBytes), fInfo(info) + {} + + /** Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to + kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType. + + The prior pixels are unaffected; it is up to the caller to release pixels + memory if desired. + + example: https://fiddle.skia.org/c/@Pixmap_reset + */ + void reset(); + + /** Sets width, height, SkAlphaType, and SkColorType from info. + Sets pixel address from addr, which may be nullptr. + Sets row bytes from rowBytes, which should be info.width() times + info.bytesPerPixel(), or larger. + + Does not check addr. Asserts if built with SK_DEBUG defined and if rowBytes is + too small to hold one row of pixels. + + The memory lifetime pixels are managed by the caller. When SkPixmap goes + out of scope, addr is unaffected. + + @param info width, height, SkAlphaType, SkColorType of SkImageInfo + @param addr pointer to pixels allocated by caller; may be nullptr + @param rowBytes size of one row of addr; width times pixel size, or larger + + example: https://fiddle.skia.org/c/@Pixmap_reset_2 + */ + void reset(const SkImageInfo& info, const void* addr, size_t rowBytes); + + /** Changes SkColorSpace in SkImageInfo; preserves width, height, SkAlphaType, and + SkColorType in SkImage, and leaves pixel address and row bytes unchanged. + SkColorSpace reference count is incremented. + + @param colorSpace SkColorSpace moved to SkImageInfo + + example: https://fiddle.skia.org/c/@Pixmap_setColorSpace + */ + void setColorSpace(sk_sp colorSpace); + + /** Deprecated. + */ + bool SK_WARN_UNUSED_RESULT reset(const SkMask& mask); + + /** Sets subset width, height, pixel address to intersection of SkPixmap with area, + if intersection is not empty; and return true. Otherwise, leave subset unchanged + and return false. + + Failing to read the return value generates a compile time warning. + + @param subset storage for width, height, pixel address of intersection + @param area bounds to intersect with SkPixmap + @return true if intersection of SkPixmap and area is not empty + */ + bool SK_WARN_UNUSED_RESULT extractSubset(SkPixmap* subset, const SkIRect& area) const; + + /** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace. + + @return reference to SkImageInfo + */ + const SkImageInfo& info() const { return fInfo; } + + /** Returns row bytes, the interval from one pixel row to the next. Row bytes + is at least as large as: width() * info().bytesPerPixel(). + + Returns zero if colorType() is kUnknown_SkColorType. + It is up to the SkBitmap creator to ensure that row bytes is a useful value. + + @return byte length of pixel row + */ + size_t rowBytes() const { return fRowBytes; } + + /** Returns pixel address, the base address corresponding to the pixel origin. + + It is up to the SkPixmap creator to ensure that pixel address is a useful value. + + @return pixel address + */ + const void* addr() const { return fPixels; } + + /** Returns pixel count in each pixel row. Should be equal or less than: + rowBytes() / info().bytesPerPixel(). + + @return pixel width in SkImageInfo + */ + int width() const { return fInfo.width(); } + + /** Returns pixel row count. + + @return pixel height in SkImageInfo + */ + int height() const { return fInfo.height(); } + + /** + * Return the dimensions of the pixmap (from its ImageInfo) + */ + SkISize dimensions() const { return fInfo.dimensions(); } + + SkColorType colorType() const { return fInfo.colorType(); } + + SkAlphaType alphaType() const { return fInfo.alphaType(); } + + /** Returns SkColorSpace, the range of colors, associated with SkImageInfo. The + reference count of SkColorSpace is unchanged. The returned SkColorSpace is + immutable. + + @return SkColorSpace in SkImageInfo, or nullptr + */ + SkColorSpace* colorSpace() const; + + /** Returns smart pointer to SkColorSpace, the range of colors, associated with + SkImageInfo. The smart pointer tracks the number of objects sharing this + SkColorSpace reference so the memory is released when the owners destruct. + + The returned SkColorSpace is immutable. + + @return SkColorSpace in SkImageInfo wrapped in a smart pointer + */ + sk_sp refColorSpace() const; + + /** Returns true if SkAlphaType is kOpaque_SkAlphaType. + Does not check if SkColorType allows alpha, or if any pixel value has + transparency. + + @return true if SkImageInfo has opaque SkAlphaType + */ + bool isOpaque() const { return fInfo.isOpaque(); } + + /** Returns SkIRect { 0, 0, width(), height() }. + + @return integral rectangle from origin to width() and height() + */ + SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); } + + /** Returns number of pixels that fit on row. Should be greater than or equal to + width(). + + @return maximum pixels per row + */ + int rowBytesAsPixels() const { return int(fRowBytes >> this->shiftPerPixel()); } + + /** Returns bit shift converting row bytes to row pixels. + Returns zero for kUnknown_SkColorType. + + @return one of: 0, 1, 2, 3; left shift to convert pixels to bytes + */ + int shiftPerPixel() const { return fInfo.shiftPerPixel(); } + + /** Returns minimum memory required for pixel storage. + Does not include unused memory on last row when rowBytesAsPixels() exceeds width(). + Returns SIZE_MAX if result does not fit in size_t. + Returns zero if height() or width() is 0. + Returns height() times rowBytes() if colorType() is kUnknown_SkColorType. + + @return size in bytes of image buffer + */ + size_t computeByteSize() const { return fInfo.computeByteSize(fRowBytes); } + + /** Returns true if all pixels are opaque. SkColorType determines how pixels + are encoded, and whether pixel describes alpha. Returns true for SkColorType + without alpha in each pixel; for other SkColorType, returns true if all + pixels have alpha values equivalent to 1.0 or greater. + + For SkColorType kRGB_565_SkColorType or kGray_8_SkColorType: always + returns true. For SkColorType kAlpha_8_SkColorType, kBGRA_8888_SkColorType, + kRGBA_8888_SkColorType: returns true if all pixel alpha values are 255. + For SkColorType kARGB_4444_SkColorType: returns true if all pixel alpha values are 15. + For kRGBA_F16_SkColorType: returns true if all pixel alpha values are 1.0 or + greater. + + Returns false for kUnknown_SkColorType. + + @return true if all pixels have opaque values or SkColorType is opaque + + example: https://fiddle.skia.org/c/@Pixmap_computeIsOpaque + */ + bool computeIsOpaque() const; + + /** Returns pixel at (x, y) as unpremultiplied color. + Returns black with alpha if SkColorType is kAlpha_8_SkColorType. + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined; and returns undefined values or may crash if + SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or + pixel address is nullptr. + + SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the + conversion to unpremultiplied color; original pixel data may have additional + precision. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return pixel converted to unpremultiplied color + + example: https://fiddle.skia.org/c/@Pixmap_getColor + */ + SkColor getColor(int x, int y) const; + + /** Returns pixel at (x, y) as unpremultiplied color as an SkColor4f. + Returns black with alpha if SkColorType is kAlpha_8_SkColorType. + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined; and returns undefined values or may crash if + SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or + pixel address is nullptr. + + SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the + conversion to unpremultiplied color; original pixel data may have additional + precision, though this is less likely than for getColor(). Rounding errors may + occur if the underlying type has lower precision. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return pixel converted to unpremultiplied float color + */ + SkColor4f getColor4f(int x, int y) const; + + /** Look up the pixel at (x,y) and return its alpha component, normalized to [0..1]. + This is roughly equivalent to SkGetColorA(getColor()), but can be more efficent + (and more precise if the pixels store more than 8 bits per component). + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return alpha converted to normalized float + */ + float getAlphaf(int x, int y) const; + + /** Returns readable pixel address at (x, y). Returns nullptr if SkPixelRef is nullptr. + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. Returns nullptr if SkColorType is kUnknown_SkColorType. + + Performs a lookup of pixel size; for better performance, call + one of: addr8, addr16, addr32, addr64, or addrF16(). + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return readable generic pointer to pixel + */ + const void* addr(int x, int y) const { + return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes); + } + + /** Returns readable base pixel address. Result is addressable as unsigned 8-bit bytes. + Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType or + kGray_8_SkColorType, and is built with SK_DEBUG defined. + + One byte corresponds to one pixel. + + @return readable unsigned 8-bit pointer to pixels + */ + const uint8_t* addr8() const { + SkASSERT(1 == fInfo.bytesPerPixel()); + return reinterpret_cast(fPixels); + } + + /** Returns readable base pixel address. Result is addressable as unsigned 16-bit words. + Will trigger an assert() if SkColorType is not kRGB_565_SkColorType or + kARGB_4444_SkColorType, and is built with SK_DEBUG defined. + + One word corresponds to one pixel. + + @return readable unsigned 16-bit pointer to pixels + */ + const uint16_t* addr16() const { + SkASSERT(2 == fInfo.bytesPerPixel()); + return reinterpret_cast(fPixels); + } + + /** Returns readable base pixel address. Result is addressable as unsigned 32-bit words. + Will trigger an assert() if SkColorType is not kRGBA_8888_SkColorType or + kBGRA_8888_SkColorType, and is built with SK_DEBUG defined. + + One word corresponds to one pixel. + + @return readable unsigned 32-bit pointer to pixels + */ + const uint32_t* addr32() const { + SkASSERT(4 == fInfo.bytesPerPixel()); + return reinterpret_cast(fPixels); + } + + /** Returns readable base pixel address. Result is addressable as unsigned 64-bit words. + Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built + with SK_DEBUG defined. + + One word corresponds to one pixel. + + @return readable unsigned 64-bit pointer to pixels + */ + const uint64_t* addr64() const { + SkASSERT(8 == fInfo.bytesPerPixel()); + return reinterpret_cast(fPixels); + } + + /** Returns readable base pixel address. Result is addressable as unsigned 16-bit words. + Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built + with SK_DEBUG defined. + + Each word represents one color component encoded as a half float. + Four words correspond to one pixel. + + @return readable unsigned 16-bit pointer to first component of pixels + */ + const uint16_t* addrF16() const { + SkASSERT(8 == fInfo.bytesPerPixel()); + SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType() || + kRGBA_F16Norm_SkColorType == fInfo.colorType()); + return reinterpret_cast(fPixels); + } + + /** Returns readable pixel address at (x, y). + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. + + Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType or + kGray_8_SkColorType, and is built with SK_DEBUG defined. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return readable unsigned 8-bit pointer to pixel at (x, y) + */ + const uint8_t* addr8(int x, int y) const { + SkASSERT((unsigned)x < (unsigned)fInfo.width()); + SkASSERT((unsigned)y < (unsigned)fInfo.height()); + return (const uint8_t*)((const char*)this->addr8() + (size_t)y * fRowBytes + (x << 0)); + } + + /** Returns readable pixel address at (x, y). + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. + + Will trigger an assert() if SkColorType is not kRGB_565_SkColorType or + kARGB_4444_SkColorType, and is built with SK_DEBUG defined. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return readable unsigned 16-bit pointer to pixel at (x, y) + */ + const uint16_t* addr16(int x, int y) const { + SkASSERT((unsigned)x < (unsigned)fInfo.width()); + SkASSERT((unsigned)y < (unsigned)fInfo.height()); + return (const uint16_t*)((const char*)this->addr16() + (size_t)y * fRowBytes + (x << 1)); + } + + /** Returns readable pixel address at (x, y). + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. + + Will trigger an assert() if SkColorType is not kRGBA_8888_SkColorType or + kBGRA_8888_SkColorType, and is built with SK_DEBUG defined. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return readable unsigned 32-bit pointer to pixel at (x, y) + */ + const uint32_t* addr32(int x, int y) const { + SkASSERT((unsigned)x < (unsigned)fInfo.width()); + SkASSERT((unsigned)y < (unsigned)fInfo.height()); + return (const uint32_t*)((const char*)this->addr32() + (size_t)y * fRowBytes + (x << 2)); + } + + /** Returns readable pixel address at (x, y). + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. + + Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built + with SK_DEBUG defined. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return readable unsigned 64-bit pointer to pixel at (x, y) + */ + const uint64_t* addr64(int x, int y) const { + SkASSERT((unsigned)x < (unsigned)fInfo.width()); + SkASSERT((unsigned)y < (unsigned)fInfo.height()); + return (const uint64_t*)((const char*)this->addr64() + (size_t)y * fRowBytes + (x << 3)); + } + + /** Returns readable pixel address at (x, y). + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. + + Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built + with SK_DEBUG defined. + + Each unsigned 16-bit word represents one color component encoded as a half float. + Four words correspond to one pixel. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return readable unsigned 16-bit pointer to pixel component at (x, y) + */ + const uint16_t* addrF16(int x, int y) const { + SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType() || + kRGBA_F16Norm_SkColorType == fInfo.colorType()); + return reinterpret_cast(this->addr64(x, y)); + } + + /** Returns writable base pixel address. + + @return writable generic base pointer to pixels + */ + void* writable_addr() const { return const_cast(fPixels); } + + /** Returns writable pixel address at (x, y). + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined. Returns zero if SkColorType is kUnknown_SkColorType. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return writable generic pointer to pixel + */ + void* writable_addr(int x, int y) const { + return const_cast(this->addr(x, y)); + } + + /** Returns writable pixel address at (x, y). Result is addressable as unsigned + 8-bit bytes. Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType + or kGray_8_SkColorType, and is built with SK_DEBUG defined. + + One byte corresponds to one pixel. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return writable unsigned 8-bit pointer to pixels + */ + uint8_t* writable_addr8(int x, int y) const { + return const_cast(this->addr8(x, y)); + } + + /** Returns writable_addr pixel address at (x, y). Result is addressable as unsigned + 16-bit words. Will trigger an assert() if SkColorType is not kRGB_565_SkColorType + or kARGB_4444_SkColorType, and is built with SK_DEBUG defined. + + One word corresponds to one pixel. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return writable unsigned 16-bit pointer to pixel + */ + uint16_t* writable_addr16(int x, int y) const { + return const_cast(this->addr16(x, y)); + } + + /** Returns writable pixel address at (x, y). Result is addressable as unsigned + 32-bit words. Will trigger an assert() if SkColorType is not + kRGBA_8888_SkColorType or kBGRA_8888_SkColorType, and is built with SK_DEBUG + defined. + + One word corresponds to one pixel. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return writable unsigned 32-bit pointer to pixel + */ + uint32_t* writable_addr32(int x, int y) const { + return const_cast(this->addr32(x, y)); + } + + /** Returns writable pixel address at (x, y). Result is addressable as unsigned + 64-bit words. Will trigger an assert() if SkColorType is not + kRGBA_F16_SkColorType and is built with SK_DEBUG defined. + + One word corresponds to one pixel. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return writable unsigned 64-bit pointer to pixel + */ + uint64_t* writable_addr64(int x, int y) const { + return const_cast(this->addr64(x, y)); + } + + /** Returns writable pixel address at (x, y). Result is addressable as unsigned + 16-bit words. Will trigger an assert() if SkColorType is not + kRGBA_F16_SkColorType and is built with SK_DEBUG defined. + + Each word represents one color component encoded as a half float. + Four words correspond to one pixel. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return writable unsigned 16-bit pointer to first component of pixel + */ + uint16_t* writable_addrF16(int x, int y) const { + return reinterpret_cast(writable_addr64(x, y)); + } + + /** Copies a SkRect of pixels to dstPixels. Copy starts at (0, 0), and does not + exceed SkPixmap (width(), height()). + + dstInfo specifies width, height, SkColorType, SkAlphaType, and + SkColorSpace of destination. dstRowBytes specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if + dstInfo address equals nullptr, or dstRowBytes is less than dstInfo.minRowBytes(). + + Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If SkPixmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If SkPixmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If SkPixmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns + false if pixel conversion is not possible. + + Returns false if SkPixmap width() or height() is zero or negative. + + @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace + @param dstPixels destination pixel storage + @param dstRowBytes destination row length + @return true if pixels are copied to dstPixels + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const { + return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0); + } + + /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not + exceed SkPixmap (width(), height()). + + dstInfo specifies width, height, SkColorType, SkAlphaType, and + SkColorSpace of destination. dstRowBytes specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if + dstInfo address equals nullptr, or dstRowBytes is less than dstInfo.minRowBytes(). + + Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If SkPixmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If SkPixmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If SkPixmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if SkPixmap width() or height() is zero or negative. Returns false if: + abs(srcX) >= Pixmap width(), or if abs(srcY) >= Pixmap height(). + + @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace + @param dstPixels destination pixel storage + @param dstRowBytes destination row length + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @return true if pixels are copied to dstPixels + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, + int srcY) const; + + /** Copies a SkRect of pixels to dst. Copy starts at (srcX, srcY), and does not + exceed SkPixmap (width(), height()). dst specifies width, height, SkColorType, + SkAlphaType, and SkColorSpace of destination. Returns true if pixels are copied. + Returns false if dst address equals nullptr, or dst.rowBytes() is less than + dst SkImageInfo::minRowBytes. + + Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.info().colorType must match. + If SkPixmap colorType() is kGray_8_SkColorType, dst.info().colorSpace must match. + If SkPixmap alphaType() is kOpaque_SkAlphaType, dst.info().alphaType must + match. If SkPixmap colorSpace() is nullptr, dst.info().colorSpace must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false SkPixmap width() or height() is zero or negative. Returns false if: + abs(srcX) >= Pixmap width(), or if abs(srcY) >= Pixmap height(). + + @param dst SkImageInfo and pixel address to write to + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @return true if pixels are copied to dst + */ + bool readPixels(const SkPixmap& dst, int srcX, int srcY) const { + return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); + } + + /** Copies pixels inside bounds() to dst. dst specifies width, height, SkColorType, + SkAlphaType, and SkColorSpace of destination. Returns true if pixels are copied. + Returns false if dst address equals nullptr, or dst.rowBytes() is less than + dst SkImageInfo::minRowBytes. + + Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If SkPixmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If SkPixmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If SkPixmap colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + Returns false if SkPixmap width() or height() is zero or negative. + + @param dst SkImageInfo and pixel address to write to + @return true if pixels are copied to dst + */ + bool readPixels(const SkPixmap& dst) const { + return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0); + } + + /** Copies SkBitmap to dst, scaling pixels to fit dst.width() and dst.height(), and + converting pixels to match dst.colorType() and dst.alphaType(). Returns true if + pixels are copied. Returns false if dst address is nullptr, or dst.rowBytes() is + less than dst SkImageInfo::minRowBytes. + + Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If SkPixmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If SkPixmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If SkPixmap colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + Returns false if SkBitmap width() or height() is zero or negative. + + @param dst SkImageInfo and pixel address to write to + @return true if pixels are scaled to fit dst + + example: https://fiddle.skia.org/c/@Pixmap_scalePixels + */ + bool scalePixels(const SkPixmap& dst, const SkSamplingOptions&) const; + + /** Writes color to pixels bounded by subset; returns true on success. + Returns false if colorType() is kUnknown_SkColorType, or if subset does + not intersect bounds(). + + @param color sRGB unpremultiplied color to write + @param subset bounding integer SkRect of written pixels + @return true if pixels are changed + + example: https://fiddle.skia.org/c/@Pixmap_erase + */ + bool erase(SkColor color, const SkIRect& subset) const; + + /** Writes color to pixels inside bounds(); returns true on success. + Returns false if colorType() is kUnknown_SkColorType, or if bounds() + is empty. + + @param color sRGB unpremultiplied color to write + @return true if pixels are changed + */ + bool erase(SkColor color) const { return this->erase(color, this->bounds()); } + + /** Writes color to pixels bounded by subset; returns true on success. + if subset is nullptr, writes colors pixels inside bounds(). Returns false if + colorType() is kUnknown_SkColorType, if subset is not nullptr and does + not intersect bounds(), or if subset is nullptr and bounds() is empty. + + @param color unpremultiplied color to write + @param subset bounding integer SkRect of pixels to write; may be nullptr + @return true if pixels are changed + */ + bool erase(const SkColor4f& color, const SkIRect* subset = nullptr) const; + +private: + const void* fPixels; + size_t fRowBytes; + SkImageInfo fInfo; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPoint.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPoint.h new file mode 100644 index 00000000000000..a5e7fa09fbab53 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPoint.h @@ -0,0 +1,568 @@ +/* + * 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 SkPoint_DEFINED +#define SkPoint_DEFINED + +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkSafe32.h" + +#include + +struct SkIPoint; + +/** SkIVector provides an alternative name for SkIPoint. SkIVector and SkIPoint + can be used interchangeably for all purposes. +*/ +typedef SkIPoint SkIVector; + +/** \struct SkIPoint + SkIPoint holds two 32-bit integer coordinates. +*/ +struct SkIPoint { + int32_t fX; //!< x-axis value + int32_t fY; //!< y-axis value + + /** Sets fX to x, fY to y. + + @param x integer x-axis value of constructed SkIPoint + @param y integer y-axis value of constructed SkIPoint + @return SkIPoint (x, y) + */ + static constexpr SkIPoint Make(int32_t x, int32_t y) { + return {x, y}; + } + + /** Returns x-axis value of SkIPoint. + + @return fX + */ + constexpr int32_t x() const { return fX; } + + /** Returns y-axis value of SkIPoint. + + @return fY + */ + constexpr int32_t y() const { return fY; } + + /** Returns true if fX and fY are both zero. + + @return true if fX is zero and fY is zero + */ + bool isZero() const { return (fX | fY) == 0; } + + /** Sets fX to x and fY to y. + + @param x new value for fX + @param y new value for fY + */ + void set(int32_t x, int32_t y) { + fX = x; + fY = y; + } + + /** Returns SkIPoint changing the signs of fX and fY. + + @return SkIPoint as (-fX, -fY) + */ + SkIPoint operator-() const { + return {-fX, -fY}; + } + + /** Offsets SkIPoint by ivector v. Sets SkIPoint to (fX + v.fX, fY + v.fY). + + @param v ivector to add + */ + void operator+=(const SkIVector& v) { + fX = Sk32_sat_add(fX, v.fX); + fY = Sk32_sat_add(fY, v.fY); + } + + /** Subtracts ivector v from SkIPoint. Sets SkIPoint to: (fX - v.fX, fY - v.fY). + + @param v ivector to subtract + */ + void operator-=(const SkIVector& v) { + fX = Sk32_sat_sub(fX, v.fX); + fY = Sk32_sat_sub(fY, v.fY); + } + + /** Returns true if SkIPoint is equivalent to SkIPoint constructed from (x, y). + + @param x value compared with fX + @param y value compared with fY + @return true if SkIPoint equals (x, y) + */ + bool equals(int32_t x, int32_t y) const { + return fX == x && fY == y; + } + + /** Returns true if a is equivalent to b. + + @param a SkIPoint to compare + @param b SkIPoint to compare + @return true if a.fX == b.fX and a.fY == b.fY + */ + friend bool operator==(const SkIPoint& a, const SkIPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + /** Returns true if a is not equivalent to b. + + @param a SkIPoint to compare + @param b SkIPoint to compare + @return true if a.fX != b.fX or a.fY != b.fY + */ + friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns ivector from b to a; computed as (a.fX - b.fX, a.fY - b.fY). + + Can also be used to subtract ivector from ivector, returning ivector. + + @param a SkIPoint or ivector to subtract from + @param b ivector to subtract + @return ivector from b to a + */ + friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) { + return { Sk32_sat_sub(a.fX, b.fX), Sk32_sat_sub(a.fY, b.fY) }; + } + + /** Returns SkIPoint resulting from SkIPoint a offset by ivector b, computed as: + (a.fX + b.fX, a.fY + b.fY). + + Can also be used to offset SkIPoint b by ivector a, returning SkIPoint. + Can also be used to add ivector to ivector, returning ivector. + + @param a SkIPoint or ivector to add to + @param b SkIPoint or ivector to add + @return SkIPoint equal to a offset by b + */ + friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) { + return { Sk32_sat_add(a.fX, b.fX), Sk32_sat_add(a.fY, b.fY) }; + } +}; + +struct SkPoint; + +/** SkVector provides an alternative name for SkPoint. SkVector and SkPoint can + be used interchangeably for all purposes. +*/ +typedef SkPoint SkVector; + +/** \struct SkPoint + SkPoint holds two 32-bit floating point coordinates. +*/ +struct SK_API SkPoint { + SkScalar fX; //!< x-axis value + SkScalar fY; //!< y-axis value + + /** Sets fX to x, fY to y. Used both to set SkPoint and vector. + + @param x SkScalar x-axis value of constructed SkPoint or vector + @param y SkScalar y-axis value of constructed SkPoint or vector + @return SkPoint (x, y) + */ + static constexpr SkPoint Make(SkScalar x, SkScalar y) { + return {x, y}; + } + + /** Returns x-axis value of SkPoint or vector. + + @return fX + */ + constexpr SkScalar x() const { return fX; } + + /** Returns y-axis value of SkPoint or vector. + + @return fY + */ + constexpr SkScalar y() const { return fY; } + + /** Returns true if fX and fY are both zero. + + @return true if fX is zero and fY is zero + */ + bool isZero() const { return (0 == fX) & (0 == fY); } + + /** Sets fX to x and fY to y. + + @param x new value for fX + @param y new value for fY + */ + void set(SkScalar x, SkScalar y) { + fX = x; + fY = y; + } + + /** Sets fX to x and fY to y, promoting integers to SkScalar values. + + Assigning a large integer value directly to fX or fY may cause a compiler + error, triggered by narrowing conversion of int to SkScalar. This safely + casts x and y to avoid the error. + + @param x new value for fX + @param y new value for fY + */ + void iset(int32_t x, int32_t y) { + fX = SkIntToScalar(x); + fY = SkIntToScalar(y); + } + + /** Sets fX to p.fX and fY to p.fY, promoting integers to SkScalar values. + + Assigning an SkIPoint containing a large integer value directly to fX or fY may + cause a compiler error, triggered by narrowing conversion of int to SkScalar. + This safely casts p.fX and p.fY to avoid the error. + + @param p SkIPoint members promoted to SkScalar + */ + void iset(const SkIPoint& p) { + fX = SkIntToScalar(p.fX); + fY = SkIntToScalar(p.fY); + } + + /** Sets fX to absolute value of pt.fX; and fY to absolute value of pt.fY. + + @param pt members providing magnitude for fX and fY + */ + void setAbs(const SkPoint& pt) { + fX = SkScalarAbs(pt.fX); + fY = SkScalarAbs(pt.fY); + } + + /** Adds offset to each SkPoint in points array with count entries. + + @param points SkPoint array + @param count entries in array + @param offset vector added to points + */ + static void Offset(SkPoint points[], int count, const SkVector& offset) { + Offset(points, count, offset.fX, offset.fY); + } + + /** Adds offset (dx, dy) to each SkPoint in points array of length count. + + @param points SkPoint array + @param count entries in array + @param dx added to fX in points + @param dy added to fY in points + */ + static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) { + for (int i = 0; i < count; ++i) { + points[i].offset(dx, dy); + } + } + + /** Adds offset (dx, dy) to SkPoint. + + @param dx added to fX + @param dy added to fY + */ + void offset(SkScalar dx, SkScalar dy) { + fX += dx; + fY += dy; + } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(fX * fX + fY * fY) + + . + + @return straight-line distance to origin + */ + SkScalar length() const { return SkPoint::Length(fX, fY); } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(fX * fX + fY * fY) + + . + + @return straight-line distance to origin + */ + SkScalar distanceToOrigin() const { return this->length(); } + + /** Scales (fX, fY) so that length() returns one, while preserving ratio of fX to fY, + if possible. If prior length is nearly zero, sets vector to (0, 0) and returns + false; otherwise returns true. + + @return true if former length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_normalize_2 + */ + bool normalize(); + + /** Sets vector to (x, y) scaled so length() returns one, and so that + (fX, fY) is proportional to (x, y). If (x, y) length is nearly zero, + sets vector to (0, 0) and returns false; otherwise returns true. + + @param x proportional value for fX + @param y proportional value for fY + @return true if (x, y) length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_setNormalize + */ + bool setNormalize(SkScalar x, SkScalar y); + + /** Scales vector so that distanceToOrigin() returns length, if possible. If former + length is nearly zero, sets vector to (0, 0) and return false; otherwise returns + true. + + @param length straight-line distance to origin + @return true if former length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_setLength + */ + bool setLength(SkScalar length); + + /** Sets vector to (x, y) scaled to length, if possible. If former + length is nearly zero, sets vector to (0, 0) and return false; otherwise returns + true. + + @param x proportional value for fX + @param y proportional value for fY + @param length straight-line distance to origin + @return true if (x, y) length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_setLength_2 + */ + bool setLength(SkScalar x, SkScalar y, SkScalar length); + + /** Sets dst to SkPoint times scale. dst may be SkPoint to modify SkPoint in place. + + @param scale factor to multiply SkPoint by + @param dst storage for scaled SkPoint + + example: https://fiddle.skia.org/c/@Point_scale + */ + void scale(SkScalar scale, SkPoint* dst) const; + + /** Scales SkPoint in place by scale. + + @param value factor to multiply SkPoint by + */ + void scale(SkScalar value) { this->scale(value, this); } + + /** Changes the sign of fX and fY. + */ + void negate() { + fX = -fX; + fY = -fY; + } + + /** Returns SkPoint changing the signs of fX and fY. + + @return SkPoint as (-fX, -fY) + */ + SkPoint operator-() const { + return {-fX, -fY}; + } + + /** Adds vector v to SkPoint. Sets SkPoint to: (fX + v.fX, fY + v.fY). + + @param v vector to add + */ + void operator+=(const SkVector& v) { + fX += v.fX; + fY += v.fY; + } + + /** Subtracts vector v from SkPoint. Sets SkPoint to: (fX - v.fX, fY - v.fY). + + @param v vector to subtract + */ + void operator-=(const SkVector& v) { + fX -= v.fX; + fY -= v.fY; + } + + /** Returns SkPoint multiplied by scale. + + @param scale scalar to multiply by + @return SkPoint as (fX * scale, fY * scale) + */ + SkPoint operator*(SkScalar scale) const { + return {fX * scale, fY * scale}; + } + + /** Multiplies SkPoint by scale. Sets SkPoint to: (fX * scale, fY * scale). + + @param scale scalar to multiply by + @return reference to SkPoint + */ + SkPoint& operator*=(SkScalar scale) { + fX *= scale; + fY *= scale; + return *this; + } + + /** Returns true if both fX and fY are measurable values. + + @return true for values other than infinities and NaN + */ + bool isFinite() const { + SkScalar accum = 0; + accum *= fX; + accum *= fY; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + + /** Returns true if SkPoint is equivalent to SkPoint constructed from (x, y). + + @param x value compared with fX + @param y value compared with fY + @return true if SkPoint equals (x, y) + */ + bool equals(SkScalar x, SkScalar y) const { + return fX == x && fY == y; + } + + /** Returns true if a is equivalent to b. + + @param a SkPoint to compare + @param b SkPoint to compare + @return true if a.fX == b.fX and a.fY == b.fY + */ + friend bool operator==(const SkPoint& a, const SkPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + /** Returns true if a is not equivalent to b. + + @param a SkPoint to compare + @param b SkPoint to compare + @return true if a.fX != b.fX or a.fY != b.fY + */ + friend bool operator!=(const SkPoint& a, const SkPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns vector from b to a, computed as (a.fX - b.fX, a.fY - b.fY). + + Can also be used to subtract vector from SkPoint, returning SkPoint. + Can also be used to subtract vector from vector, returning vector. + + @param a SkPoint to subtract from + @param b SkPoint to subtract + @return vector from b to a + */ + friend SkVector operator-(const SkPoint& a, const SkPoint& b) { + return {a.fX - b.fX, a.fY - b.fY}; + } + + /** Returns SkPoint resulting from SkPoint a offset by vector b, computed as: + (a.fX + b.fX, a.fY + b.fY). + + Can also be used to offset SkPoint b by vector a, returning SkPoint. + Can also be used to add vector to vector, returning vector. + + @param a SkPoint or vector to add to + @param b SkPoint or vector to add + @return SkPoint equal to a offset by b + */ + friend SkPoint operator+(const SkPoint& a, const SkVector& b) { + return {a.fX + b.fX, a.fY + b.fY}; + } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(x * x + y * y) + + . + + @param x component of length + @param y component of length + @return straight-line distance to origin + + example: https://fiddle.skia.org/c/@Point_Length + */ + static SkScalar Length(SkScalar x, SkScalar y); + + /** Scales (vec->fX, vec->fY) so that length() returns one, while preserving ratio of vec->fX + to vec->fY, if possible. If original length is nearly zero, sets vec to (0, 0) and returns + zero; otherwise, returns length of vec before vec is scaled. + + Returned prior length may be SK_ScalarInfinity if it can not be represented by SkScalar. + + Note that normalize() is faster if prior length is not required. + + @param vec normalized to unit length + @return original vec length + + example: https://fiddle.skia.org/c/@Point_Normalize + */ + static SkScalar Normalize(SkVector* vec); + + /** Returns the Euclidean distance between a and b. + + @param a line end point + @param b line end point + @return straight-line distance from a to b + */ + static SkScalar Distance(const SkPoint& a, const SkPoint& b) { + return Length(a.fX - b.fX, a.fY - b.fY); + } + + /** Returns the dot product of vector a and vector b. + + @param a left side of dot product + @param b right side of dot product + @return product of input magnitudes and cosine of the angle between them + */ + static SkScalar DotProduct(const SkVector& a, const SkVector& b) { + return a.fX * b.fX + a.fY * b.fY; + } + + /** Returns the cross product of vector a and vector b. + + a and b form three-dimensional vectors with z-axis value equal to zero. The + cross product is a three-dimensional vector with x-axis and y-axis values equal + to zero. The cross product z-axis component is returned. + + @param a left side of cross product + @param b right side of cross product + @return area spanned by vectors signed by angle direction + */ + static SkScalar CrossProduct(const SkVector& a, const SkVector& b) { + return a.fX * b.fY - a.fY * b.fX; + } + + /** Returns the cross product of vector and vec. + + Vector and vec form three-dimensional vectors with z-axis value equal to zero. + The cross product is a three-dimensional vector with x-axis and y-axis values + equal to zero. The cross product z-axis component is returned. + + @param vec right side of cross product + @return area spanned by vectors signed by angle direction + */ + SkScalar cross(const SkVector& vec) const { + return CrossProduct(*this, vec); + } + + /** Returns the dot product of vector and vector vec. + + @param vec right side of dot product + @return product of input magnitudes and cosine of the angle between them + */ + SkScalar dot(const SkVector& vec) const { + return DotProduct(*this, vec); + } + +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPoint3.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPoint3.h new file mode 100644 index 00000000000000..e372f82791c678 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPoint3.h @@ -0,0 +1,157 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPoint3_DEFINED +#define SkPoint3_DEFINED + +#include "include/core/SkPoint.h" + +struct SK_API SkPoint3 { + SkScalar fX, fY, fZ; + + static SkPoint3 Make(SkScalar x, SkScalar y, SkScalar z) { + SkPoint3 pt; + pt.set(x, y, z); + return pt; + } + + SkScalar x() const { return fX; } + SkScalar y() const { return fY; } + SkScalar z() const { return fZ; } + + void set(SkScalar x, SkScalar y, SkScalar z) { fX = x; fY = y; fZ = z; } + + friend bool operator==(const SkPoint3& a, const SkPoint3& b) { + return a.fX == b.fX && a.fY == b.fY && a.fZ == b.fZ; + } + + friend bool operator!=(const SkPoint3& a, const SkPoint3& b) { + return !(a == b); + } + + /** Returns the Euclidian distance from (0,0,0) to (x,y,z) + */ + static SkScalar Length(SkScalar x, SkScalar y, SkScalar z); + + /** Return the Euclidian distance from (0,0,0) to the point + */ + SkScalar length() const { return SkPoint3::Length(fX, fY, fZ); } + + /** Set the point (vector) to be unit-length in the same direction as it + already points. If the point has a degenerate length (i.e., nearly 0) + then set it to (0,0,0) and return false; otherwise return true. + */ + bool normalize(); + + /** Return a new point whose X, Y and Z coordinates are scaled. + */ + SkPoint3 makeScale(SkScalar scale) const { + SkPoint3 p; + p.set(scale * fX, scale * fY, scale * fZ); + return p; + } + + /** Scale the point's coordinates by scale. + */ + void scale(SkScalar value) { + fX *= value; + fY *= value; + fZ *= value; + } + + /** Return a new point whose X, Y and Z coordinates are the negative of the + original point's + */ + SkPoint3 operator-() const { + SkPoint3 neg; + neg.fX = -fX; + neg.fY = -fY; + neg.fZ = -fZ; + return neg; + } + + /** Returns a new point whose coordinates are the difference between + a and b (i.e., a - b) + */ + friend SkPoint3 operator-(const SkPoint3& a, const SkPoint3& b) { + return { a.fX - b.fX, a.fY - b.fY, a.fZ - b.fZ }; + } + + /** Returns a new point whose coordinates are the sum of a and b (a + b) + */ + friend SkPoint3 operator+(const SkPoint3& a, const SkPoint3& b) { + return { a.fX + b.fX, a.fY + b.fY, a.fZ + b.fZ }; + } + + /** Add v's coordinates to the point's + */ + void operator+=(const SkPoint3& v) { + fX += v.fX; + fY += v.fY; + fZ += v.fZ; + } + + /** Subtract v's coordinates from the point's + */ + void operator-=(const SkPoint3& v) { + fX -= v.fX; + fY -= v.fY; + fZ -= v.fZ; + } + + friend SkPoint3 operator*(SkScalar t, SkPoint3 p) { + return { t * p.fX, t * p.fY, t * p.fZ }; + } + + /** Returns true if fX, fY, and fZ are measurable values. + + @return true for values other than infinities and NaN + */ + bool isFinite() const { + SkScalar accum = 0; + accum *= fX; + accum *= fY; + accum *= fZ; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + + /** Returns the dot product of a and b, treating them as 3D vectors + */ + static SkScalar DotProduct(const SkPoint3& a, const SkPoint3& b) { + return a.fX * b.fX + a.fY * b.fY + a.fZ * b.fZ; + } + + SkScalar dot(const SkPoint3& vec) const { + return DotProduct(*this, vec); + } + + /** Returns the cross product of a and b, treating them as 3D vectors + */ + static SkPoint3 CrossProduct(const SkPoint3& a, const SkPoint3& b) { + SkPoint3 result; + result.fX = a.fY*b.fZ - a.fZ*b.fY; + result.fY = a.fZ*b.fX - a.fX*b.fZ; + result.fZ = a.fX*b.fY - a.fY*b.fX; + + return result; + } + + SkPoint3 cross(const SkPoint3& vec) const { + return CrossProduct(*this, vec); + } +}; + +typedef SkPoint3 SkVector3; +typedef SkPoint3 SkColor3f; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPromiseImageTexture.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPromiseImageTexture.h new file mode 100644 index 00000000000000..0bd4034fdcda6a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkPromiseImageTexture.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPromiseImageTexture_DEFINED +#define SkPromiseImageTexture_DEFINED + +#include "include/core/SkTypes.h" + +#if defined(SK_GANESH) +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrBackendSurface.h" +/** + * This type is used to fulfill textures for PromiseImages. Once an instance is returned from a + * PromiseImageTextureFulfillProc the GrBackendTexture it wraps must remain valid until the + * corresponding PromiseImageTextureReleaseProc is called. + */ +class SK_API SkPromiseImageTexture : public SkNVRefCnt { +public: + SkPromiseImageTexture() = delete; + SkPromiseImageTexture(const SkPromiseImageTexture&) = delete; + SkPromiseImageTexture(SkPromiseImageTexture&&) = delete; + ~SkPromiseImageTexture(); + SkPromiseImageTexture& operator=(const SkPromiseImageTexture&) = delete; + SkPromiseImageTexture& operator=(SkPromiseImageTexture&&) = delete; + + static sk_sp Make(const GrBackendTexture& backendTexture) { + if (!backendTexture.isValid()) { + return nullptr; + } + return sk_sp(new SkPromiseImageTexture(backendTexture)); + } + + GrBackendTexture backendTexture() const { return fBackendTexture; } + +private: + explicit SkPromiseImageTexture(const GrBackendTexture& backendTexture); + + GrBackendTexture fBackendTexture; +}; +#endif // defined(SK_GANESH) + +#endif // SkPromiseImageTexture_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRRect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRRect.h new file mode 100644 index 00000000000000..73bc4a95b99ecb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRRect.h @@ -0,0 +1,516 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRRect_DEFINED +#define SkRRect_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkMatrix; +class SkString; + +/** \class SkRRect + SkRRect describes a rounded rectangle with a bounds and a pair of radii for each corner. + The bounds and radii can be set so that SkRRect describes: a rectangle with sharp corners; + a circle; an oval; or a rectangle with one or more rounded corners. + + SkRRect allows implementing CSS properties that describe rounded corners. + SkRRect may have up to eight different radii, one for each axis on each of its four + corners. + + SkRRect may modify the provided parameters when initializing bounds and radii. + If either axis radii is zero or less: radii are stored as zero; corner is square. + If corner curves overlap, radii are proportionally reduced to fit within bounds. +*/ +class SK_API SkRRect { +public: + + /** Initializes bounds at (0, 0), the origin, with zero width and height. + Initializes corner radii to (0, 0), and sets type of kEmpty_Type. + + @return empty SkRRect + */ + SkRRect() = default; + + /** Initializes to copy of rrect bounds and corner radii. + + @param rrect bounds and corner to copy + @return copy of rrect + */ + SkRRect(const SkRRect& rrect) = default; + + /** Copies rrect bounds and corner radii. + + @param rrect bounds and corner to copy + @return copy of rrect + */ + SkRRect& operator=(const SkRRect& rrect) = default; + + /** \enum SkRRect::Type + Type describes possible specializations of SkRRect. Each Type is + exclusive; a SkRRect may only have one type. + + Type members become progressively less restrictive; larger values of + Type have more degrees of freedom than smaller values. + */ + enum Type { + kEmpty_Type, //!< zero width or height + kRect_Type, //!< non-zero width and height, and zeroed radii + kOval_Type, //!< non-zero width and height filled with radii + kSimple_Type, //!< non-zero width and height with equal radii + kNinePatch_Type, //!< non-zero width and height with axis-aligned radii + kComplex_Type, //!< non-zero width and height with arbitrary radii + kLastType = kComplex_Type, //!< largest Type value + }; + + Type getType() const { + SkASSERT(this->isValid()); + return static_cast(fType); + } + + Type type() const { return this->getType(); } + + inline bool isEmpty() const { return kEmpty_Type == this->getType(); } + inline bool isRect() const { return kRect_Type == this->getType(); } + inline bool isOval() const { return kOval_Type == this->getType(); } + inline bool isSimple() const { return kSimple_Type == this->getType(); } + inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); } + inline bool isComplex() const { return kComplex_Type == this->getType(); } + + /** Returns span on the x-axis. This does not check if result fits in 32-bit float; + result may be infinity. + + @return rect().fRight minus rect().fLeft + */ + SkScalar width() const { return fRect.width(); } + + /** Returns span on the y-axis. This does not check if result fits in 32-bit float; + result may be infinity. + + @return rect().fBottom minus rect().fTop + */ + SkScalar height() const { return fRect.height(); } + + /** Returns top-left corner radii. If type() returns kEmpty_Type, kRect_Type, + kOval_Type, or kSimple_Type, returns a value representative of all corner radii. + If type() returns kNinePatch_Type or kComplex_Type, at least one of the + remaining three corners has a different value. + + @return corner radii for simple types + */ + SkVector getSimpleRadii() const { + return fRadii[0]; + } + + /** Sets bounds to zero width and height at (0, 0), the origin. Sets + corner radii to zero and sets type to kEmpty_Type. + */ + void setEmpty() { *this = SkRRect(); } + + /** Sets bounds to sorted rect, and sets corner radii to zero. + If set bounds has width and height, and sets type to kRect_Type; + otherwise, sets type to kEmpty_Type. + + @param rect bounds to set + */ + void setRect(const SkRect& rect) { + if (!this->initializeRect(rect)) { + return; + } + + memset(fRadii, 0, sizeof(fRadii)); + fType = kRect_Type; + + SkASSERT(this->isValid()); + } + + /** Initializes bounds at (0, 0), the origin, with zero width and height. + Initializes corner radii to (0, 0), and sets type of kEmpty_Type. + + @return empty SkRRect + */ + static SkRRect MakeEmpty() { return SkRRect(); } + + /** Initializes to copy of r bounds and zeroes corner radii. + + @param r bounds to copy + @return copy of r + */ + static SkRRect MakeRect(const SkRect& r) { + SkRRect rr; + rr.setRect(r); + return rr; + } + + /** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii + to half oval.height(). If oval bounds is empty, sets to kEmpty_Type. + Otherwise, sets to kOval_Type. + + @param oval bounds of oval + @return oval + */ + static SkRRect MakeOval(const SkRect& oval) { + SkRRect rr; + rr.setOval(oval); + return rr; + } + + /** Sets to rounded rectangle with the same radii for all four corners. + If rect is empty, sets to kEmpty_Type. + Otherwise, if xRad and yRad are zero, sets to kRect_Type. + Otherwise, if xRad is at least half rect.width() and yRad is at least half + rect.height(), sets to kOval_Type. + Otherwise, sets to kSimple_Type. + + @param rect bounds of rounded rectangle + @param xRad x-axis radius of corners + @param yRad y-axis radius of corners + @return rounded rectangle + */ + static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { + SkRRect rr; + rr.setRectXY(rect, xRad, yRad); + return rr; + } + + /** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii + to half oval.height(). If oval bounds is empty, sets to kEmpty_Type. + Otherwise, sets to kOval_Type. + + @param oval bounds of oval + */ + void setOval(const SkRect& oval); + + /** Sets to rounded rectangle with the same radii for all four corners. + If rect is empty, sets to kEmpty_Type. + Otherwise, if xRad or yRad is zero, sets to kRect_Type. + Otherwise, if xRad is at least half rect.width() and yRad is at least half + rect.height(), sets to kOval_Type. + Otherwise, sets to kSimple_Type. + + @param rect bounds of rounded rectangle + @param xRad x-axis radius of corners + @param yRad y-axis radius of corners + + example: https://fiddle.skia.org/c/@RRect_setRectXY + */ + void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad); + + /** Sets bounds to rect. Sets radii to (leftRad, topRad), (rightRad, topRad), + (rightRad, bottomRad), (leftRad, bottomRad). + + If rect is empty, sets to kEmpty_Type. + Otherwise, if leftRad and rightRad are zero, sets to kRect_Type. + Otherwise, if topRad and bottomRad are zero, sets to kRect_Type. + Otherwise, if leftRad and rightRad are equal and at least half rect.width(), and + topRad and bottomRad are equal at least half rect.height(), sets to kOval_Type. + Otherwise, if leftRad and rightRad are equal, and topRad and bottomRad are equal, + sets to kSimple_Type. Otherwise, sets to kNinePatch_Type. + + Nine patch refers to the nine parts defined by the radii: one center rectangle, + four edge patches, and four corner patches. + + @param rect bounds of rounded rectangle + @param leftRad left-top and left-bottom x-axis radius + @param topRad left-top and right-top y-axis radius + @param rightRad right-top and right-bottom x-axis radius + @param bottomRad left-bottom and right-bottom y-axis radius + */ + void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad, + SkScalar rightRad, SkScalar bottomRad); + + /** Sets bounds to rect. Sets radii array for individual control of all for corners. + + If rect is empty, sets to kEmpty_Type. + Otherwise, if one of each corner radii are zero, sets to kRect_Type. + Otherwise, if all x-axis radii are equal and at least half rect.width(), and + all y-axis radii are equal at least half rect.height(), sets to kOval_Type. + Otherwise, if all x-axis radii are equal, and all y-axis radii are equal, + sets to kSimple_Type. Otherwise, sets to kNinePatch_Type. + + @param rect bounds of rounded rectangle + @param radii corner x-axis and y-axis radii + + example: https://fiddle.skia.org/c/@RRect_setRectRadii + */ + void setRectRadii(const SkRect& rect, const SkVector radii[4]); + + /** \enum SkRRect::Corner + The radii are stored: top-left, top-right, bottom-right, bottom-left. + */ + enum Corner { + kUpperLeft_Corner, //!< index of top-left corner radii + kUpperRight_Corner, //!< index of top-right corner radii + kLowerRight_Corner, //!< index of bottom-right corner radii + kLowerLeft_Corner, //!< index of bottom-left corner radii + }; + + /** Returns bounds. Bounds may have zero width or zero height. Bounds right is + greater than or equal to left; bounds bottom is greater than or equal to top. + Result is identical to getBounds(). + + @return bounding box + */ + const SkRect& rect() const { return fRect; } + + /** Returns scalar pair for radius of curve on x-axis and y-axis for one corner. + Both radii may be zero. If not zero, both are positive and finite. + + @return x-axis and y-axis radii for one corner + */ + SkVector radii(Corner corner) const { return fRadii[corner]; } + + /** Returns bounds. Bounds may have zero width or zero height. Bounds right is + greater than or equal to left; bounds bottom is greater than or equal to top. + Result is identical to rect(). + + @return bounding box + */ + const SkRect& getBounds() const { return fRect; } + + /** Returns true if bounds and radii in a are equal to bounds and radii in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect bounds and radii to compare + @param b SkRect bounds and radii to compare + @return true if members are equal + */ + friend bool operator==(const SkRRect& a, const SkRRect& b) { + return a.fRect == b.fRect && SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8); + } + + /** Returns true if bounds and radii in a are not equal to bounds and radii in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect bounds and radii to compare + @param b SkRect bounds and radii to compare + @return true if members are not equal + */ + friend bool operator!=(const SkRRect& a, const SkRRect& b) { + return a.fRect != b.fRect || !SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8); + } + + /** Copies SkRRect to dst, then insets dst bounds by dx and dy, and adjusts dst + radii by dx and dy. dx and dy may be positive, negative, or zero. dst may be + SkRRect. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half dst bounds width, dst bounds left and right are set to + bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, dst bounds is zeroed. + + @param dx added to rect().fLeft, and subtracted from rect().fRight + @param dy added to rect().fTop, and subtracted from rect().fBottom + @param dst insets bounds and radii + + example: https://fiddle.skia.org/c/@RRect_inset + */ + void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const; + + /** Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half bounds width, bounds left and right are set to + bounds x-axis center. If dy exceeds half bounds height, bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, bounds is zeroed. + + @param dx added to rect().fLeft, and subtracted from rect().fRight + @param dy added to rect().fTop, and subtracted from rect().fBottom + */ + void inset(SkScalar dx, SkScalar dy) { + this->inset(dx, dy, this); + } + + /** Outsets dst bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half dst bounds width, dst bounds left and right are set to + bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, dst bounds is zeroed. + + @param dx subtracted from rect().fLeft, and added to rect().fRight + @param dy subtracted from rect().fTop, and added to rect().fBottom + @param dst outset bounds and radii + */ + void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const { + this->inset(-dx, -dy, dst); + } + + /** Outsets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half bounds width, bounds left and right are set to + bounds x-axis center. If dy exceeds half bounds height, bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, bounds is zeroed. + + @param dx subtracted from rect().fLeft, and added to rect().fRight + @param dy subtracted from rect().fTop, and added to rect().fBottom + */ + void outset(SkScalar dx, SkScalar dy) { + this->inset(-dx, -dy, this); + } + + /** Translates SkRRect by (dx, dy). + + @param dx offset added to rect().fLeft and rect().fRight + @param dy offset added to rect().fTop and rect().fBottom + */ + void offset(SkScalar dx, SkScalar dy) { + fRect.offset(dx, dy); + } + + /** Returns SkRRect translated by (dx, dy). + + @param dx offset added to rect().fLeft and rect().fRight + @param dy offset added to rect().fTop and rect().fBottom + @return SkRRect bounds offset by (dx, dy), with unchanged corner radii + */ + SkRRect SK_WARN_UNUSED_RESULT makeOffset(SkScalar dx, SkScalar dy) const { + return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType); + } + + /** Returns true if rect is inside the bounds and corner radii, and if + SkRRect and rect are not empty. + + @param rect area tested for containment + @return true if SkRRect contains rect + + example: https://fiddle.skia.org/c/@RRect_contains + */ + bool contains(const SkRect& rect) const; + + /** Returns true if bounds and radii values are finite and describe a SkRRect + SkRRect::Type that matches getType(). All SkRRect methods construct valid types, + even if the input values are not valid. Invalid SkRRect data can only + be generated by corrupting memory. + + @return true if bounds and radii match type() + + example: https://fiddle.skia.org/c/@RRect_isValid + */ + bool isValid() const; + + static constexpr size_t kSizeInMemory = 12 * sizeof(SkScalar); + + /** Writes SkRRect to buffer. Writes kSizeInMemory bytes, and returns + kSizeInMemory, the number of bytes written. + + @param buffer storage for SkRRect + @return bytes written, kSizeInMemory + + example: https://fiddle.skia.org/c/@RRect_writeToMemory + */ + size_t writeToMemory(void* buffer) const; + + /** Reads SkRRect from buffer, reading kSizeInMemory bytes. + Returns kSizeInMemory, bytes read if length is at least kSizeInMemory. + Otherwise, returns zero. + + @param buffer memory to read from + @param length size of buffer + @return bytes read, or 0 if length is less than kSizeInMemory + + example: https://fiddle.skia.org/c/@RRect_readFromMemory + */ + size_t readFromMemory(const void* buffer, size_t length); + + /** Transforms by SkRRect by matrix, storing result in dst. + Returns true if SkRRect transformed can be represented by another SkRRect. + Returns false if matrix contains transformations that are not axis aligned. + + Asserts in debug builds if SkRRect equals dst. + + @param matrix SkMatrix specifying the transform + @param dst SkRRect to store the result + @return true if transformation succeeded. + + example: https://fiddle.skia.org/c/@RRect_transform + */ + bool transform(const SkMatrix& matrix, SkRRect* dst) const; + + /** Writes text representation of SkRRect to standard output. + Set asHex true to generate exact binary representations + of floating point numbers. + + @param asHex true if SkScalar values are written as hexadecimal + + example: https://fiddle.skia.org/c/@RRect_dump + */ + void dump(bool asHex) const; + SkString dumpToString(bool asHex) const; + + /** Writes text representation of SkRRect to standard output. The representation + may be directly compiled as C++ code. Floating point values are written + with limited precision; it may not be possible to reconstruct original + SkRRect from output. + */ + void dump() const { this->dump(false); } + + /** Writes text representation of SkRRect to standard output. The representation + may be directly compiled as C++ code. Floating point values are written + in hexadecimal to preserve their exact bit pattern. The output reconstructs the + original SkRRect. + */ + void dumpHex() const { this->dump(true); } + +private: + static bool AreRectAndRadiiValid(const SkRect&, const SkVector[4]); + + SkRRect(const SkRect& rect, const SkVector radii[4], int32_t type) + : fRect(rect) + , fRadii{radii[0], radii[1], radii[2], radii[3]} + , fType(type) {} + + /** + * Initializes fRect. If the passed in rect is not finite or empty the rrect will be fully + * initialized and false is returned. Otherwise, just fRect is initialized and true is returned. + */ + bool initializeRect(const SkRect&); + + void computeType(); + bool checkCornerContainment(SkScalar x, SkScalar y) const; + // Returns true if the radii had to be scaled to fit rect + bool scaleRadii(); + + SkRect fRect = SkRect::MakeEmpty(); + // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[] + SkVector fRadii[4] = {{0, 0}, {0, 0}, {0,0}, {0,0}}; + // use an explicitly sized type so we're sure the class is dense (no uninitialized bytes) + int32_t fType = kEmpty_Type; + // TODO: add padding so we can use memcpy for flattening and not copy uninitialized data + + // to access fRadii directly + friend class SkPath; + friend class SkRRectPriv; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRSXform.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRSXform.h new file mode 100644 index 00000000000000..5fcfff29221afd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRSXform.h @@ -0,0 +1,69 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRSXform_DEFINED +#define SkRSXform_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkSize.h" + +/** + * A compressed form of a rotation+scale matrix. + * + * [ fSCos -fSSin fTx ] + * [ fSSin fSCos fTy ] + * [ 0 0 1 ] + */ +struct SK_API SkRSXform { + static SkRSXform Make(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) { + SkRSXform xform = { scos, ssin, tx, ty }; + return xform; + } + + /* + * Initialize a new xform based on the scale, rotation (in radians), final tx,ty location + * and anchor-point ax,ay within the src quad. + * + * Note: the anchor point is not normalized (e.g. 0...1) but is in pixels of the src image. + */ + static SkRSXform MakeFromRadians(SkScalar scale, SkScalar radians, SkScalar tx, SkScalar ty, + SkScalar ax, SkScalar ay) { + const SkScalar s = SkScalarSin(radians) * scale; + const SkScalar c = SkScalarCos(radians) * scale; + return Make(c, s, tx + -c * ax + s * ay, ty + -s * ax - c * ay); + } + + SkScalar fSCos; + SkScalar fSSin; + SkScalar fTx; + SkScalar fTy; + + bool rectStaysRect() const { + return 0 == fSCos || 0 == fSSin; + } + + void setIdentity() { + fSCos = 1; + fSSin = fTx = fTy = 0; + } + + void set(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) { + fSCos = scos; + fSSin = ssin; + fTx = tx; + fTy = ty; + } + + void toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const; + void toQuad(const SkSize& size, SkPoint quad[4]) const { + this->toQuad(size.width(), size.height(), quad); + } + void toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const; +}; + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRasterHandleAllocator.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRasterHandleAllocator.h new file mode 100644 index 00000000000000..6fe121a6dedecc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRasterHandleAllocator.h @@ -0,0 +1,94 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRasterHandleAllocator_DEFINED +#define SkRasterHandleAllocator_DEFINED + +#include "include/core/SkImageInfo.h" + +class SkBitmap; +class SkCanvas; +class SkMatrix; +class SkSurfaceProps; + +/** + * If a client wants to control the allocation of raster layers in a canvas, it should subclass + * SkRasterHandleAllocator. This allocator performs two tasks: + * 1. controls how the memory for the pixels is allocated + * 2. associates a "handle" to a private object that can track the matrix/clip of the SkCanvas + * + * This example allocates a canvas, and defers to the allocator to create the base layer. + * + * std::unique_ptr canvas = SkRasterHandleAllocator::MakeCanvas( + * SkImageInfo::Make(...), + * std::make_unique(...), + * nullptr); + * + * If you have already allocated the base layer (and its handle, release-proc etc.) then you + * can pass those in using the last parameter to MakeCanvas(). + * + * Regardless of how the base layer is allocated, each time canvas->saveLayer() is called, + * your allocator's allocHandle() will be called. + */ +class SK_API SkRasterHandleAllocator { +public: + virtual ~SkRasterHandleAllocator() = default; + + // The value that is returned to clients of the canvas that has this allocator installed. + typedef void* Handle; + + struct Rec { + // When the allocation goes out of scope, this proc is called to free everything associated + // with it: the pixels, the "handle", etc. This is passed the pixel address and fReleaseCtx. + void (*fReleaseProc)(void* pixels, void* ctx); + void* fReleaseCtx; // context passed to fReleaseProc + void* fPixels; // pixels for this allocation + size_t fRowBytes; // rowbytes for these pixels + Handle fHandle; // public handle returned by SkCanvas::accessTopRasterHandle() + }; + + /** + * Given a requested info, allocate the corresponding pixels/rowbytes, and whatever handle + * is desired to give clients access to those pixels. The rec also contains a proc and context + * which will be called when this allocation goes out of scope. + * + * e.g. + * when canvas->saveLayer() is called, the allocator will be called to allocate the pixels + * for the layer. When canvas->restore() is called, the fReleaseProc will be called. + */ + virtual bool allocHandle(const SkImageInfo&, Rec*) = 0; + + /** + * Clients access the handle for a given layer by calling SkCanvas::accessTopRasterHandle(). + * To allow the handle to reflect the current matrix/clip in the canvs, updateHandle() is + * is called. The subclass is responsible to update the handle as it sees fit. + */ + virtual void updateHandle(Handle, const SkMatrix&, const SkIRect&) = 0; + + /** + * This creates a canvas which will use the allocator to manage pixel allocations, including + * all calls to saveLayer(). + * + * If rec is non-null, then it will be used as the base-layer of pixels/handle. + * If rec is null, then the allocator will be called for the base-layer as well. + */ + static std::unique_ptr MakeCanvas(std::unique_ptr, + const SkImageInfo&, const Rec* rec = nullptr, + const SkSurfaceProps* props = nullptr); + +protected: + SkRasterHandleAllocator() = default; + SkRasterHandleAllocator(const SkRasterHandleAllocator&) = delete; + SkRasterHandleAllocator& operator=(const SkRasterHandleAllocator&) = delete; + +private: + friend class SkBitmapDevice; + + Handle allocBitmap(const SkImageInfo&, SkBitmap*); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRect.h new file mode 100644 index 00000000000000..1ed7823c237739 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRect.h @@ -0,0 +1,1388 @@ +/* + * 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 SkRect_DEFINED +#define SkRect_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkSafe32.h" +#include "include/private/base/SkTFitsIn.h" + +#include +#include +#include + +struct SkRect; + +/** \struct SkIRect + SkIRect holds four 32-bit integer coordinates describing the upper and + lower bounds of a rectangle. SkIRect may be created from outer bounds or + from position, width, and height. SkIRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. +*/ +struct SK_API SkIRect { + int32_t fLeft; //!< smaller x-axis bounds + int32_t fTop; //!< smaller y-axis bounds + int32_t fRight; //!< larger x-axis bounds + int32_t fBottom; //!< larger y-axis bounds + + /** Returns constructed SkIRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() { + return SkIRect{0, 0, 0, 0}; + } + + /** Returns constructed SkIRect set to (0, 0, w, h). Does not validate input; w or h + may be negative. + + @param w width of constructed SkIRect + @param h height of constructed SkIRect + @return bounds (0, 0, w, h) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) { + return SkIRect{0, 0, w, h}; + } + + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size values for SkIRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) { + return SkIRect{0, 0, size.fWidth, size.fHeight}; + } + + /** Returns constructed SkIRect set to (pt.x(), pt.y(), pt.x() + size.width(), + pt.y() + size.height()). Does not validate input; size.width() or size.height() may be + negative. + + @param pt values for SkIRect fLeft and fTop + @param size values for SkIRect width and height + @return bounds at pt with width and height of size + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakePtSize(SkIPoint pt, SkISize size) { + return MakeXYWH(pt.x(), pt.y(), size.width(), size.height()); + } + + /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkIRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l integer stored in fLeft + @param t integer stored in fTop + @param r integer stored in fRight + @param b integer stored in fBottom + @return bounds (l, t, r, b) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, + int32_t r, int32_t b) { + return SkIRect{l, t, r, b}; + } + + /** Returns constructed SkIRect set to: (x, y, x + w, y + h). + Does not validate input; w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, + int32_t w, int32_t h) { + return { x, y, Sk32_sat_add(x, w), Sk32_sat_add(y, h) }; + } + + /** Returns left edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr int32_t left() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr int32_t top() const { return fTop; } + + /** Returns right edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ + constexpr int32_t right() const { return fRight; } + + /** Returns bottom edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ + constexpr int32_t bottom() const { return fBottom; } + + /** Returns left edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr int32_t x() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr int32_t y() const { return fTop; } + + // Experimental + constexpr SkIPoint topLeft() const { return {fLeft, fTop}; } + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fRight minus fLeft + */ + constexpr int32_t width() const { return Sk32_can_overflow_sub(fRight, fLeft); } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fBottom minus fTop + */ + constexpr int32_t height() const { return Sk32_can_overflow_sub(fBottom, fTop); } + + /** Returns spans on the x-axis and y-axis. This does not check if SkIRect is sorted, + or if result fits in 32-bit signed integer; result may be negative. + + @return SkISize (width, height) + */ + constexpr SkISize size() const { return SkISize::Make(this->width(), this->height()); } + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, so the + result may be negative. This is safer than calling width() since width() might + overflow in its calculation. + + @return fRight minus fLeft cast to int64_t + */ + constexpr int64_t width64() const { return (int64_t)fRight - (int64_t)fLeft; } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, so the + result may be negative. This is safer than calling height() since height() might + overflow in its calculation. + + @return fBottom minus fTop cast to int64_t + */ + constexpr int64_t height64() const { return (int64_t)fBottom - (int64_t)fTop; } + + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width64() or height64(). + + @return true if width64() or height64() are zero or negative + */ + bool isEmpty64() const { return fRight <= fLeft || fBottom <= fTop; } + + /** Returns true if width() or height() are zero or negative. + + @return true if width() or height() are zero or negative + */ + bool isEmpty() const { + int64_t w = this->width64(); + int64_t h = this->height64(); + if (w <= 0 || h <= 0) { + return true; + } + // Return true if either exceeds int32_t + return !SkTFitsIn(w | h); + } + + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + identical to corresponding members in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are equal + */ + friend bool operator==(const SkIRect& a, const SkIRect& b) { + return a.fLeft == b.fLeft && a.fTop == b.fTop && + a.fRight == b.fRight && a.fBottom == b.fBottom; + } + + /** Returns true if any member in a: fLeft, fTop, fRight, and fBottom; is not + identical to the corresponding member in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are not equal + */ + friend bool operator!=(const SkIRect& a, const SkIRect& b) { + return a.fLeft != b.fLeft || a.fTop != b.fTop || + a.fRight != b.fRight || a.fBottom != b.fBottom; + } + + /** Sets SkIRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + */ + void setEmpty() { memset(this, 0, sizeof(*this)); } + + /** Sets SkIRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Sets SkIRect to: (x, y, x + width, y + height). + Does not validate input; width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ + void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { + fLeft = x; + fTop = y; + fRight = Sk32_sat_add(x, width); + fBottom = Sk32_sat_add(y, height); + } + + void setWH(int32_t width, int32_t height) { + fLeft = 0; + fTop = 0; + fRight = width; + fBottom = height; + } + + void setSize(SkISize size) { + fLeft = 0; + fTop = 0; + fRight = size.width(); + fBottom = size.height(); + } + + /** Returns SkIRect offset by (dx, dy). + + If dx is negative, SkIRect returned is moved to the left. + If dx is positive, SkIRect returned is moved to the right. + If dy is negative, SkIRect returned is moved upward. + If dy is positive, SkIRect returned is moved downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + @return SkIRect offset by dx and dy, with original width and height + */ + constexpr SkIRect makeOffset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_add(fLeft, dx), Sk32_sat_add(fTop, dy), + Sk32_sat_add(fRight, dx), Sk32_sat_add(fBottom, dy), + }; + } + + /** Returns SkIRect offset by (offset.x(), offset.y()). + + If offset.x() is negative, SkIRect returned is moved to the left. + If offset.x() is positive, SkIRect returned is moved to the right. + If offset.y() is negative, SkIRect returned is moved upward. + If offset.y() is positive, SkIRect returned is moved downward. + + @param offset translation vector + @return SkIRect translated by offset, with original width and height + */ + constexpr SkIRect makeOffset(SkIVector offset) const { + return this->makeOffset(offset.x(), offset.y()); + } + + /** Returns SkIRect, inset by (dx, dy). + + If dx is negative, SkIRect returned is wider. + If dx is positive, SkIRect returned is narrower. + If dy is negative, SkIRect returned is taller. + If dy is positive, SkIRect returned is shorter. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + @return SkIRect inset symmetrically left and right, top and bottom + */ + SkIRect makeInset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_add(fLeft, dx), Sk32_sat_add(fTop, dy), + Sk32_sat_sub(fRight, dx), Sk32_sat_sub(fBottom, dy), + }; + } + + /** Returns SkIRect, outset by (dx, dy). + + If dx is negative, SkIRect returned is narrower. + If dx is positive, SkIRect returned is wider. + If dy is negative, SkIRect returned is shorter. + If dy is positive, SkIRect returned is taller. + + @param dx offset subtracted to fLeft and added from fRight + @param dy offset subtracted to fTop and added from fBottom + @return SkIRect outset symmetrically left and right, top and bottom + */ + SkIRect makeOutset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_sub(fLeft, dx), Sk32_sat_sub(fTop, dy), + Sk32_sat_add(fRight, dx), Sk32_sat_add(fBottom, dy), + }; + } + + /** Offsets SkIRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkIRect returned to the left. + If dx is positive, moves SkIRect returned to the right. + If dy is negative, moves SkIRect returned upward. + If dy is positive, moves SkIRect returned downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + */ + void offset(int32_t dx, int32_t dy) { + fLeft = Sk32_sat_add(fLeft, dx); + fTop = Sk32_sat_add(fTop, dy); + fRight = Sk32_sat_add(fRight, dx); + fBottom = Sk32_sat_add(fBottom, dy); + } + + /** Offsets SkIRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkIRect returned to the left. + If delta.fX is positive, moves SkIRect returned to the right. + If delta.fY is negative, moves SkIRect returned upward. + If delta.fY is positive, moves SkIRect returned downward. + + @param delta offset added to SkIRect + */ + void offset(const SkIPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** Offsets SkIRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ + void offsetTo(int32_t newX, int32_t newY) { + fRight = Sk64_pin_to_s32((int64_t)fRight + newX - fLeft); + fBottom = Sk64_pin_to_s32((int64_t)fBottom + newY - fTop); + fLeft = newX; + fTop = newY; + } + + /** Insets SkIRect by (dx,dy). + + If dx is positive, makes SkIRect narrower. + If dx is negative, makes SkIRect wider. + If dy is positive, makes SkIRect shorter. + If dy is negative, makes SkIRect taller. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + */ + void inset(int32_t dx, int32_t dy) { + fLeft = Sk32_sat_add(fLeft, dx); + fTop = Sk32_sat_add(fTop, dy); + fRight = Sk32_sat_sub(fRight, dx); + fBottom = Sk32_sat_sub(fBottom, dy); + } + + /** Outsets SkIRect by (dx, dy). + + If dx is positive, makes SkIRect wider. + If dx is negative, makes SkIRect narrower. + If dy is positive, makes SkIRect taller. + If dy is negative, makes SkIRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + */ + void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } + + /** Adjusts SkIRect by adding dL to fLeft, dT to fTop, dR to fRight, and dB to fBottom. + + If dL is positive, narrows SkIRect on the left. If negative, widens it on the left. + If dT is positive, shrinks SkIRect on the top. If negative, lengthens it on the top. + If dR is positive, narrows SkIRect on the right. If negative, widens it on the right. + If dB is positive, shrinks SkIRect on the bottom. If negative, lengthens it on the bottom. + + The resulting SkIRect is not checked for validity. Thus, if the resulting SkIRect left is + greater than right, the SkIRect will be considered empty. Call sort() after this call + if that is not the desired behavior. + + @param dL offset added to fLeft + @param dT offset added to fTop + @param dR offset added to fRight + @param dB offset added to fBottom + */ + void adjust(int32_t dL, int32_t dT, int32_t dR, int32_t dB) { + fLeft = Sk32_sat_add(fLeft, dL); + fTop = Sk32_sat_add(fTop, dT); + fRight = Sk32_sat_add(fRight, dR); + fBottom = Sk32_sat_add(fBottom, dB); + } + + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkIRect is empty. + + Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and + returns true if constructed area is completely enclosed by SkIRect area. + + @param x test SkIPoint x-coordinate + @param y test SkIPoint y-coordinate + @return true if (x, y) is inside SkIRect + */ + bool contains(int32_t x, int32_t y) const { + return x >= fLeft && x < fRight && y >= fTop && y < fBottom; + } + + /** Returns true if SkIRect contains r. + Returns false if SkIRect is empty or r is empty. + + SkIRect contains r when SkIRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r + */ + bool contains(const SkIRect& r) const { + return !r.isEmpty() && !this->isEmpty() && // check for empties + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkIRect contains r. + Returns false if SkIRect is empty or r is empty. + + SkIRect contains r when SkIRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkIRect are outside r + */ + inline bool contains(const SkRect& r) const; + + /** Returns true if SkIRect contains construction. + Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. + + Return is undefined if SkIRect is empty or construction is empty. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r + */ + bool containsNoEmptyCheck(const SkIRect& r) const { + SkASSERT(fLeft < fRight && fTop < fBottom); + SkASSERT(r.fLeft < r.fRight && r.fTop < r.fBottom); + return fLeft <= r.fLeft && fTop <= r.fTop && fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkIRect intersects r, and sets SkIRect to intersection. + Returns false if SkIRect does not intersect r, and leaves SkIRect unchanged. + + Returns false if either r or SkIRect is empty, leaving SkIRect unchanged. + + @param r limit of result + @return true if r and SkIRect have area in common + */ + bool intersect(const SkIRect& r) { + return this->intersect(*this, r); + } + + /** Returns true if a intersects b, and sets SkIRect to intersection. + Returns false if a does not intersect b, and leaves SkIRect unchanged. + + Returns false if either a or b is empty, leaving SkIRect unchanged. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& a, const SkIRect& b); + + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + static bool Intersects(const SkIRect& a, const SkIRect& b) { + return SkIRect{}.intersect(a, b); + } + + /** Sets SkIRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkIRect is empty, sets SkIRect to r. + + @param r expansion SkIRect + + example: https://fiddle.skia.org/c/@IRect_join_2 + */ + void join(const SkIRect& r); + + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty, + and width() and height() will be zero or positive. + */ + void sort() { + using std::swap; + if (fLeft > fRight) { + swap(fLeft, fRight); + } + if (fTop > fBottom) { + swap(fTop, fBottom); + } + } + + /** Returns SkIRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkIRect + */ + SkIRect makeSorted() const { + return MakeLTRB(std::min(fLeft, fRight), std::min(fTop, fBottom), + std::max(fLeft, fRight), std::max(fTop, fBottom)); + } +}; + +/** \struct SkRect + SkRect holds four SkScalar coordinates describing the upper and + lower bounds of a rectangle. SkRect may be created from outer bounds or + from position, width, and height. SkRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. +*/ +struct SK_API SkRect { + SkScalar fLeft; //!< smaller x-axis bounds + SkScalar fTop; //!< smaller y-axis bounds + SkScalar fRight; //!< larger x-axis bounds + SkScalar fBottom; //!< larger y-axis bounds + + /** Returns constructed SkRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { + return SkRect{0, 0, 0, 0}; + } + + /** Returns constructed SkRect set to SkScalar values (0, 0, w, h). Does not + validate input; w or h may be negative. + + Passing integer values may generate a compiler warning since SkRect cannot + represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle. + + @param w SkScalar width of constructed SkRect + @param h SkScalar height of constructed SkRect + @return bounds (0, 0, w, h) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) { + return SkRect{0, 0, w, h}; + } + + /** Returns constructed SkRect set to integer values (0, 0, w, h). Does not validate + input; w or h may be negative. + + Use to avoid a compiler warning that input may lose precision when stored. + Use SkIRect for an exact integer rectangle. + + @param w integer width of constructed SkRect + @param h integer height of constructed SkRect + @return bounds (0, 0, w, h) + */ + static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) { + return {0, 0, SkIntToScalar(w), SkIntToScalar(h)}; + } + + /** Returns constructed SkRect set to (0, 0, size.width(), size.height()). Does not + validate input; size.width() or size.height() may be negative. + + @param size SkScalar values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) { + return SkRect{0, 0, size.fWidth, size.fHeight}; + } + + /** Returns constructed SkRect set to (l, t, r, b). Does not sort input; SkRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l SkScalar stored in fLeft + @param t SkScalar stored in fTop + @param r SkScalar stored in fRight + @param b SkScalar stored in fBottom + @return bounds (l, t, r, b) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, + SkScalar b) { + return SkRect {l, t, r, b}; + } + + /** Returns constructed SkRect set to (x, y, x + w, y + h). + Does not validate input; w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, + SkScalar h) { + return SkRect {x, y, x + w, y + h}; + } + + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size integer values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static SkRect Make(const SkISize& size) { + return MakeIWH(size.width(), size.height()); + } + + /** Returns constructed SkIRect set to irect, promoting integers to scalar. + Does not validate input; fLeft may be greater than fRight, fTop may be greater + than fBottom. + + @param irect integer unsorted bounds + @return irect members converted to SkScalar + */ + static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { + return { + SkIntToScalar(irect.fLeft), SkIntToScalar(irect.fTop), + SkIntToScalar(irect.fRight), SkIntToScalar(irect.fBottom) + }; + } + + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or negative + */ + bool isEmpty() const { + // We write it as the NOT of a non-empty rect, so we will return true if any values + // are NaN. + return !(fLeft < fRight && fTop < fBottom); + } + + /** Returns true if fLeft is equal to or less than fRight, or if fTop is equal + to or less than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or positive + */ + bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; } + + /** Returns true if all values in the rectangle are finite: SK_ScalarMin or larger, + and SK_ScalarMax or smaller. + + @return true if no member is infinite or NaN + */ + bool isFinite() const { + float accum = 0; + accum *= fLeft; + accum *= fTop; + accum *= fRight; + accum *= fBottom; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr SkScalar x() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr SkScalar y() const { return fTop; } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr SkScalar left() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr SkScalar top() const { return fTop; } + + /** Returns right edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ + constexpr SkScalar right() const { return fRight; } + + /** Returns bottom edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ + constexpr SkScalar bottom() const { return fBottom; } + + /** Returns span on the x-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fRight minus fLeft + */ + constexpr SkScalar width() const { return fRight - fLeft; } + + /** Returns span on the y-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fBottom minus fTop + */ + constexpr SkScalar height() const { return fBottom - fTop; } + + /** Returns average of left edge and right edge. Result does not change if SkRect + is sorted. Result may overflow to infinity if SkRect is far from the origin. + + @return midpoint on x-axis + */ + constexpr SkScalar centerX() const { + // don't use SkScalarHalf(fLeft + fBottom) as that might overflow before the 0.5 + return SkScalarHalf(fLeft) + SkScalarHalf(fRight); + } + + /** Returns average of top edge and bottom edge. Result does not change if SkRect + is sorted. + + @return midpoint on y-axis + */ + constexpr SkScalar centerY() const { + // don't use SkScalarHalf(fTop + fBottom) as that might overflow before the 0.5 + return SkScalarHalf(fTop) + SkScalarHalf(fBottom); + } + + /** Returns the point this->centerX(), this->centerY(). + @return rectangle center + */ + constexpr SkPoint center() const { return {this->centerX(), this->centerY()}; } + + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + equal to the corresponding members in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect to compare + @param b SkRect to compare + @return true if members are equal + */ + friend bool operator==(const SkRect& a, const SkRect& b) { + return SkScalarsEqual((const SkScalar*)&a, (const SkScalar*)&b, 4); + } + + /** Returns true if any in a: fLeft, fTop, fRight, and fBottom; does not + equal the corresponding members in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect to compare + @param b SkRect to compare + @return true if members are not equal + */ + friend bool operator!=(const SkRect& a, const SkRect& b) { + return !SkScalarsEqual((const SkScalar*)&a, (const SkScalar*)&b, 4); + } + + /** Returns four points in quad that enclose SkRect ordered as: top-left, top-right, + bottom-right, bottom-left. + + TODO: Consider adding parameter to control whether quad is clockwise or counterclockwise. + + @param quad storage for corners of SkRect + + example: https://fiddle.skia.org/c/@Rect_toQuad + */ + void toQuad(SkPoint quad[4]) const; + + /** Sets SkRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + */ + void setEmpty() { *this = MakeEmpty(); } + + /** Sets SkRect to src, promoting src members from integer to scalar. + Very large values in src may lose precision. + + @param src integer SkRect + */ + void set(const SkIRect& src) { + fLeft = SkIntToScalar(src.fLeft); + fTop = SkIntToScalar(src.fTop); + fRight = SkIntToScalar(src.fRight); + fBottom = SkIntToScalar(src.fBottom); + } + + /** Sets SkRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, + or if SkPoint array contains an infinity or NaN, sets to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + */ + void setBounds(const SkPoint pts[], int count) { + (void)this->setBoundsCheck(pts, count); + } + + /** Sets to bounds of SkPoint array with count entries. Returns false if count is + zero or smaller, or if SkPoint array contains an infinity or NaN; in these cases + sets SkRect to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + @return true if all SkPoint values are finite + + example: https://fiddle.skia.org/c/@Rect_setBoundsCheck + */ + bool setBoundsCheck(const SkPoint pts[], int count); + + /** Sets to bounds of SkPoint pts array with count entries. If any SkPoint in pts + contains infinity or NaN, all SkRect dimensions are set to NaN. + + @param pts SkPoint array + @param count entries in array + + example: https://fiddle.skia.org/c/@Rect_setBoundsNoCheck + */ + void setBoundsNoCheck(const SkPoint pts[], int count); + + /** Sets bounds to the smallest SkRect enclosing SkPoint p0 and p1. The result is + sorted and may be empty. Does not check to see if values are finite. + + @param p0 corner to include + @param p1 corner to include + */ + void set(const SkPoint& p0, const SkPoint& p1) { + fLeft = std::min(p0.fX, p1.fX); + fRight = std::max(p0.fX, p1.fX); + fTop = std::min(p0.fY, p1.fY); + fBottom = std::max(p0.fY, p1.fY); + } + + /** Sets SkRect to (x, y, x + width, y + height). + Does not validate input; width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ + void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { + fLeft = x; + fTop = y; + fRight = x + width; + fBottom = y + height; + } + + /** Sets SkRect to (0, 0, width, height). Does not validate input; + width or height may be negative. + + @param width stored in fRight + @param height stored in fBottom + */ + void setWH(SkScalar width, SkScalar height) { + fLeft = 0; + fTop = 0; + fRight = width; + fBottom = height; + } + void setIWH(int32_t width, int32_t height) { + this->setWH(SkIntToScalar(width), SkIntToScalar(height)); + } + + /** Returns SkRect offset by (dx, dy). + + If dx is negative, SkRect returned is moved to the left. + If dx is positive, SkRect returned is moved to the right. + If dy is negative, SkRect returned is moved upward. + If dy is positive, SkRect returned is moved downward. + + @param dx added to fLeft and fRight + @param dy added to fTop and fBottom + @return SkRect offset on axes, with original width and height + */ + constexpr SkRect makeOffset(SkScalar dx, SkScalar dy) const { + return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy); + } + + /** Returns SkRect offset by v. + + @param v added to rect + @return SkRect offset on axes, with original width and height + */ + constexpr SkRect makeOffset(SkVector v) const { return this->makeOffset(v.x(), v.y()); } + + /** Returns SkRect, inset by (dx, dy). + + If dx is negative, SkRect returned is wider. + If dx is positive, SkRect returned is narrower. + If dy is negative, SkRect returned is taller. + If dy is positive, SkRect returned is shorter. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + @return SkRect inset symmetrically left and right, top and bottom + */ + SkRect makeInset(SkScalar dx, SkScalar dy) const { + return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy); + } + + /** Returns SkRect, outset by (dx, dy). + + If dx is negative, SkRect returned is narrower. + If dx is positive, SkRect returned is wider. + If dy is negative, SkRect returned is shorter. + If dy is positive, SkRect returned is taller. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + @return SkRect outset symmetrically left and right, top and bottom + */ + SkRect makeOutset(SkScalar dx, SkScalar dy) const { + return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy); + } + + /** Offsets SkRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkRect to the left. + If dx is positive, moves SkRect to the right. + If dy is negative, moves SkRect upward. + If dy is positive, moves SkRect downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + */ + void offset(SkScalar dx, SkScalar dy) { + fLeft += dx; + fTop += dy; + fRight += dx; + fBottom += dy; + } + + /** Offsets SkRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkRect to the left. + If delta.fX is positive, moves SkRect to the right. + If delta.fY is negative, moves SkRect upward. + If delta.fY is positive, moves SkRect downward. + + @param delta added to SkRect + */ + void offset(const SkPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** Offsets SkRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ + void offsetTo(SkScalar newX, SkScalar newY) { + fRight += newX - fLeft; + fBottom += newY - fTop; + fLeft = newX; + fTop = newY; + } + + /** Insets SkRect by (dx, dy). + + If dx is positive, makes SkRect narrower. + If dx is negative, makes SkRect wider. + If dy is positive, makes SkRect shorter. + If dy is negative, makes SkRect taller. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + */ + void inset(SkScalar dx, SkScalar dy) { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= dy; + } + + /** Outsets SkRect by (dx, dy). + + If dx is positive, makes SkRect wider. + If dx is negative, makes SkRect narrower. + If dy is positive, makes SkRect taller. + If dy is negative, makes SkRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + */ + void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } + + /** Returns true if SkRect intersects r, and sets SkRect to intersection. + Returns false if SkRect does not intersect r, and leaves SkRect unchanged. + + Returns false if either r or SkRect is empty, leaving SkRect unchanged. + + @param r limit of result + @return true if r and SkRect have area in common + + example: https://fiddle.skia.org/c/@Rect_intersect + */ + bool intersect(const SkRect& r); + + /** Returns true if a intersects b, and sets SkRect to intersection. + Returns false if a does not intersect b, and leaves SkRect unchanged. + + Returns false if either a or b is empty, leaving SkRect unchanged. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ + bool SK_WARN_UNUSED_RESULT intersect(const SkRect& a, const SkRect& b); + + +private: + static bool Intersects(SkScalar al, SkScalar at, SkScalar ar, SkScalar ab, + SkScalar bl, SkScalar bt, SkScalar br, SkScalar bb) { + SkScalar L = std::max(al, bl); + SkScalar R = std::min(ar, br); + SkScalar T = std::max(at, bt); + SkScalar B = std::min(ab, bb); + return L < R && T < B; + } + +public: + + /** Returns true if SkRect intersects r. + Returns false if either r or SkRect is empty, or do not intersect. + + @param r SkRect to intersect + @return true if r and SkRect have area in common + */ + bool intersects(const SkRect& r) const { + return Intersects(fLeft, fTop, fRight, fBottom, + r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ + static bool Intersects(const SkRect& a, const SkRect& b) { + return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom, + b.fLeft, b.fTop, b.fRight, b.fBottom); + } + + /** Sets SkRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkRect is empty, sets + SkRect to r. + + @param r expansion SkRect + + example: https://fiddle.skia.org/c/@Rect_join_2 + */ + void join(const SkRect& r); + + /** Sets SkRect to the union of itself and r. + + Asserts if r is empty and SK_DEBUG is defined. + If SkRect is empty, sets SkRect to r. + + May produce incorrect results if r is empty. + + @param r expansion SkRect + */ + void joinNonEmptyArg(const SkRect& r) { + SkASSERT(!r.isEmpty()); + // if we are empty, just assign + if (fLeft >= fRight || fTop >= fBottom) { + *this = r; + } else { + this->joinPossiblyEmptyRect(r); + } + } + + /** Sets SkRect to the union of itself and the construction. + + May produce incorrect results if SkRect or r is empty. + + @param r expansion SkRect + */ + void joinPossiblyEmptyRect(const SkRect& r) { + fLeft = std::min(fLeft, r.left()); + fTop = std::min(fTop, r.top()); + fRight = std::max(fRight, r.right()); + fBottom = std::max(fBottom, r.bottom()); + } + + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkRect is empty. + + @param x test SkPoint x-coordinate + @param y test SkPoint y-coordinate + @return true if (x, y) is inside SkRect + */ + bool contains(SkScalar x, SkScalar y) const { + return x >= fLeft && x < fRight && y >= fTop && y < fBottom; + } + + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkRect are outside r + */ + bool contains(const SkRect& r) const { + // todo: can we eliminate the this->isEmpty check? + return !r.isEmpty() && !this->isEmpty() && + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkRect are outside r + */ + bool contains(const SkIRect& r) const { + // todo: can we eliminate the this->isEmpty check? + return !r.isEmpty() && !this->isEmpty() && + fLeft <= SkIntToScalar(r.fLeft) && fTop <= SkIntToScalar(r.fTop) && + fRight >= SkIntToScalar(r.fRight) && fBottom >= SkIntToScalar(r.fBottom); + } + + /** Sets SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)). + + @param dst storage for SkIRect + */ + void round(SkIRect* dst) const { + SkASSERT(dst); + dst->setLTRB(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); + } + + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @param dst storage for SkIRect + */ + void roundOut(SkIRect* dst) const { + SkASSERT(dst); + dst->setLTRB(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)); + } + + /** Sets SkRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @param dst storage for SkRect + */ + void roundOut(SkRect* dst) const { + dst->setLTRB(SkScalarFloorToScalar(fLeft), SkScalarFloorToScalar(fTop), + SkScalarCeilToScalar(fRight), SkScalarCeilToScalar(fBottom)); + } + + /** Sets SkRect by rounding up fLeft and fTop; and discarding the fractional portion + of fRight and fBottom, using + (SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)). + + @param dst storage for SkIRect + */ + void roundIn(SkIRect* dst) const { + SkASSERT(dst); + dst->setLTRB(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)); + } + + /** Returns SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)). + + @return rounded SkIRect + */ + SkIRect round() const { + SkIRect ir; + this->round(&ir); + return ir; + } + + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @return rounded SkIRect + */ + SkIRect roundOut() const { + SkIRect ir; + this->roundOut(&ir); + return ir; + } + /** Sets SkIRect by rounding up fLeft and fTop; and discarding the fractional portion + of fRight and fBottom, using + (SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)). + + @return rounded SkIRect + */ + SkIRect roundIn() const { + SkIRect ir; + this->roundIn(&ir); + return ir; + } + + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + */ + void sort() { + using std::swap; + if (fLeft > fRight) { + swap(fLeft, fRight); + } + + if (fTop > fBottom) { + swap(fTop, fBottom); + } + } + + /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkRect + */ + SkRect makeSorted() const { + return MakeLTRB(std::min(fLeft, fRight), std::min(fTop, fBottom), + std::max(fLeft, fRight), std::max(fTop, fBottom)); + } + + /** Returns pointer to first scalar in SkRect, to treat it as an array with four + entries. + + @return pointer to fLeft + */ + const SkScalar* asScalars() const { return &fLeft; } + + /** Writes text representation of SkRect to standard output. Set asHex to true to + generate exact binary representations of floating point numbers. + + @param asHex true if SkScalar values are written as hexadecimal + + example: https://fiddle.skia.org/c/@Rect_dump + */ + void dump(bool asHex) const; + + /** Writes text representation of SkRect to standard output. The representation may be + directly compiled as C++ code. Floating point values are written + with limited precision; it may not be possible to reconstruct original SkRect + from output. + */ + void dump() const { this->dump(false); } + + /** Writes text representation of SkRect to standard output. The representation may be + directly compiled as C++ code. Floating point values are written + in hexadecimal to preserve their exact bit pattern. The output reconstructs the + original SkRect. + + Use instead of dump() when submitting + */ + void dumpHex() const { this->dump(true); } +}; + +inline bool SkIRect::contains(const SkRect& r) const { + return !r.isEmpty() && !this->isEmpty() && // check for empties + (SkScalar)fLeft <= r.fLeft && (SkScalar)fTop <= r.fTop && + (SkScalar)fRight >= r.fRight && (SkScalar)fBottom >= r.fBottom; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRefCnt.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRefCnt.h new file mode 100644 index 00000000000000..668de14e1d1afb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRefCnt.h @@ -0,0 +1,389 @@ +/* + * 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 SkRefCnt_DEFINED +#define SkRefCnt_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/base/SkDebug.h" + +#include +#include +#include +#include +#include +#include + +/** \class SkRefCntBase + + SkRefCntBase is the base class for objects that may be shared by multiple + objects. When an existing owner wants to share a reference, it calls ref(). + When an owner wants to release its reference, it calls unref(). When the + shared object's reference count goes to zero as the result of an unref() + call, its (virtual) destructor is called. It is an error for the + destructor to be called explicitly (or via the object going out of scope on + the stack or calling delete) if getRefCnt() > 1. +*/ +class SK_API SkRefCntBase { +public: + /** Default construct, initializing the reference count to 1. + */ + SkRefCntBase() : fRefCnt(1) {} + + /** Destruct, asserting that the reference count is 1. + */ + virtual ~SkRefCntBase() { + #ifdef SK_DEBUG + SkASSERTF(this->getRefCnt() == 1, "fRefCnt was %d", this->getRefCnt()); + // illegal value, to catch us if we reuse after delete + fRefCnt.store(0, std::memory_order_relaxed); + #endif + } + + /** May return true if the caller is the only owner. + * Ensures that all previous owner's actions are complete. + */ + bool unique() const { + if (1 == fRefCnt.load(std::memory_order_acquire)) { + // The acquire barrier is only really needed if we return true. It + // prevents code conditioned on the result of unique() from running + // until previous owners are all totally done calling unref(). + return true; + } + return false; + } + + /** Increment the reference count. Must be balanced by a call to unref(). + */ + void ref() const { + SkASSERT(this->getRefCnt() > 0); + // No barrier required. + (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); + } + + /** Decrement the reference count. If the reference count is 1 before the + decrement, then delete the object. Note that if this is the case, then + the object needs to have been allocated via new, and not on the stack. + */ + void unref() const { + SkASSERT(this->getRefCnt() > 0); + // A release here acts in place of all releases we "should" have been doing in ref(). + if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // Like unique(), the acquire is only needed on success, to make sure + // code in internal_dispose() doesn't happen before the decrement. + this->internal_dispose(); + } + } + +private: + +#ifdef SK_DEBUG + /** Return the reference count. Use only for debugging. */ + int32_t getRefCnt() const { + return fRefCnt.load(std::memory_order_relaxed); + } +#endif + + /** + * Called when the ref count goes to 0. + */ + virtual void internal_dispose() const { + #ifdef SK_DEBUG + SkASSERT(0 == this->getRefCnt()); + fRefCnt.store(1, std::memory_order_relaxed); + #endif + delete this; + } + + // The following friends are those which override internal_dispose() + // and conditionally call SkRefCnt::internal_dispose(). + friend class SkWeakRefCnt; + + mutable std::atomic fRefCnt; + + SkRefCntBase(SkRefCntBase&&) = delete; + SkRefCntBase(const SkRefCntBase&) = delete; + SkRefCntBase& operator=(SkRefCntBase&&) = delete; + SkRefCntBase& operator=(const SkRefCntBase&) = delete; +}; + +#ifdef SK_REF_CNT_MIXIN_INCLUDE +// It is the responsibility of the following include to define the type SkRefCnt. +// This SkRefCnt should normally derive from SkRefCntBase. +#include SK_REF_CNT_MIXIN_INCLUDE +#else +class SK_API SkRefCnt : public SkRefCntBase { + // "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system. + #if defined(SK_BUILD_FOR_GOOGLE3) + public: + void deref() const { this->unref(); } + #endif +}; +#endif + +/////////////////////////////////////////////////////////////////////////////// + +/** Call obj->ref() and return obj. The obj must not be nullptr. + */ +template static inline T* SkRef(T* obj) { + SkASSERT(obj); + obj->ref(); + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->ref() and return obj. + */ +template static inline T* SkSafeRef(T* obj) { + if (obj) { + obj->ref(); + } + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->unref() + */ +template static inline void SkSafeUnref(T* obj) { + if (obj) { + obj->unref(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16. +// There's only benefit to using this if the deriving class does not otherwise need a vtable. +template +class SkNVRefCnt { +public: + SkNVRefCnt() : fRefCnt(1) {} + ~SkNVRefCnt() { + #ifdef SK_DEBUG + int rc = fRefCnt.load(std::memory_order_relaxed); + SkASSERTF(rc == 1, "NVRefCnt was %d", rc); + #endif + } + + // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same: + // - unique() needs acquire when it returns true, and no barrier if it returns false; + // - ref() doesn't need any barrier; + // - unref() needs a release barrier, and an acquire if it's going to call delete. + + bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); } + void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } + void unref() const { + if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // restore the 1 for our destructor's assert + SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed)); + delete (const Derived*)this; + } + } + void deref() const { this->unref(); } + + // This must be used with caution. It is only valid to call this when 'threadIsolatedTestCnt' + // refs are known to be isolated to the current thread. That is, it is known that there are at + // least 'threadIsolatedTestCnt' refs for which no other thread may make a balancing unref() + // call. Assuming the contract is followed, if this returns false then no other thread has + // ownership of this. If it returns true then another thread *may* have ownership. + bool refCntGreaterThan(int32_t threadIsolatedTestCnt) const { + int cnt = fRefCnt.load(std::memory_order_acquire); + // If this fails then the above contract has been violated. + SkASSERT(cnt >= threadIsolatedTestCnt); + return cnt > threadIsolatedTestCnt; + } + +private: + mutable std::atomic fRefCnt; + + SkNVRefCnt(SkNVRefCnt&&) = delete; + SkNVRefCnt(const SkNVRefCnt&) = delete; + SkNVRefCnt& operator=(SkNVRefCnt&&) = delete; + SkNVRefCnt& operator=(const SkNVRefCnt&) = delete; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Shared pointer class to wrap classes that support a ref()/unref() interface. + * + * This can be used for classes inheriting from SkRefCnt, but it also works for other + * classes that match the interface, but have different internal choices: e.g. the hosted class + * may have its ref/unref be thread-safe, but that is not assumed/imposed by sk_sp. + * + * Declared with the trivial_abi attribute where supported so that sk_sp and types containing it + * may be considered as trivially relocatable by the compiler so that destroying-move operations + * i.e. move constructor followed by destructor can be optimized to memcpy. + */ +template class SK_TRIVIAL_ABI sk_sp { +public: + using element_type = T; + + constexpr sk_sp() : fPtr(nullptr) {} + constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {} + + /** + * Shares the underlying object by calling ref(), so that both the argument and the newly + * created sk_sp both have a reference to it. + */ + sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {} + template ::value>::type> + sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {} + + /** + * Move the underlying object from the argument to the newly created sk_sp. Afterwards only + * the new sk_sp will have a reference to the object, and the argument will point to null. + * No call to ref() or unref() will be made. + */ + sk_sp(sk_sp&& that) : fPtr(that.release()) {} + template ::value>::type> + sk_sp(sk_sp&& that) : fPtr(that.release()) {} + + /** + * Adopt the bare pointer into the newly created sk_sp. + * No call to ref() or unref() will be made. + */ + explicit sk_sp(T* obj) : fPtr(obj) {} + + /** + * Calls unref() on the underlying object pointer. + */ + ~sk_sp() { + SkSafeUnref(fPtr); + SkDEBUGCODE(fPtr = nullptr); + } + + sk_sp& operator=(std::nullptr_t) { this->reset(); return *this; } + + /** + * Shares the underlying object referenced by the argument by calling ref() on it. If this + * sk_sp previously had a reference to an object (i.e. not null) it will call unref() on that + * object. + */ + sk_sp& operator=(const sk_sp& that) { + if (this != &that) { + this->reset(SkSafeRef(that.get())); + } + return *this; + } + template ::value>::type> + sk_sp& operator=(const sk_sp& that) { + this->reset(SkSafeRef(that.get())); + return *this; + } + + /** + * Move the underlying object from the argument to the sk_sp. If the sk_sp previously held + * a reference to another object, unref() will be called on that object. No call to ref() + * will be made. + */ + sk_sp& operator=(sk_sp&& that) { + this->reset(that.release()); + return *this; + } + template ::value>::type> + sk_sp& operator=(sk_sp&& that) { + this->reset(that.release()); + return *this; + } + + T& operator*() const { + SkASSERT(this->get() != nullptr); + return *this->get(); + } + + explicit operator bool() const { return this->get() != nullptr; } + + T* get() const { return fPtr; } + T* operator->() const { return fPtr; } + + /** + * Adopt the new bare pointer, and call unref() on any previously held object (if not null). + * No call to ref() will be made. + */ + void reset(T* ptr = nullptr) { + // Calling fPtr->unref() may call this->~() or this->reset(T*). + // http://wg21.cmeerw.net/lwg/issue998 + // http://wg21.cmeerw.net/lwg/issue2262 + T* oldPtr = fPtr; + fPtr = ptr; + SkSafeUnref(oldPtr); + } + + /** + * Return the bare pointer, and set the internal object pointer to nullptr. + * The caller must assume ownership of the object, and manage its reference count directly. + * No call to unref() will be made. + */ + T* SK_WARN_UNUSED_RESULT release() { + T* ptr = fPtr; + fPtr = nullptr; + return ptr; + } + + void swap(sk_sp& that) /*noexcept*/ { + using std::swap; + swap(fPtr, that.fPtr); + } + + using sk_is_trivially_relocatable = std::true_type; + +private: + T* fPtr; +}; + +template inline void swap(sk_sp& a, sk_sp& b) /*noexcept*/ { + a.swap(b); +} + +template inline bool operator==(const sk_sp& a, const sk_sp& b) { + return a.get() == b.get(); +} +template inline bool operator==(const sk_sp& a, std::nullptr_t) /*noexcept*/ { + return !a; +} +template inline bool operator==(std::nullptr_t, const sk_sp& b) /*noexcept*/ { + return !b; +} + +template inline bool operator!=(const sk_sp& a, const sk_sp& b) { + return a.get() != b.get(); +} +template inline bool operator!=(const sk_sp& a, std::nullptr_t) /*noexcept*/ { + return static_cast(a); +} +template inline bool operator!=(std::nullptr_t, const sk_sp& b) /*noexcept*/ { + return static_cast(b); +} + +template +auto operator<<(std::basic_ostream& os, const sk_sp& sp) -> decltype(os << sp.get()) { + return os << sp.get(); +} + +template +sk_sp sk_make_sp(Args&&... args) { + return sk_sp(new T(std::forward(args)...)); +} + +/* + * Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null). + * + * This is different than the semantics of the constructor for sk_sp, which just wraps the ptr, + * effectively "adopting" it. + */ +template sk_sp sk_ref_sp(T* obj) { + return sk_sp(SkSafeRef(obj)); +} + +template sk_sp sk_ref_sp(const T* obj) { + return sk_sp(const_cast(SkSafeRef(obj))); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRegion.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRegion.h new file mode 100644 index 00000000000000..6f8aa25d54282c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkRegion.h @@ -0,0 +1,678 @@ +/* + * Copyright 2005 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 SkRegion_DEFINED +#define SkRegion_DEFINED + +#include "include/core/SkRect.h" +#include "include/private/base/SkTypeTraits.h" + +class SkPath; +class SkRgnBuilder; + +/** \class SkRegion + SkRegion describes the set of pixels used to clip SkCanvas. SkRegion is compact, + efficiently storing a single integer rectangle, or a run length encoded array + of rectangles. SkRegion may reduce the current SkCanvas clip, or may be drawn as + one or more integer rectangles. SkRegion iterator returns the scan lines or + rectangles contained by it, optionally intersecting a bounding rectangle. +*/ +class SK_API SkRegion { + typedef int32_t RunType; +public: + + /** Constructs an empty SkRegion. SkRegion is set to empty bounds + at (0, 0) with zero width and height. + + @return empty SkRegion + + example: https://fiddle.skia.org/c/@Region_empty_constructor + */ + SkRegion(); + + /** Constructs a copy of an existing region. + Copy constructor makes two regions identical by value. Internally, region and + the returned result share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param region SkRegion to copy by value + @return copy of SkRegion + + example: https://fiddle.skia.org/c/@Region_copy_const_SkRegion + */ + SkRegion(const SkRegion& region); + + /** Constructs a rectangular SkRegion matching the bounds of rect. + + @param rect bounds of constructed SkRegion + @return rectangular SkRegion + + example: https://fiddle.skia.org/c/@Region_copy_const_SkIRect + */ + explicit SkRegion(const SkIRect& rect); + + /** Releases ownership of any shared data and deletes data if SkRegion is sole owner. + + example: https://fiddle.skia.org/c/@Region_destructor + */ + ~SkRegion(); + + /** Constructs a copy of an existing region. + Makes two regions identical by value. Internally, region and + the returned result share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param region SkRegion to copy by value + @return SkRegion to copy by value + + example: https://fiddle.skia.org/c/@Region_copy_operator + */ + SkRegion& operator=(const SkRegion& region); + + /** Compares SkRegion and other; returns true if they enclose exactly + the same area. + + @param other SkRegion to compare + @return true if SkRegion pair are equivalent + + example: https://fiddle.skia.org/c/@Region_equal1_operator + */ + bool operator==(const SkRegion& other) const; + + /** Compares SkRegion and other; returns true if they do not enclose the same area. + + @param other SkRegion to compare + @return true if SkRegion pair are not equivalent + */ + bool operator!=(const SkRegion& other) const { + return !(*this == other); + } + + /** Sets SkRegion to src, and returns true if src bounds is not empty. + This makes SkRegion and src identical by value. Internally, + SkRegion and src share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param src SkRegion to copy + @return copy of src + */ + bool set(const SkRegion& src) { + *this = src; + return !this->isEmpty(); + } + + /** Exchanges SkIRect array of SkRegion and other. swap() internally exchanges pointers, + so it is lightweight and does not allocate memory. + + swap() usage has largely been replaced by operator=(const SkRegion& region). + SkPath do not copy their content on assignment until they are written to, + making assignment as efficient as swap(). + + @param other operator=(const SkRegion& region) set + + example: https://fiddle.skia.org/c/@Region_swap + */ + void swap(SkRegion& other); + + /** Returns true if SkRegion is empty. + Empty SkRegion has bounds width or height less than or equal to zero. + SkRegion() constructs empty SkRegion; setEmpty() + and setRect() with dimensionless data make SkRegion empty. + + @return true if bounds has no width or height + */ + bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); } + + /** Returns true if SkRegion is one SkIRect with positive dimensions. + + @return true if SkRegion contains one SkIRect + */ + bool isRect() const { return fRunHead == kRectRunHeadPtr; } + + /** Returns true if SkRegion is described by more than one rectangle. + + @return true if SkRegion contains more than one SkIRect + */ + bool isComplex() const { return !this->isEmpty() && !this->isRect(); } + + /** Returns minimum and maximum axes values of SkIRect array. + Returns (0, 0, 0, 0) if SkRegion is empty. + + @return combined bounds of all SkIRect elements + */ + const SkIRect& getBounds() const { return fBounds; } + + /** Returns a value that increases with the number of + elements in SkRegion. Returns zero if SkRegion is empty. + Returns one if SkRegion equals SkIRect; otherwise, returns + value greater than one indicating that SkRegion is complex. + + Call to compare SkRegion for relative complexity. + + @return relative complexity + + example: https://fiddle.skia.org/c/@Region_computeRegionComplexity + */ + int computeRegionComplexity() const; + + /** Appends outline of SkRegion to path. + Returns true if SkRegion is not empty; otherwise, returns false, and leaves path + unmodified. + + @param path SkPath to append to + @return true if path changed + + example: https://fiddle.skia.org/c/@Region_getBoundaryPath + */ + bool getBoundaryPath(SkPath* path) const; + + /** Constructs an empty SkRegion. SkRegion is set to empty bounds + at (0, 0) with zero width and height. Always returns false. + + @return false + + example: https://fiddle.skia.org/c/@Region_setEmpty + */ + bool setEmpty(); + + /** Constructs a rectangular SkRegion matching the bounds of rect. + If rect is empty, constructs empty and returns false. + + @param rect bounds of constructed SkRegion + @return true if rect is not empty + + example: https://fiddle.skia.org/c/@Region_setRect + */ + bool setRect(const SkIRect& rect); + + /** Constructs SkRegion as the union of SkIRect in rects array. If count is + zero, constructs empty SkRegion. Returns false if constructed SkRegion is empty. + + May be faster than repeated calls to op(). + + @param rects array of SkIRect + @param count array size + @return true if constructed SkRegion is not empty + + example: https://fiddle.skia.org/c/@Region_setRects + */ + bool setRects(const SkIRect rects[], int count); + + /** Constructs a copy of an existing region. + Makes two regions identical by value. Internally, region and + the returned result share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param region SkRegion to copy by value + @return SkRegion to copy by value + + example: https://fiddle.skia.org/c/@Region_setRegion + */ + bool setRegion(const SkRegion& region); + + /** Constructs SkRegion to match outline of path within clip. + Returns false if constructed SkRegion is empty. + + Constructed SkRegion draws the same pixels as path through clip when + anti-aliasing is disabled. + + @param path SkPath providing outline + @param clip SkRegion containing path + @return true if constructed SkRegion is not empty + + example: https://fiddle.skia.org/c/@Region_setPath + */ + bool setPath(const SkPath& path, const SkRegion& clip); + + /** Returns true if SkRegion intersects rect. + Returns false if either rect or SkRegion is empty, or do not intersect. + + @param rect SkIRect to intersect + @return true if rect and SkRegion have area in common + + example: https://fiddle.skia.org/c/@Region_intersects + */ + bool intersects(const SkIRect& rect) const; + + /** Returns true if SkRegion intersects other. + Returns false if either other or SkRegion is empty, or do not intersect. + + @param other SkRegion to intersect + @return true if other and SkRegion have area in common + + example: https://fiddle.skia.org/c/@Region_intersects_2 + */ + bool intersects(const SkRegion& other) const; + + /** Returns true if SkIPoint (x, y) is inside SkRegion. + Returns false if SkRegion is empty. + + @param x test SkIPoint x-coordinate + @param y test SkIPoint y-coordinate + @return true if (x, y) is inside SkRegion + + example: https://fiddle.skia.org/c/@Region_contains + */ + bool contains(int32_t x, int32_t y) const; + + /** Returns true if other is completely inside SkRegion. + Returns false if SkRegion or other is empty. + + @param other SkIRect to contain + @return true if other is inside SkRegion + + example: https://fiddle.skia.org/c/@Region_contains_2 + */ + bool contains(const SkIRect& other) const; + + /** Returns true if other is completely inside SkRegion. + Returns false if SkRegion or other is empty. + + @param other SkRegion to contain + @return true if other is inside SkRegion + + example: https://fiddle.skia.org/c/@Region_contains_3 + */ + bool contains(const SkRegion& other) const; + + /** Returns true if SkRegion is a single rectangle and contains r. + May return false even though SkRegion contains r. + + @param r SkIRect to contain + @return true quickly if r points are equal or inside + */ + bool quickContains(const SkIRect& r) const { + SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region + + return r.fLeft < r.fRight && r.fTop < r.fBottom && + fRunHead == kRectRunHeadPtr && // this->isRect() + /* fBounds.contains(left, top, right, bottom); */ + fBounds.fLeft <= r.fLeft && fBounds.fTop <= r.fTop && + fBounds.fRight >= r.fRight && fBounds.fBottom >= r.fBottom; + } + + /** Returns true if SkRegion does not intersect rect. + Returns true if rect is empty or SkRegion is empty. + May return false even though SkRegion does not intersect rect. + + @param rect SkIRect to intersect + @return true if rect does not intersect + */ + bool quickReject(const SkIRect& rect) const { + return this->isEmpty() || rect.isEmpty() || + !SkIRect::Intersects(fBounds, rect); + } + + /** Returns true if SkRegion does not intersect rgn. + Returns true if rgn is empty or SkRegion is empty. + May return false even though SkRegion does not intersect rgn. + + @param rgn SkRegion to intersect + @return true if rgn does not intersect + */ + bool quickReject(const SkRegion& rgn) const { + return this->isEmpty() || rgn.isEmpty() || + !SkIRect::Intersects(fBounds, rgn.fBounds); + } + + /** Offsets SkRegion by ivector (dx, dy). Has no effect if SkRegion is empty. + + @param dx x-axis offset + @param dy y-axis offset + */ + void translate(int dx, int dy) { this->translate(dx, dy, this); } + + /** Offsets SkRegion by ivector (dx, dy), writing result to dst. SkRegion may be passed + as dst parameter, translating SkRegion in place. Has no effect if dst is nullptr. + If SkRegion is empty, sets dst to empty. + + @param dx x-axis offset + @param dy y-axis offset + @param dst translated result + + example: https://fiddle.skia.org/c/@Region_translate_2 + */ + void translate(int dx, int dy, SkRegion* dst) const; + + /** \enum SkRegion::Op + The logical operations that can be performed when combining two SkRegion. + */ + enum Op { + kDifference_Op, //!< target minus operand + kIntersect_Op, //!< target intersected with operand + kUnion_Op, //!< target unioned with operand + kXOR_Op, //!< target exclusive or with operand + kReverseDifference_Op, //!< operand minus target + kReplace_Op, //!< replace target with operand + kLastOp = kReplace_Op, //!< last operator + }; + + static const int kOpCnt = kLastOp + 1; + + /** Replaces SkRegion with the result of SkRegion op rect. + Returns true if replaced SkRegion is not empty. + + @param rect SkIRect operand + @return false if result is empty + */ + bool op(const SkIRect& rect, Op op) { + if (this->isRect() && kIntersect_Op == op) { + if (!fBounds.intersect(rect)) { + return this->setEmpty(); + } + return true; + } + return this->op(*this, rect, op); + } + + /** Replaces SkRegion with the result of SkRegion op rgn. + Returns true if replaced SkRegion is not empty. + + @param rgn SkRegion operand + @return false if result is empty + */ + bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } + + /** Replaces SkRegion with the result of rect op rgn. + Returns true if replaced SkRegion is not empty. + + @param rect SkIRect operand + @param rgn SkRegion operand + @return false if result is empty + + example: https://fiddle.skia.org/c/@Region_op_4 + */ + bool op(const SkIRect& rect, const SkRegion& rgn, Op op); + + /** Replaces SkRegion with the result of rgn op rect. + Returns true if replaced SkRegion is not empty. + + @param rgn SkRegion operand + @param rect SkIRect operand + @return false if result is empty + + example: https://fiddle.skia.org/c/@Region_op_5 + */ + bool op(const SkRegion& rgn, const SkIRect& rect, Op op); + + /** Replaces SkRegion with the result of rgna op rgnb. + Returns true if replaced SkRegion is not empty. + + @param rgna SkRegion operand + @param rgnb SkRegion operand + @return false if result is empty + + example: https://fiddle.skia.org/c/@Region_op_6 + */ + bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + /** Private. Android framework only. + + @return string representation of SkRegion + */ + char* toString(); +#endif + + /** \class SkRegion::Iterator + Returns sequence of rectangles, sorted along y-axis, then x-axis, that make + up SkRegion. + */ + class SK_API Iterator { + public: + + /** Initializes SkRegion::Iterator with an empty SkRegion. done() on SkRegion::Iterator + returns true. + Call reset() to initialized SkRegion::Iterator at a later time. + + @return empty SkRegion iterator + */ + Iterator() : fRgn(nullptr), fDone(true) {} + + /** Sets SkRegion::Iterator to return elements of SkIRect array in region. + + @param region SkRegion to iterate + @return SkRegion iterator + + example: https://fiddle.skia.org/c/@Region_Iterator_copy_const_SkRegion + */ + Iterator(const SkRegion& region); + + /** SkPoint SkRegion::Iterator to start of SkRegion. + Returns true if SkRegion was set; otherwise, returns false. + + @return true if SkRegion was set + + example: https://fiddle.skia.org/c/@Region_Iterator_rewind + */ + bool rewind(); + + /** Resets iterator, using the new SkRegion. + + @param region SkRegion to iterate + + example: https://fiddle.skia.org/c/@Region_Iterator_reset + */ + void reset(const SkRegion& region); + + /** Returns true if SkRegion::Iterator is pointing to final SkIRect in SkRegion. + + @return true if data parsing is complete + */ + bool done() const { return fDone; } + + /** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done. + + example: https://fiddle.skia.org/c/@Region_Iterator_next + */ + void next(); + + /** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion + is empty. + + @return part of SkRegion as SkIRect + */ + const SkIRect& rect() const { return fRect; } + + /** Returns SkRegion if set; otherwise, returns nullptr. + + @return iterated SkRegion + */ + const SkRegion* rgn() const { return fRgn; } + + private: + const SkRegion* fRgn; + const SkRegion::RunType* fRuns; + SkIRect fRect = {0, 0, 0, 0}; + bool fDone; + }; + + /** \class SkRegion::Cliperator + Returns the sequence of rectangles, sorted along y-axis, then x-axis, that make + up SkRegion intersected with the specified clip rectangle. + */ + class SK_API Cliperator { + public: + + /** Sets SkRegion::Cliperator to return elements of SkIRect array in SkRegion within clip. + + @param region SkRegion to iterate + @param clip bounds of iteration + @return SkRegion iterator + + example: https://fiddle.skia.org/c/@Region_Cliperator_const_SkRegion_const_SkIRect + */ + Cliperator(const SkRegion& region, const SkIRect& clip); + + /** Returns true if SkRegion::Cliperator is pointing to final SkIRect in SkRegion. + + @return true if data parsing is complete + */ + bool done() { return fDone; } + + /** Advances iterator to next SkIRect in SkRegion contained by clip. + + example: https://fiddle.skia.org/c/@Region_Cliperator_next + */ + void next(); + + /** Returns SkIRect element in SkRegion, intersected with clip passed to + SkRegion::Cliperator constructor. Does not return predictable results if SkRegion + is empty. + + @return part of SkRegion inside clip as SkIRect + */ + const SkIRect& rect() const { return fRect; } + + private: + Iterator fIter; + SkIRect fClip; + SkIRect fRect = {0, 0, 0, 0}; + bool fDone; + }; + + /** \class SkRegion::Spanerator + Returns the line segment ends within SkRegion that intersect a horizontal line. + */ + class Spanerator { + public: + + /** Sets SkRegion::Spanerator to return line segments in SkRegion on scan line. + + @param region SkRegion to iterate + @param y horizontal line to intersect + @param left bounds of iteration + @param right bounds of iteration + @return SkRegion iterator + + example: https://fiddle.skia.org/c/@Region_Spanerator_const_SkRegion_int_int_int + */ + Spanerator(const SkRegion& region, int y, int left, int right); + + /** Advances iterator to next span intersecting SkRegion within line segment provided + in constructor. Returns true if interval was found. + + @param left pointer to span start; may be nullptr + @param right pointer to span end; may be nullptr + @return true if interval was found + + example: https://fiddle.skia.org/c/@Region_Spanerator_next + */ + bool next(int* left, int* right); + + private: + const SkRegion::RunType* fRuns; + int fLeft, fRight; + bool fDone; + }; + + /** Writes SkRegion to buffer, and returns number of bytes written. + If buffer is nullptr, returns number number of bytes that would be written. + + @param buffer storage for binary data + @return size of SkRegion + + example: https://fiddle.skia.org/c/@Region_writeToMemory + */ + size_t writeToMemory(void* buffer) const; + + /** Constructs SkRegion from buffer of size length. Returns bytes read. + Returned value will be multiple of four or zero if length was too small. + + @param buffer storage for binary data + @param length size of buffer + @return bytes read + + example: https://fiddle.skia.org/c/@Region_readFromMemory + */ + size_t readFromMemory(const void* buffer, size_t length); + + using sk_is_trivially_relocatable = std::true_type; + +private: + static constexpr int kOpCount = kReplace_Op + 1; + + // T + // [B N L R S] + // S + static constexpr int kRectRegionRuns = 7; + + struct RunHead; + + static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; } + static constexpr RunHead* kRectRunHeadPtr = nullptr; + + // allocate space for count runs + void allocateRuns(int count); + void allocateRuns(int count, int ySpanCount, int intervalCount); + void allocateRuns(const RunHead& src); + + SkDEBUGCODE(void dump() const;) + + SkIRect fBounds; + RunHead* fRunHead; + + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + + void freeRuns(); + + /** + * Return the runs from this region, consing up fake runs if the region + * is empty or a rect. In those 2 cases, we use tmpStorage to hold the + * run data. + */ + const RunType* getRuns(RunType tmpStorage[], int* intervals) const; + + // This is called with runs[] that do not yet have their interval-count + // field set on each scanline. That is computed as part of this call + // (inside ComputeRunBounds). + bool setRuns(RunType runs[], int count); + + int count_runtype_values(int* itop, int* ibot) const; + + bool isValid() const; + + static void BuildRectRuns(const SkIRect& bounds, + RunType runs[kRectRegionRuns]); + + // If the runs define a simple rect, return true and set bounds to that + // rect. If not, return false and ignore bounds. + static bool RunsAreARect(const SkRegion::RunType runs[], int count, + SkIRect* bounds); + + /** + * If the last arg is null, just return if the result is non-empty, + * else store the result in the last arg. + */ + static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); + + friend struct RunHead; + friend class Iterator; + friend class Spanerator; + friend class SkRegionPriv; + friend class SkRgnBuilder; + friend class SkFlatRegion; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSamplingOptions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSamplingOptions.h new file mode 100644 index 00000000000000..24b6d51659607d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSamplingOptions.h @@ -0,0 +1,105 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageSampling_DEFINED +#define SkImageSampling_DEFINED + +#include "include/core/SkTypes.h" + +#include +#include + +enum class SkFilterMode { + kNearest, // single sample point (nearest neighbor) + kLinear, // interporate between 2x2 sample points (bilinear interpolation) + + kLast = kLinear, +}; +static constexpr int kSkFilterModeCount = static_cast(SkFilterMode::kLast) + 1; + +enum class SkMipmapMode { + kNone, // ignore mipmap levels, sample from the "base" + kNearest, // sample from the nearest level + kLinear, // interpolate between the two nearest levels + + kLast = kLinear, +}; +static constexpr int kSkMipmapModeCount = static_cast(SkMipmapMode::kLast) + 1; + +/* + * Specify B and C (each between 0...1) to create a shader that applies the corresponding + * cubic reconstruction filter to the image. + * + * Example values: + * B = 1/3, C = 1/3 "Mitchell" filter + * B = 0, C = 1/2 "Catmull-Rom" filter + * + * See "Reconstruction Filters in Computer Graphics" + * Don P. Mitchell + * Arun N. Netravali + * 1988 + * https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf + * + * Desmos worksheet https://www.desmos.com/calculator/aghdpicrvr + * Nice overview https://entropymine.com/imageworsener/bicubic/ + */ +struct SkCubicResampler { + float B, C; + + // Historic default for kHigh_SkFilterQuality + static constexpr SkCubicResampler Mitchell() { return {1/3.0f, 1/3.0f}; } + static constexpr SkCubicResampler CatmullRom() { return {0.0f, 1/2.0f}; } +}; + +struct SK_API SkSamplingOptions { + const int maxAniso = 0; + const bool useCubic = false; + const SkCubicResampler cubic = {0, 0}; + const SkFilterMode filter = SkFilterMode::kNearest; + const SkMipmapMode mipmap = SkMipmapMode::kNone; + + constexpr SkSamplingOptions() = default; + SkSamplingOptions(const SkSamplingOptions&) = default; + SkSamplingOptions& operator=(const SkSamplingOptions& that) { + this->~SkSamplingOptions(); // A pedantic no-op. + new (this) SkSamplingOptions(that); + return *this; + } + + constexpr SkSamplingOptions(SkFilterMode fm, SkMipmapMode mm) + : filter(fm) + , mipmap(mm) {} + + explicit constexpr SkSamplingOptions(SkFilterMode fm) + : filter(fm) + , mipmap(SkMipmapMode::kNone) {} + + explicit constexpr SkSamplingOptions(const SkCubicResampler& c) + : useCubic(true) + , cubic(c) {} + + static constexpr SkSamplingOptions Aniso(int maxAniso) { + return SkSamplingOptions{std::max(maxAniso, 1)}; + } + + bool operator==(const SkSamplingOptions& other) const { + return maxAniso == other.maxAniso + && useCubic == other.useCubic + && cubic.B == other.cubic.B + && cubic.C == other.cubic.C + && filter == other.filter + && mipmap == other.mipmap; + } + bool operator!=(const SkSamplingOptions& other) const { return !(*this == other); } + + bool isAniso() const { return maxAniso != 0; } + +private: + constexpr SkSamplingOptions(int maxAniso) : maxAniso(maxAniso) {} +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkScalar.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkScalar.h new file mode 100644 index 00000000000000..f3e11b34c25043 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkScalar.h @@ -0,0 +1,173 @@ +/* + * 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 SkScalar_DEFINED +#define SkScalar_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkFloatingPoint.h" + +typedef float SkScalar; + +#define SK_Scalar1 1.0f +#define SK_ScalarHalf 0.5f +#define SK_ScalarSqrt2 SK_FloatSqrt2 +#define SK_ScalarPI SK_FloatPI +#define SK_ScalarTanPIOver8 0.414213562f +#define SK_ScalarRoot2Over2 0.707106781f +#define SK_ScalarMax 3.402823466e+38f +#define SK_ScalarMin (-SK_ScalarMax) +#define SK_ScalarInfinity SK_FloatInfinity +#define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity +#define SK_ScalarNaN SK_FloatNaN + +#define SkScalarFloorToScalar(x) sk_float_floor(x) +#define SkScalarCeilToScalar(x) sk_float_ceil(x) +#define SkScalarRoundToScalar(x) sk_float_round(x) +#define SkScalarTruncToScalar(x) sk_float_trunc(x) + +#define SkScalarFloorToInt(x) sk_float_floor2int(x) +#define SkScalarCeilToInt(x) sk_float_ceil2int(x) +#define SkScalarRoundToInt(x) sk_float_round2int(x) + +#define SkScalarAbs(x) sk_float_abs(x) +#define SkScalarCopySign(x, y) sk_float_copysign(x, y) +#define SkScalarMod(x, y) sk_float_mod(x,y) +#define SkScalarSqrt(x) sk_float_sqrt(x) +#define SkScalarPow(b, e) sk_float_pow(b, e) + +#define SkScalarSin(radians) (float)sk_float_sin(radians) +#define SkScalarCos(radians) (float)sk_float_cos(radians) +#define SkScalarTan(radians) (float)sk_float_tan(radians) +#define SkScalarASin(val) (float)sk_float_asin(val) +#define SkScalarACos(val) (float)sk_float_acos(val) +#define SkScalarATan2(y, x) (float)sk_float_atan2(y,x) +#define SkScalarExp(x) (float)sk_float_exp(x) +#define SkScalarLog(x) (float)sk_float_log(x) +#define SkScalarLog2(x) (float)sk_float_log2(x) + +////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SkIntToScalar(x) static_cast(x) +#define SkIntToFloat(x) static_cast(x) +#define SkScalarTruncToInt(x) sk_float_saturate2int(x) + +#define SkScalarToFloat(x) static_cast(x) +#define SkFloatToScalar(x) static_cast(x) +#define SkScalarToDouble(x) static_cast(x) +#define SkDoubleToScalar(x) sk_double_to_float(x) + +static inline bool SkScalarIsNaN(SkScalar x) { return x != x; } + +/** Returns true if x is not NaN and not infinite + */ +static inline bool SkScalarIsFinite(SkScalar x) { return sk_float_isfinite(x); } + +static inline bool SkScalarsAreFinite(SkScalar a, SkScalar b) { + return sk_floats_are_finite(a, b); +} + +static inline bool SkScalarsAreFinite(const SkScalar array[], int count) { + return sk_floats_are_finite(array, count); +} + +/** Returns the fractional part of the scalar. */ +static inline SkScalar SkScalarFraction(SkScalar x) { + return x - SkScalarTruncToScalar(x); +} + +static inline SkScalar SkScalarSquare(SkScalar x) { return x * x; } + +#define SkScalarInvert(x) sk_ieee_float_divide_TODO_IS_DIVIDE_BY_ZERO_SAFE_HERE(SK_Scalar1, (x)) +#define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf) +#define SkScalarHalf(a) ((a) * SK_ScalarHalf) + +#define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180)) +#define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI)) + +static inline bool SkScalarIsInt(SkScalar x) { + return x == SkScalarFloorToScalar(x); +} + +/** + * Returns -1 || 0 || 1 depending on the sign of value: + * -1 if x < 0 + * 0 if x == 0 + * 1 if x > 0 + */ +static inline int SkScalarSignAsInt(SkScalar x) { + return x < 0 ? -1 : (x > 0); +} + +// Scalar result version of above +static inline SkScalar SkScalarSignAsScalar(SkScalar x) { + return x < 0 ? -SK_Scalar1 : ((x > 0) ? SK_Scalar1 : 0); +} + +#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12)) + +static inline bool SkScalarNearlyZero(SkScalar x, + SkScalar tolerance = SK_ScalarNearlyZero) { + SkASSERT(tolerance >= 0); + return SkScalarAbs(x) <= tolerance; +} + +static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y, + SkScalar tolerance = SK_ScalarNearlyZero) { + SkASSERT(tolerance >= 0); + return SkScalarAbs(x-y) <= tolerance; +} + +#define SK_ScalarSinCosNearlyZero (SK_Scalar1 / (1 << 16)) + +static inline float SkScalarSinSnapToZero(SkScalar radians) { + float v = SkScalarSin(radians); + return SkScalarNearlyZero(v, SK_ScalarSinCosNearlyZero) ? 0.0f : v; +} + +static inline float SkScalarCosSnapToZero(SkScalar radians) { + float v = SkScalarCos(radians); + return SkScalarNearlyZero(v, SK_ScalarSinCosNearlyZero) ? 0.0f : v; +} + +/** Linearly interpolate between A and B, based on t. + If t is 0, return A + If t is 1, return B + else interpolate. + t must be [0..SK_Scalar1] +*/ +static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) { + SkASSERT(t >= 0 && t <= SK_Scalar1); + return A + (B - A) * t; +} + +/** Interpolate along the function described by (keys[length], values[length]) + for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length] + clamp to the min or max value. This function assumes the number of pairs + (length) will be small and a linear search is used. + + Repeated keys are allowed for discontinuous functions (so long as keys is + monotonically increasing). If key is the value of a repeated scalar in + keys the first one will be used. +*/ +SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[], + const SkScalar values[], int length); + +/* + * Helper to compare an array of scalars. + */ +static inline bool SkScalarsEqual(const SkScalar a[], const SkScalar b[], int n) { + SkASSERT(n >= 0); + for (int i = 0; i < n; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSerialProcs.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSerialProcs.h new file mode 100644 index 00000000000000..a9a0386370cd93 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSerialProcs.h @@ -0,0 +1,81 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSerialProcs_DEFINED +#define SkSerialProcs_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +class SkData; +class SkImage; +class SkPicture; +class SkTypeface; + +/** + * A serial-proc is asked to serialize the specified object (e.g. picture or image). + * If a data object is returned, it will be used (even if it is zero-length). + * If null is returned, then Skia will take its default action. + * + * The default action for pictures is to use Skia's internal format. + * The default action for images is to encode either in its native format or PNG. + * The default action for typefaces is to use Skia's internal format. + */ + +using SkSerialPictureProc = sk_sp (*)(SkPicture*, void* ctx); +using SkSerialImageProc = sk_sp (*)(SkImage*, void* ctx); +using SkSerialTypefaceProc = sk_sp (*)(SkTypeface*, void* ctx); + +/** + * Called with the encoded form of a picture (previously written with a custom + * SkSerialPictureProc proc). Return a picture object, or nullptr indicating failure. + */ +using SkDeserialPictureProc = sk_sp (*)(const void* data, size_t length, void* ctx); + +/** + * Called with the encoded form of an image. The proc can return an image object, or if it + * returns nullptr, then Skia will take its default action to try to create an image from the data. + * + * This will also be used to decode the internal mipmap layers that are saved on some images. + * + * Note that unlike SkDeserialPictureProc and SkDeserialTypefaceProc, return nullptr from this + * does not indicate failure, but is a signal for Skia to take its default action. + */ +using SkDeserialImageProc = sk_sp (*)(const void* data, size_t length, void* ctx); + +/** + * Called with the encoded form of a typeface (previously written with a custom + * SkSerialTypefaceProc proc). Return a typeface object, or nullptr indicating failure. + */ +using SkDeserialTypefaceProc = sk_sp (*)(const void* data, size_t length, void* ctx); + +struct SK_API SkSerialProcs { + SkSerialPictureProc fPictureProc = nullptr; + void* fPictureCtx = nullptr; + + SkSerialImageProc fImageProc = nullptr; + void* fImageCtx = nullptr; + + SkSerialTypefaceProc fTypefaceProc = nullptr; + void* fTypefaceCtx = nullptr; +}; + +struct SK_API SkDeserialProcs { + SkDeserialPictureProc fPictureProc = nullptr; + void* fPictureCtx = nullptr; + + SkDeserialImageProc fImageProc = nullptr; + void* fImageCtx = nullptr; + + SkDeserialTypefaceProc fTypefaceProc = nullptr; + void* fTypefaceCtx = nullptr; +}; + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkShader.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkShader.h new file mode 100644 index 00000000000000..be42a87b9a9c60 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkShader.h @@ -0,0 +1,93 @@ +/* + * 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 SkShader_DEFINED +#define SkShader_DEFINED + +#include "include/core/SkBlendMode.h" +#include "include/core/SkColor.h" +#include "include/core/SkFlattenable.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkTileMode.h" + +class SkArenaAlloc; +class SkBitmap; +class SkBlender; +class SkColorFilter; +class SkColorSpace; +class SkImage; +class SkPath; +class SkPicture; +class SkRasterPipeline; +class GrFragmentProcessor; + +/** \class SkShader + * + * Shaders specify the source color(s) for what is being drawn. If a paint + * has no shader, then the paint's color is used. If the paint has a + * shader, then the shader's color(s) are use instead, but they are + * modulated by the paint's alpha. This makes it easy to create a shader + * once (e.g. bitmap tiling or gradient) and then change its transparency + * w/o having to modify the original shader... only the paint's alpha needs + * to be modified. + */ +class SK_API SkShader : public SkFlattenable { +public: + /** + * Returns true if the shader is guaranteed to produce only opaque + * colors, subject to the SkPaint using the shader to apply an opaque + * alpha value. Subclasses should override this to allow some + * optimizations. + */ + virtual bool isOpaque() const { return false; } + + /** + * Iff this shader is backed by a single SkImage, return its ptr (the caller must ref this + * if they want to keep it longer than the lifetime of the shader). If not, return nullptr. + */ + SkImage* isAImage(SkMatrix* localMatrix, SkTileMode xy[2]) const; + + bool isAImage() const { + return this->isAImage(nullptr, (SkTileMode*)nullptr) != nullptr; + } + + ////////////////////////////////////////////////////////////////////////// + // Methods to create combinations or variants of shaders + + /** + * Return a shader that will apply the specified localMatrix to this shader. + * The specified matrix will be applied before any matrix associated with this shader. + */ + sk_sp makeWithLocalMatrix(const SkMatrix&) const; + + /** + * Create a new shader that produces the same colors as invoking this shader and then applying + * the colorfilter. + */ + sk_sp makeWithColorFilter(sk_sp) const; + +private: + SkShader() = default; + friend class SkShaderBase; + + using INHERITED = SkFlattenable; +}; + +class SK_API SkShaders { +public: + static sk_sp Empty(); + static sk_sp Color(SkColor); + static sk_sp Color(const SkColor4f&, sk_sp); + static sk_sp Blend(SkBlendMode mode, sk_sp dst, sk_sp src); + static sk_sp Blend(sk_sp, sk_sp dst, sk_sp src); + static sk_sp CoordClamp(sk_sp, const SkRect& subset); +private: + SkShaders() = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSize.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSize.h new file mode 100644 index 00000000000000..867f4eeb97b909 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSize.h @@ -0,0 +1,92 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSize_DEFINED +#define SkSize_DEFINED + +#include "include/core/SkScalar.h" + +#include + +struct SkISize { + int32_t fWidth; + int32_t fHeight; + + static constexpr SkISize Make(int32_t w, int32_t h) { return {w, h}; } + + static constexpr SkISize MakeEmpty() { return {0, 0}; } + + void set(int32_t w, int32_t h) { *this = SkISize{w, h}; } + + /** Returns true iff fWidth == 0 && fHeight == 0 + */ + bool isZero() const { return 0 == fWidth && 0 == fHeight; } + + /** Returns true if either width or height are <= 0 */ + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } + + /** Set the width and height to 0 */ + void setEmpty() { fWidth = fHeight = 0; } + + constexpr int32_t width() const { return fWidth; } + constexpr int32_t height() const { return fHeight; } + + constexpr int64_t area() const { return fWidth * fHeight; } + + bool equals(int32_t w, int32_t h) const { return fWidth == w && fHeight == h; } +}; + +static inline bool operator==(const SkISize& a, const SkISize& b) { + return a.fWidth == b.fWidth && a.fHeight == b.fHeight; +} + +static inline bool operator!=(const SkISize& a, const SkISize& b) { return !(a == b); } + +/////////////////////////////////////////////////////////////////////////////// + +struct SkSize { + SkScalar fWidth; + SkScalar fHeight; + + static SkSize Make(SkScalar w, SkScalar h) { return {w, h}; } + + static SkSize Make(const SkISize& src) { + return {SkIntToScalar(src.width()), SkIntToScalar(src.height())}; + } + + static SkSize MakeEmpty() { return {0, 0}; } + + void set(SkScalar w, SkScalar h) { *this = SkSize{w, h}; } + + /** Returns true iff fWidth == 0 && fHeight == 0 + */ + bool isZero() const { return 0 == fWidth && 0 == fHeight; } + + /** Returns true if either width or height are <= 0 */ + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } + + /** Set the width and height to 0 */ + void setEmpty() { *this = SkSize{0, 0}; } + + SkScalar width() const { return fWidth; } + SkScalar height() const { return fHeight; } + + bool equals(SkScalar w, SkScalar h) const { return fWidth == w && fHeight == h; } + + SkISize toRound() const { return {SkScalarRoundToInt(fWidth), SkScalarRoundToInt(fHeight)}; } + + SkISize toCeil() const { return {SkScalarCeilToInt(fWidth), SkScalarCeilToInt(fHeight)}; } + + SkISize toFloor() const { return {SkScalarFloorToInt(fWidth), SkScalarFloorToInt(fHeight)}; } +}; + +static inline bool operator==(const SkSize& a, const SkSize& b) { + return a.fWidth == b.fWidth && a.fHeight == b.fHeight; +} + +static inline bool operator!=(const SkSize& a, const SkSize& b) { return !(a == b); } +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSpan.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSpan.h new file mode 100644 index 00000000000000..37cac632b1e8db --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSpan.h @@ -0,0 +1,13 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// We want SkSpan to be a public API, but it is also fundamental to many of our internal types. +// Thus, we have a public file that clients can include. This file defers to the private copy +// so we do not have a dependency cycle from our "base" files to our "core" files. + +#include "include/private/base/SkSpan_impl.h" // IWYU pragma: export + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkStream.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkStream.h new file mode 100644 index 00000000000000..c582c80a0528c3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkStream.h @@ -0,0 +1,523 @@ +/* + * 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 SkStream_DEFINED +#define SkStream_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include +#include +class SkStreamAsset; + +/** + * SkStream -- abstraction for a source of bytes. Subclasses can be backed by + * memory, or a file, or something else. + * + * NOTE: + * + * Classic "streams" APIs are sort of async, in that on a request for N + * bytes, they may return fewer than N bytes on a given call, in which case + * the caller can "try again" to get more bytes, eventually (modulo an error) + * receiving their total N bytes. + * + * Skia streams behave differently. They are effectively synchronous, and will + * always return all N bytes of the request if possible. If they return fewer + * (the read() call returns the number of bytes read) then that means there is + * no more data (at EOF or hit an error). The caller should *not* call again + * in hopes of fulfilling more of the request. + */ +class SK_API SkStream { +public: + virtual ~SkStream() {} + SkStream() {} + + /** + * Attempts to open the specified file as a stream, returns nullptr on failure. + */ + static std::unique_ptr MakeFromFile(const char path[]); + + /** Reads or skips size number of bytes. + * If buffer == NULL, skip size bytes, return how many were skipped. + * If buffer != NULL, copy size bytes into buffer, return how many were copied. + * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer + * @param size the number of bytes to skip or copy + * @return the number of bytes actually read. + */ + virtual size_t read(void* buffer, size_t size) = 0; + + /** Skip size number of bytes. + * @return the actual number bytes that could be skipped. + */ + size_t skip(size_t size) { + return this->read(nullptr, size); + } + + /** + * Attempt to peek at size bytes. + * If this stream supports peeking, copy min(size, peekable bytes) into + * buffer, and return the number of bytes copied. + * If the stream does not support peeking, or cannot peek any bytes, + * return 0 and leave buffer unchanged. + * The stream is guaranteed to be in the same visible state after this + * call, regardless of success or failure. + * @param buffer Must not be NULL, and must be at least size bytes. Destination + * to copy bytes. + * @param size Number of bytes to copy. + * @return The number of bytes peeked/copied. + */ + virtual size_t peek(void* /*buffer*/, size_t /*size*/) const { return 0; } + + /** Returns true when all the bytes in the stream have been read. + * This may return true early (when there are no more bytes to be read) + * or late (after the first unsuccessful read). + */ + virtual bool isAtEnd() const = 0; + + bool SK_WARN_UNUSED_RESULT readS8(int8_t*); + bool SK_WARN_UNUSED_RESULT readS16(int16_t*); + bool SK_WARN_UNUSED_RESULT readS32(int32_t*); + + bool SK_WARN_UNUSED_RESULT readU8(uint8_t* i) { return this->readS8((int8_t*)i); } + bool SK_WARN_UNUSED_RESULT readU16(uint16_t* i) { return this->readS16((int16_t*)i); } + bool SK_WARN_UNUSED_RESULT readU32(uint32_t* i) { return this->readS32((int32_t*)i); } + + bool SK_WARN_UNUSED_RESULT readBool(bool* b) { + uint8_t i; + if (!this->readU8(&i)) { return false; } + *b = (i != 0); + return true; + } + bool SK_WARN_UNUSED_RESULT readScalar(SkScalar*); + bool SK_WARN_UNUSED_RESULT readPackedUInt(size_t*); + +//SkStreamRewindable + /** Rewinds to the beginning of the stream. Returns true if the stream is known + * to be at the beginning after this call returns. + */ + virtual bool rewind() { return false; } + + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned at the beginning of its data. + */ + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned the same as this stream. + */ + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + +//SkStreamSeekable + /** Returns true if this stream can report its current position. */ + virtual bool hasPosition() const { return false; } + /** Returns the current position in the stream. If this cannot be done, returns 0. */ + virtual size_t getPosition() const { return 0; } + + /** Seeks to an absolute position in the stream. If this cannot be done, returns false. + * If an attempt is made to seek past the end of the stream, the position will be set + * to the end of the stream. + */ + virtual bool seek(size_t /*position*/) { return false; } + + /** Seeks to an relative offset in the stream. If this cannot be done, returns false. + * If an attempt is made to move to a position outside the stream, the position will be set + * to the closest point within the stream (beginning or end). + */ + virtual bool move(long /*offset*/) { return false; } + +//SkStreamAsset + /** Returns true if this stream can report its total length. */ + virtual bool hasLength() const { return false; } + /** Returns the total length of the stream. If this cannot be done, returns 0. */ + virtual size_t getLength() const { return 0; } + +//SkStreamMemory + /** Returns the starting address for the data. If this cannot be done, returns NULL. */ + //TODO: replace with virtual const SkData* getData() + virtual const void* getMemoryBase() { return nullptr; } + +private: + virtual SkStream* onDuplicate() const { return nullptr; } + virtual SkStream* onFork() const { return nullptr; } + + SkStream(SkStream&&) = delete; + SkStream(const SkStream&) = delete; + SkStream& operator=(SkStream&&) = delete; + SkStream& operator=(const SkStream&) = delete; +}; + +/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */ +class SK_API SkStreamRewindable : public SkStream { +public: + bool rewind() override = 0; + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } +private: + SkStreamRewindable* onDuplicate() const override = 0; +}; + +/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */ +class SK_API SkStreamSeekable : public SkStreamRewindable { +public: + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + bool hasPosition() const override { return true; } + size_t getPosition() const override = 0; + bool seek(size_t position) override = 0; + bool move(long offset) override = 0; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } +private: + SkStreamSeekable* onDuplicate() const override = 0; + SkStreamSeekable* onFork() const override = 0; +}; + +/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */ +class SK_API SkStreamAsset : public SkStreamSeekable { +public: + bool hasLength() const override { return true; } + size_t getLength() const override = 0; + + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } +private: + SkStreamAsset* onDuplicate() const override = 0; + SkStreamAsset* onFork() const override = 0; +}; + +/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */ +class SK_API SkStreamMemory : public SkStreamAsset { +public: + const void* getMemoryBase() override = 0; + + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } +private: + SkStreamMemory* onDuplicate() const override = 0; + SkStreamMemory* onFork() const override = 0; +}; + +class SK_API SkWStream { +public: + virtual ~SkWStream(); + SkWStream() {} + + /** Called to write bytes to a SkWStream. Returns true on success + @param buffer the address of at least size bytes to be written to the stream + @param size The number of bytes in buffer to write to the stream + @return true on success + */ + virtual bool write(const void* buffer, size_t size) = 0; + virtual void flush(); + + virtual size_t bytesWritten() const = 0; + + // helpers + + bool write8(U8CPU value) { + uint8_t v = SkToU8(value); + return this->write(&v, 1); + } + bool write16(U16CPU value) { + uint16_t v = SkToU16(value); + return this->write(&v, 2); + } + bool write32(uint32_t v) { + return this->write(&v, 4); + } + + bool writeText(const char text[]) { + SkASSERT(text); + return this->write(text, std::strlen(text)); + } + + bool newline() { return this->write("\n", std::strlen("\n")); } + + bool writeDecAsText(int32_t); + bool writeBigDecAsText(int64_t, int minDigits = 0); + bool writeHexAsText(uint32_t, int minDigits = 0); + bool writeScalarAsText(SkScalar); + + bool writeBool(bool v) { return this->write8(v); } + bool writeScalar(SkScalar); + bool writePackedUInt(size_t); + + bool writeStream(SkStream* input, size_t length); + + /** + * This returns the number of bytes in the stream required to store + * 'value'. + */ + static int SizeOfPackedUInt(size_t value); + +private: + SkWStream(const SkWStream&) = delete; + SkWStream& operator=(const SkWStream&) = delete; +}; + +class SK_API SkNullWStream : public SkWStream { +public: + SkNullWStream() : fBytesWritten(0) {} + + bool write(const void* , size_t n) override { fBytesWritten += n; return true; } + void flush() override {} + size_t bytesWritten() const override { return fBytesWritten; } + +private: + size_t fBytesWritten; +}; + +//////////////////////////////////////////////////////////////////////////////////////// + +/** A stream that wraps a C FILE* file stream. */ +class SK_API SkFILEStream : public SkStreamAsset { +public: + /** Initialize the stream by calling sk_fopen on the specified path. + * This internal stream will be closed in the destructor. + */ + explicit SkFILEStream(const char path[] = nullptr); + + /** Initialize the stream with an existing C FILE stream. + * The current position of the C FILE stream will be considered the + * beginning of the SkFILEStream and the current seek end of the FILE will be the end. + * The C FILE stream will be closed in the destructor. + */ + explicit SkFILEStream(FILE* file); + + /** Initialize the stream with an existing C FILE stream. + * The current position of the C FILE stream will be considered the + * beginning of the SkFILEStream and size bytes later will be the end. + * The C FILE stream will be closed in the destructor. + */ + explicit SkFILEStream(FILE* file, size_t size); + + ~SkFILEStream() override; + + static std::unique_ptr Make(const char path[]) { + std::unique_ptr stream(new SkFILEStream(path)); + return stream->isValid() ? std::move(stream) : nullptr; + } + + /** Returns true if the current path could be opened. */ + bool isValid() const { return fFILE != nullptr; } + + /** Close this SkFILEStream. */ + void close(); + + size_t read(void* buffer, size_t size) override; + bool isAtEnd() const override; + + bool rewind() override; + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + size_t getPosition() const override; + bool seek(size_t position) override; + bool move(long offset) override; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + + size_t getLength() const override; + +private: + explicit SkFILEStream(FILE*, size_t size, size_t start); + explicit SkFILEStream(std::shared_ptr, size_t end, size_t start); + explicit SkFILEStream(std::shared_ptr, size_t end, size_t start, size_t current); + + SkStreamAsset* onDuplicate() const override; + SkStreamAsset* onFork() const override; + + std::shared_ptr fFILE; + // My own council will I keep on sizes and offsets. + // These are seek positions in the underling FILE, not offsets into the stream. + size_t fEnd; + size_t fStart; + size_t fCurrent; + + using INHERITED = SkStreamAsset; +}; + +class SK_API SkMemoryStream : public SkStreamMemory { +public: + SkMemoryStream(); + + /** We allocate (and free) the memory. Write to it via getMemoryBase() */ + SkMemoryStream(size_t length); + + /** If copyData is true, the stream makes a private copy of the data. */ + SkMemoryStream(const void* data, size_t length, bool copyData = false); + + /** Creates the stream to read from the specified data */ + SkMemoryStream(sk_sp data); + + /** Returns a stream with a copy of the input data. */ + static std::unique_ptr MakeCopy(const void* data, size_t length); + + /** Returns a stream with a bare pointer reference to the input data. */ + static std::unique_ptr MakeDirect(const void* data, size_t length); + + /** Returns a stream with a shared reference to the input data. */ + static std::unique_ptr Make(sk_sp data); + + /** Resets the stream to the specified data and length, + just like the constructor. + if copyData is true, the stream makes a private copy of the data + */ + virtual void setMemory(const void* data, size_t length, + bool copyData = false); + /** Replace any memory buffer with the specified buffer. The caller + must have allocated data with sk_malloc or sk_realloc, since it + will be freed with sk_free. + */ + void setMemoryOwned(const void* data, size_t length); + + sk_sp asData() const { return fData; } + void setData(sk_sp data); + + void skipToAlign4(); + const void* getAtPos(); + + size_t read(void* buffer, size_t size) override; + bool isAtEnd() const override; + + size_t peek(void* buffer, size_t size) const override; + + bool rewind() override; + + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + size_t getPosition() const override; + bool seek(size_t position) override; + bool move(long offset) override; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + + size_t getLength() const override; + + const void* getMemoryBase() override; + +private: + SkMemoryStream* onDuplicate() const override; + SkMemoryStream* onFork() const override; + + sk_sp fData; + size_t fOffset; + + using INHERITED = SkStreamMemory; +}; + +///////////////////////////////////////////////////////////////////////////////////////////// + +class SK_API SkFILEWStream : public SkWStream { +public: + SkFILEWStream(const char path[]); + ~SkFILEWStream() override; + + /** Returns true if the current path could be opened. + */ + bool isValid() const { return fFILE != nullptr; } + + bool write(const void* buffer, size_t size) override; + void flush() override; + void fsync(); + size_t bytesWritten() const override; + +private: + FILE* fFILE; + + using INHERITED = SkWStream; +}; + +class SK_API SkDynamicMemoryWStream : public SkWStream { +public: + SkDynamicMemoryWStream() = default; + SkDynamicMemoryWStream(SkDynamicMemoryWStream&&); + SkDynamicMemoryWStream& operator=(SkDynamicMemoryWStream&&); + ~SkDynamicMemoryWStream() override; + + bool write(const void* buffer, size_t size) override; + size_t bytesWritten() const override; + + bool read(void* buffer, size_t offset, size_t size); + + /** More efficient version of read(dst, 0, bytesWritten()). */ + void copyTo(void* dst) const; + bool writeToStream(SkWStream* dst) const; + + /** Equivalent to copyTo() followed by reset(), but may save memory use. */ + void copyToAndReset(void* dst); + + /** Equivalent to writeToStream() followed by reset(), but may save memory use. */ + bool writeToAndReset(SkWStream* dst); + + /** Equivalent to writeToStream() followed by reset(), but may save memory use. + When the dst is also a SkDynamicMemoryWStream, the implementation is constant time. */ + bool writeToAndReset(SkDynamicMemoryWStream* dst); + + /** Prepend this stream to dst, resetting this. */ + void prependToAndReset(SkDynamicMemoryWStream* dst); + + /** Return the contents as SkData, and then reset the stream. */ + sk_sp detachAsData(); + + /** Reset, returning a reader stream with the current content. */ + std::unique_ptr detachAsStream(); + + /** Reset the stream to its original, empty, state. */ + void reset(); + void padToAlign4(); +private: + struct Block; + Block* fHead = nullptr; + Block* fTail = nullptr; + size_t fBytesWrittenBeforeTail = 0; + +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif + + // For access to the Block type. + friend class SkBlockMemoryStream; + friend class SkBlockMemoryRefCnt; + + using INHERITED = SkWStream; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkString.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkString.h new file mode 100644 index 00000000000000..1b27fbf44b07ce --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkString.h @@ -0,0 +1,291 @@ +/* + * 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 SkString_DEFINED +#define SkString_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" + +#include +#include +#include +#include +#include +#include +#include + +/* Some helper functions for C strings */ +static inline bool SkStrStartsWith(const char string[], const char prefixStr[]) { + SkASSERT(string); + SkASSERT(prefixStr); + return !strncmp(string, prefixStr, strlen(prefixStr)); +} +static inline bool SkStrStartsWith(const char string[], const char prefixChar) { + SkASSERT(string); + return (prefixChar == *string); +} + +bool SkStrEndsWith(const char string[], const char suffixStr[]); +bool SkStrEndsWith(const char string[], const char suffixChar); + +int SkStrStartsWithOneOf(const char string[], const char prefixes[]); + +static inline int SkStrFind(const char string[], const char substring[]) { + const char *first = strstr(string, substring); + if (nullptr == first) return -1; + return SkToInt(first - &string[0]); +} + +static inline int SkStrFindLastOf(const char string[], const char subchar) { + const char* last = strrchr(string, subchar); + if (nullptr == last) return -1; + return SkToInt(last - &string[0]); +} + +static inline bool SkStrContains(const char string[], const char substring[]) { + SkASSERT(string); + SkASSERT(substring); + return (-1 != SkStrFind(string, substring)); +} +static inline bool SkStrContains(const char string[], const char subchar) { + SkASSERT(string); + char tmp[2]; + tmp[0] = subchar; + tmp[1] = '\0'; + return (-1 != SkStrFind(string, tmp)); +} + +/* + * The SkStrAppend... methods will write into the provided buffer, assuming it is large enough. + * Each method has an associated const (e.g. kSkStrAppendU32_MaxSize) which will be the largest + * value needed for that method's buffer. + * + * char storage[kSkStrAppendU32_MaxSize]; + * SkStrAppendU32(storage, value); + * + * Note : none of the SkStrAppend... methods write a terminating 0 to their buffers. Instead, + * the methods return the ptr to the end of the written part of the buffer. This can be used + * to compute the length, and/or know where to write a 0 if that is desired. + * + * char storage[kSkStrAppendU32_MaxSize + 1]; + * char* stop = SkStrAppendU32(storage, value); + * size_t len = stop - storage; + * *stop = 0; // valid, since storage was 1 byte larger than the max. + */ + +static constexpr int kSkStrAppendU32_MaxSize = 10; +char* SkStrAppendU32(char buffer[], uint32_t); +static constexpr int kSkStrAppendU64_MaxSize = 20; +char* SkStrAppendU64(char buffer[], uint64_t, int minDigits); + +static constexpr int kSkStrAppendS32_MaxSize = kSkStrAppendU32_MaxSize + 1; +char* SkStrAppendS32(char buffer[], int32_t); +static constexpr int kSkStrAppendS64_MaxSize = kSkStrAppendU64_MaxSize + 1; +char* SkStrAppendS64(char buffer[], int64_t, int minDigits); + +/** + * Floats have at most 8 significant digits, so we limit our %g to that. + * However, the total string could be 15 characters: -1.2345678e-005 + * + * In theory we should only expect up to 2 digits for the exponent, but on + * some platforms we have seen 3 (as in the example above). + */ +static constexpr int kSkStrAppendScalar_MaxSize = 15; + +/** + * Write the scalar in decimal format into buffer, and return a pointer to + * the next char after the last one written. Note: a terminating 0 is not + * written into buffer, which must be at least kSkStrAppendScalar_MaxSize. + * Thus if the caller wants to add a 0 at the end, buffer must be at least + * kSkStrAppendScalar_MaxSize + 1 bytes large. + */ +char* SkStrAppendScalar(char buffer[], SkScalar); + +/** \class SkString + + Light weight class for managing strings. Uses reference + counting to make string assignments and copies very fast + with no extra RAM cost. Assumes UTF8 encoding. +*/ +class SK_API SkString { +public: + SkString(); + explicit SkString(size_t len); + explicit SkString(const char text[]); + SkString(const char text[], size_t len); + SkString(const SkString&); + SkString(SkString&&); + explicit SkString(const std::string&); + explicit SkString(std::string_view); + ~SkString(); + + bool isEmpty() const { return 0 == fRec->fLength; } + size_t size() const { return (size_t) fRec->fLength; } + const char* data() const { return fRec->data(); } + const char* c_str() const { return fRec->data(); } + char operator[](size_t n) const { return this->c_str()[n]; } + + bool equals(const SkString&) const; + bool equals(const char text[]) const; + bool equals(const char text[], size_t len) const; + + bool startsWith(const char prefixStr[]) const { + return SkStrStartsWith(fRec->data(), prefixStr); + } + bool startsWith(const char prefixChar) const { + return SkStrStartsWith(fRec->data(), prefixChar); + } + bool endsWith(const char suffixStr[]) const { + return SkStrEndsWith(fRec->data(), suffixStr); + } + bool endsWith(const char suffixChar) const { + return SkStrEndsWith(fRec->data(), suffixChar); + } + bool contains(const char substring[]) const { + return SkStrContains(fRec->data(), substring); + } + bool contains(const char subchar) const { + return SkStrContains(fRec->data(), subchar); + } + int find(const char substring[]) const { + return SkStrFind(fRec->data(), substring); + } + int findLastOf(const char subchar) const { + return SkStrFindLastOf(fRec->data(), subchar); + } + + friend bool operator==(const SkString& a, const SkString& b) { + return a.equals(b); + } + friend bool operator!=(const SkString& a, const SkString& b) { + return !a.equals(b); + } + + // these methods edit the string + + SkString& operator=(const SkString&); + SkString& operator=(SkString&&); + SkString& operator=(const char text[]); + + char* data(); + char& operator[](size_t n) { return this->data()[n]; } + + void reset(); + /** String contents are preserved on resize. (For destructive resize, `set(nullptr, length)`.) + * `resize` automatically reserves an extra byte at the end of the buffer for a null terminator. + */ + void resize(size_t len); + void set(const SkString& src) { *this = src; } + void set(const char text[]); + void set(const char text[], size_t len); + void set(std::string_view str) { this->set(str.data(), str.size()); } + + void insert(size_t offset, const char text[]); + void insert(size_t offset, const char text[], size_t len); + void insert(size_t offset, const SkString& str) { this->insert(offset, str.c_str(), str.size()); } + void insert(size_t offset, std::string_view str) { this->insert(offset, str.data(), str.size()); } + void insertUnichar(size_t offset, SkUnichar); + void insertS32(size_t offset, int32_t value); + void insertS64(size_t offset, int64_t value, int minDigits = 0); + void insertU32(size_t offset, uint32_t value); + void insertU64(size_t offset, uint64_t value, int minDigits = 0); + void insertHex(size_t offset, uint32_t value, int minDigits = 0); + void insertScalar(size_t offset, SkScalar); + + void append(const char text[]) { this->insert((size_t)-1, text); } + void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); } + void append(const SkString& str) { this->insert((size_t)-1, str.c_str(), str.size()); } + void append(std::string_view str) { this->insert((size_t)-1, str.data(), str.size()); } + void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); } + void appendS32(int32_t value) { this->insertS32((size_t)-1, value); } + void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); } + void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); } + void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); } + void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); } + void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void prepend(const char text[]) { this->insert(0, text); } + void prepend(const char text[], size_t len) { this->insert(0, text, len); } + void prepend(const SkString& str) { this->insert(0, str.c_str(), str.size()); } + void prepend(std::string_view str) { this->insert(0, str.data(), str.size()); } + void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); } + void prependS32(int32_t value) { this->insertS32(0, value); } + void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); } + void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); } + void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void printVAList(const char format[], va_list) SK_PRINTF_LIKE(2, 0); + void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void appendVAList(const char format[], va_list) SK_PRINTF_LIKE(2, 0); + void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void prependVAList(const char format[], va_list) SK_PRINTF_LIKE(2, 0); + + void remove(size_t offset, size_t length); + + SkString& operator+=(const SkString& s) { this->append(s); return *this; } + SkString& operator+=(const char text[]) { this->append(text); return *this; } + SkString& operator+=(const char c) { this->append(&c, 1); return *this; } + + /** + * Swap contents between this and other. This function is guaranteed + * to never fail or throw. + */ + void swap(SkString& other); + + using sk_is_trivially_relocatable = std::true_type; + +private: + struct Rec { + public: + constexpr Rec(uint32_t len, int32_t refCnt) : fLength(len), fRefCnt(refCnt) {} + static sk_sp Make(const char text[], size_t len); + char* data() { return fBeginningOfData; } + const char* data() const { return fBeginningOfData; } + void ref() const; + void unref() const; + bool unique() const; +#ifdef SK_DEBUG + int32_t getRefCnt() const; +#endif + uint32_t fLength; // logically size_t, but we want it to stay 32 bits + + private: + mutable std::atomic fRefCnt; + char fBeginningOfData[1] = {'\0'}; + + // Ensure the unsized delete is called. + void operator delete(void* p) { ::operator delete(p); } + }; + sk_sp fRec; + + static_assert(::sk_is_trivially_relocatable::value); + +#ifdef SK_DEBUG + const SkString& validate() const; +#else + const SkString& validate() const { return *this; } +#endif + + static const Rec gEmptyRec; +}; + +/// Creates a new string and writes into it using a printf()-style format. +SkString SkStringPrintf(const char* format, ...) SK_PRINTF_LIKE(1, 2); +/// This makes it easier to write a caller as a VAR_ARGS function where the format string is +/// optional. +static inline SkString SkStringPrintf() { return SkString(); } + +static inline void swap(SkString& a, SkString& b) { + a.swap(b); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkStrokeRec.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkStrokeRec.h new file mode 100644 index 00000000000000..1257d04a844b79 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkStrokeRec.h @@ -0,0 +1,154 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStrokeRec_DEFINED +#define SkStrokeRec_DEFINED + +#include "include/core/SkPaint.h" +#include "include/private/base/SkMacros.h" + +class SkPath; + +SK_BEGIN_REQUIRE_DENSE +class SK_API SkStrokeRec { +public: + enum InitStyle { + kHairline_InitStyle, + kFill_InitStyle + }; + SkStrokeRec(InitStyle style); + SkStrokeRec(const SkPaint&, SkPaint::Style, SkScalar resScale = 1); + explicit SkStrokeRec(const SkPaint&, SkScalar resScale = 1); + + enum Style { + kHairline_Style, + kFill_Style, + kStroke_Style, + kStrokeAndFill_Style + }; + + static constexpr int kStyleCount = kStrokeAndFill_Style + 1; + + Style getStyle() const; + SkScalar getWidth() const { return fWidth; } + SkScalar getMiter() const { return fMiterLimit; } + SkPaint::Cap getCap() const { return (SkPaint::Cap)fCap; } + SkPaint::Join getJoin() const { return (SkPaint::Join)fJoin; } + + bool isHairlineStyle() const { + return kHairline_Style == this->getStyle(); + } + + bool isFillStyle() const { + return kFill_Style == this->getStyle(); + } + + void setFillStyle(); + void setHairlineStyle(); + /** + * Specify the strokewidth, and optionally if you want stroke + fill. + * Note, if width==0, then this request is taken to mean: + * strokeAndFill==true -> new style will be Fill + * strokeAndFill==false -> new style will be Hairline + */ + void setStrokeStyle(SkScalar width, bool strokeAndFill = false); + + void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) { + fCap = cap; + fJoin = join; + fMiterLimit = miterLimit; + } + + SkScalar getResScale() const { + return fResScale; + } + + void setResScale(SkScalar rs) { + SkASSERT(rs > 0 && SkScalarIsFinite(rs)); + fResScale = rs; + } + + /** + * Returns true if this specifes any thick stroking, i.e. applyToPath() + * will return true. + */ + bool needToApply() const { + Style style = this->getStyle(); + return (kStroke_Style == style) || (kStrokeAndFill_Style == style); + } + + /** + * Apply these stroke parameters to the src path, returning the result + * in dst. + * + * If there was no change (i.e. style == hairline or fill) this returns + * false and dst is unchanged. Otherwise returns true and the result is + * stored in dst. + * + * src and dst may be the same path. + */ + bool applyToPath(SkPath* dst, const SkPath& src) const; + + /** + * Apply these stroke parameters to a paint. + */ + void applyToPaint(SkPaint* paint) const; + + /** + * Gives a conservative value for the outset that should applied to a + * geometries bounds to account for any inflation due to applying this + * strokeRec to the geometry. + */ + SkScalar getInflationRadius() const; + + /** + * Equivalent to: + * SkStrokeRec rec(paint, style); + * rec.getInflationRadius(); + * This does not account for other effects on the paint (i.e. path + * effect). + */ + static SkScalar GetInflationRadius(const SkPaint&, SkPaint::Style); + + static SkScalar GetInflationRadius(SkPaint::Join, SkScalar miterLimit, SkPaint::Cap, + SkScalar strokeWidth); + + /** + * Compare if two SkStrokeRecs have an equal effect on a path. + * Equal SkStrokeRecs produce equal paths. Equality of produced + * paths does not take the ResScale parameter into account. + */ + bool hasEqualEffect(const SkStrokeRec& other) const { + if (!this->needToApply()) { + return this->getStyle() == other.getStyle(); + } + return fWidth == other.fWidth && + (fJoin != SkPaint::kMiter_Join || fMiterLimit == other.fMiterLimit) && + fCap == other.fCap && + fJoin == other.fJoin && + fStrokeAndFill == other.fStrokeAndFill; + } + +private: + void init(const SkPaint&, SkPaint::Style, SkScalar resScale); + + SkScalar fResScale; + SkScalar fWidth; + SkScalar fMiterLimit; + // The following three members are packed together into a single u32. + // This is to avoid unnecessary padding and ensure binary equality for + // hashing (because the padded areas might contain garbage values). + // + // fCap and fJoin are larger than needed to avoid having to initialize + // any pad values + uint32_t fCap : 16; // SkPaint::Cap + uint32_t fJoin : 15; // SkPaint::Join + uint32_t fStrokeAndFill : 1; // bool +}; +SK_END_REQUIRE_DENSE + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurface.h new file mode 100644 index 00000000000000..3673d172b6d025 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurface.h @@ -0,0 +1,1199 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSurface_DEFINED +#define SkSurface_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" + +#if defined(SK_GANESH) +#include "include/gpu/GrTypes.h" +#else +enum GrSurfaceOrigin: int; +#endif + +#if defined(SK_GRAPHITE) +#include "include/gpu/GpuTypes.h" +namespace skgpu::graphite { +class BackendTexture; +} +#endif + +#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 +#include +class GrDirectContext; +#endif + +#if defined(SK_GANESH) && defined(SK_METAL) +#include "include/gpu/mtl/GrMtlTypes.h" +#endif + +#include +#include +#include + +class GrBackendRenderTarget; +class GrBackendSemaphore; +class GrBackendTexture; +class GrRecordingContext; +class SkBitmap; +class SkCanvas; +class SkCapabilities; +class SkColorSpace; +class SkDeferredDisplayList; +class SkPaint; +class SkSurfaceCharacterization; +enum SkColorType : int; +struct SkIRect; +struct SkISize; + +namespace skgpu { +class MutableTextureState; +enum class Budgeted : bool; +} + +namespace skgpu::graphite { +class Recorder; +} + +/** \class SkSurface + SkSurface is responsible for managing the pixels that a canvas draws into. The pixels can be + allocated either in CPU memory (a raster surface) or on the GPU (a GrRenderTarget surface). + SkSurface takes care of allocating a SkCanvas that will draw into the surface. Call + surface->getCanvas() to use that canvas (but don't delete it, it is owned by the surface). + SkSurface always has non-zero dimensions. If there is a request for a new surface, and either + of the requested dimensions are zero, then nullptr will be returned. +*/ +class SK_API SkSurface : public SkRefCnt { +public: + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is large enough to contain info width pixels of SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + Pixels are not initialized. + To access pixels after drawing, peekPixels() or readPixels(). + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRasterDirect(const SkImageInfo& imageInfo, void* pixels, + size_t rowBytes, + const SkSurfaceProps* surfaceProps = nullptr); + + static sk_sp MakeRasterDirect(const SkPixmap& pm, + const SkSurfaceProps* props = nullptr) { + return MakeRasterDirect(pm.info(), pm.writable_addr(), pm.rowBytes(), props); + } + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + releaseProc is called with pixels and context when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is large enough to contain info width pixels of SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + Pixels are not initialized. + To access pixels after drawing, call flush() or peekPixels(). + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next + @param releaseProc called when SkSurface is deleted; may be nullptr + @param context passed to releaseProc; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRasterDirectReleaseProc(const SkImageInfo& imageInfo, void* pixels, + size_t rowBytes, + void (*releaseProc)(void* pixels, void* context), + void* context, const SkSurfaceProps* surfaceProps = nullptr); + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + Allocates and zeroes pixel memory. Pixel memory size is imageInfo.height() times + rowBytes, or times imageInfo.minRowBytes() if rowBytes is zero. + Pixel memory is deleted when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + rowBytes is large enough to contain info width pixels of SkColorType, or is zero. + + If rowBytes is zero, a suitable value will be chosen internally. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param rowBytes interval from one SkSurface row to the next; may be zero + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRaster(const SkImageInfo& imageInfo, size_t rowBytes, + const SkSurfaceProps* surfaceProps); + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + Allocates and zeroes pixel memory. Pixel memory size is imageInfo.height() times + imageInfo.minRowBytes(). + Pixel memory is deleted when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRaster(const SkImageInfo& imageInfo, + const SkSurfaceProps* props = nullptr) { + return MakeRaster(imageInfo, 0, props); + } + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + Allocates and zeroes pixel memory. Pixel memory size is height times width times + four. Pixel memory is deleted when SkSurface is deleted. + + Internally, sets SkImageInfo to width, height, native color type, and + kPremul_SkAlphaType. + + SkSurface is returned if width and height are greater than zero. + + Use to create SkSurface that matches SkPMColor, the native pixel arrangement on + the platform. SkSurface drawn to output device skips converting its pixel format. + + @param width pixel column count; must be greater than zero + @param height pixel row count; must be greater than zero + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRasterN32Premul(int width, int height, + const SkSurfaceProps* surfaceProps = nullptr); + + /** Caller data passed to RenderTarget/TextureReleaseProc; may be nullptr. */ + typedef void* ReleaseContext; + + /** User function called when supplied render target may be deleted. */ + typedef void (*RenderTargetReleaseProc)(ReleaseContext releaseContext); + + /** User function called when supplied texture may be deleted. */ + typedef void (*TextureReleaseProc)(ReleaseContext releaseContext); + + /** Wraps a GPU-backed texture into SkSurface. Caller must ensure the texture is + valid for the lifetime of returned SkSurface. If sampleCnt greater than zero, + creates an intermediate MSAA SkSurface which is used for drawing backendTexture. + + SkSurface is returned if all parameters are valid. backendTexture is valid if + its pixel configuration agrees with colorSpace and context; for instance, if + backendTexture has an sRGB configuration, then context must support sRGB, + and colorSpace must be present. Further, backendTexture width and height must + not exceed context capabilities, and the context must be able to support + back-end textures. + + Upon success textureReleaseProc is called when it is safe to delete the texture in the + backend API (accounting only for use of the texture by this surface). If SkSurface creation + fails textureReleaseProc is called before this function returns. + + If defined(SK_GANESH) is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param backendTexture texture residing on GPU + @param sampleCnt samples per pixel, or 0 to disable full scene anti-aliasing + @param colorSpace range of colors; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @param textureReleaseProc function called when texture can be released + @param releaseContext state passed to textureReleaseProc + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeFromBackendTexture(GrRecordingContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, int sampleCnt, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps, + TextureReleaseProc textureReleaseProc = nullptr, + ReleaseContext releaseContext = nullptr); + + /** Wraps a GPU-backed buffer into SkSurface. Caller must ensure backendRenderTarget + is valid for the lifetime of returned SkSurface. + + SkSurface is returned if all parameters are valid. backendRenderTarget is valid if + its pixel configuration agrees with colorSpace and context; for instance, if + backendRenderTarget has an sRGB configuration, then context must support sRGB, + and colorSpace must be present. Further, backendRenderTarget width and height must + not exceed context capabilities, and the context must be able to support + back-end render targets. + + Upon success releaseProc is called when it is safe to delete the render target in the + backend API (accounting only for use of the render target by this surface). If SkSurface + creation fails releaseProc is called before this function returns. + + If defined(SK_GANESH) is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param backendRenderTarget GPU intermediate memory buffer + @param colorSpace range of colors + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @param releaseProc function called when backendRenderTarget can be released + @param releaseContext state passed to releaseProc + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeFromBackendRenderTarget(GrRecordingContext* context, + const GrBackendRenderTarget& backendRenderTarget, + GrSurfaceOrigin origin, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps, + RenderTargetReleaseProc releaseProc = nullptr, + ReleaseContext releaseContext = nullptr); + + /** Returns SkSurface on GPU indicated by context. Allocates memory for + pixels, based on the width, height, and SkColorType in SkImageInfo. budgeted + selects whether allocation for pixels is tracked by context. imageInfo + describes the pixel format in SkColorType, and transparency in + SkAlphaType, and color matching in SkColorSpace. + + sampleCount requests the number of samples per pixel. + Pass zero to disable multi-sample anti-aliasing. The request is rounded + up to the next supported count, or rounded down if it is larger than the + maximum supported count. + + surfaceOrigin pins either the top-left or the bottom-left corner to the origin. + + shouldCreateWithMips hints that SkImage returned by makeImageSnapshot() is mip map. + + If defined(SK_GANESH) is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace; + width, or height, or both, may be zero + @param sampleCount samples per pixel, or 0 to disable full scene anti-aliasing + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @param shouldCreateWithMips hint that SkSurface will host mip map images + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrRecordingContext* context, + skgpu::Budgeted budgeted, + const SkImageInfo& imageInfo, + int sampleCount, + GrSurfaceOrigin surfaceOrigin, + const SkSurfaceProps* surfaceProps, + bool shouldCreateWithMips = false); + + /** Returns SkSurface on GPU indicated by context. Allocates memory for + pixels, based on the width, height, and SkColorType in SkImageInfo. budgeted + selects whether allocation for pixels is tracked by context. imageInfo + describes the pixel format in SkColorType, and transparency in + SkAlphaType, and color matching in SkColorSpace. + + sampleCount requests the number of samples per pixel. + Pass zero to disable multi-sample anti-aliasing. The request is rounded + up to the next supported count, or rounded down if it is larger than the + maximum supported count. + + SkSurface bottom-left corner is pinned to the origin. + + @param context GPU context + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width, or height, or both, may be zero + @param sampleCount samples per pixel, or 0 to disable multi-sample anti-aliasing + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrRecordingContext* context, + skgpu::Budgeted budgeted, + const SkImageInfo& imageInfo, + int sampleCount, + const SkSurfaceProps* surfaceProps) { +#if defined(SK_GANESH) + return MakeRenderTarget(context, budgeted, imageInfo, sampleCount, + kBottomLeft_GrSurfaceOrigin, surfaceProps); +#else + // TODO(kjlubick, scroggo) Remove this once Android is updated. + return nullptr; +#endif + } + + /** Returns SkSurface on GPU indicated by context. Allocates memory for + pixels, based on the width, height, and SkColorType in SkImageInfo. budgeted + selects whether allocation for pixels is tracked by context. imageInfo + describes the pixel format in SkColorType, and transparency in + SkAlphaType, and color matching in SkColorSpace. + + SkSurface bottom-left corner is pinned to the origin. + + @param context GPU context + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width, or height, or both, may be zero + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrRecordingContext* context, + skgpu::Budgeted budgeted, + const SkImageInfo& imageInfo) { +#if defined(SK_GANESH) + if (!imageInfo.width() || !imageInfo.height()) { + return nullptr; + } + return MakeRenderTarget(context, budgeted, imageInfo, 0, kBottomLeft_GrSurfaceOrigin, + nullptr); +#else + // TODO(kjlubick, scroggo) Remove this once Android is updated. + return nullptr; +#endif + } + + /** Returns SkSurface on GPU indicated by context that is compatible with the provided + characterization. budgeted selects whether allocation for pixels is tracked by context. + + @param context GPU context + @param characterization description of the desired SkSurface + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrRecordingContext* context, + const SkSurfaceCharacterization& characterization, + skgpu::Budgeted budgeted); + +#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 + /** Private. + Creates SkSurface from Android hardware buffer. + Returned SkSurface takes a reference on the buffer. The ref on the buffer will be released + when the SkSurface is destroyed and there is no pending work on the GPU involving the + buffer. + + Only available on Android, when __ANDROID_API__ is defined to be 26 or greater. + + Currently this is only supported for buffers that can be textured as well as rendered to. + In other words that must have both AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT and + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE usage bits. + + @param context GPU context + @param hardwareBuffer AHardwareBuffer Android hardware buffer + @param colorSpace range of colors; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @param fromWindow Whether or not the AHardwareBuffer is part of an Android Window. + Currently only used with Vulkan backend. + @return created SkSurface, or nullptr + */ + static sk_sp MakeFromAHardwareBuffer(GrDirectContext* context, + AHardwareBuffer* hardwareBuffer, + GrSurfaceOrigin origin, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + , bool fromWindow = false +#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK + ); +#endif + +#if defined(SK_GRAPHITE) + /** + * In Graphite, while clients hold a ref on an SkSurface, the backing gpu object does _not_ + * count against the budget. Once an SkSurface is freed, the backing gpu object may or may + * not become a scratch (i.e., reusable) resource but, if it does, it will be counted against + * the budget. + */ + static sk_sp MakeGraphite( + skgpu::graphite::Recorder*, + const SkImageInfo& imageInfo, + skgpu::Mipmapped = skgpu::Mipmapped::kNo, + const SkSurfaceProps* surfaceProps = nullptr); + + /** + * Wraps a GPU-backed texture in an SkSurface. Depending on the backend gpu API, the caller may + * be required to ensure the texture is valid for the lifetime of the returned SkSurface. The + * required lifetimes for the specific apis are: + * Metal: Skia will call retain on the underlying MTLTexture so the caller can drop it once + * this call returns. + * + * SkSurface is returned if all the parameters are valid. The backendTexture is valid if its + * format agrees with colorSpace and recorder; for instance, if backendTexture has an sRGB + * configuration, then the recorder must support sRGB, and colorSpace must be present. Further, + * backendTexture's width and height must not exceed the recorder's capabilities, and the + * recorder must be able to support the back-end texture. + */ + static sk_sp MakeGraphiteFromBackendTexture(skgpu::graphite::Recorder*, + const skgpu::graphite::BackendTexture&, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* props); + +#endif // SK_GRAPHITE + +#if defined(SK_GANESH) && defined(SK_METAL) + /** Creates SkSurface from CAMetalLayer. + Returned SkSurface takes a reference on the CAMetalLayer. The ref on the layer will be + released when the SkSurface is destroyed. + + Only available when Metal API is enabled. + + Will grab the current drawable from the layer and use its texture as a backendRT to + create a renderable surface. + + @param context GPU context + @param layer GrMTLHandle (expected to be a CAMetalLayer*) + @param sampleCnt samples per pixel, or 0 to disable full scene anti-aliasing + @param colorSpace range of colors; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @param drawable Pointer to drawable to be filled in when this surface is + instantiated; may not be nullptr + @return created SkSurface, or nullptr + */ + static sk_sp MakeFromCAMetalLayer(GrRecordingContext* context, + GrMTLHandle layer, + GrSurfaceOrigin origin, + int sampleCnt, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps, + GrMTLHandle* drawable) + SK_API_AVAILABLE_CA_METAL_LAYER; + + /** Creates SkSurface from MTKView. + Returned SkSurface takes a reference on the MTKView. The ref on the layer will be + released when the SkSurface is destroyed. + + Only available when Metal API is enabled. + + Will grab the current drawable from the layer and use its texture as a backendRT to + create a renderable surface. + + @param context GPU context + @param layer GrMTLHandle (expected to be a MTKView*) + @param sampleCnt samples per pixel, or 0 to disable full scene anti-aliasing + @param colorSpace range of colors; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return created SkSurface, or nullptr + */ + static sk_sp MakeFromMTKView(GrRecordingContext* context, + GrMTLHandle mtkView, + GrSurfaceOrigin origin, + int sampleCnt, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps) + SK_API_AVAILABLE(macos(10.11), ios(9.0)); +#endif + + /** Is this surface compatible with the provided characterization? + + This method can be used to determine if an existing SkSurface is a viable destination + for an SkDeferredDisplayList. + + @param characterization The characterization for which a compatibility check is desired + @return true if this surface is compatible with the characterization; + false otherwise + */ + bool isCompatible(const SkSurfaceCharacterization& characterization) const; + + /** Returns SkSurface without backing pixels. Drawing to SkCanvas returned from SkSurface + has no effect. Calling makeImageSnapshot() on returned SkSurface returns nullptr. + + @param width one or greater + @param height one or greater + @return SkSurface if width and height are positive; otherwise, nullptr + + example: https://fiddle.skia.org/c/@Surface_MakeNull + */ + static sk_sp MakeNull(int width, int height); + + /** Returns pixel count in each row; may be zero or greater. + + @return number of pixel columns + */ + int width() const { return fWidth; } + + /** Returns pixel row count; may be zero or greater. + + @return number of pixel rows + */ + int height() const { return fHeight; } + + /** Returns an ImageInfo describing the surface. + */ + virtual SkImageInfo imageInfo() const { return SkImageInfo::MakeUnknown(fWidth, fHeight); } + + /** Returns unique value identifying the content of SkSurface. Returned value changes + each time the content changes. Content is changed by drawing, or by calling + notifyContentWillChange(). + + @return unique content identifier + + example: https://fiddle.skia.org/c/@Surface_notifyContentWillChange + */ + uint32_t generationID(); + + /** \enum SkSurface::ContentChangeMode + ContentChangeMode members are parameters to notifyContentWillChange(). + */ + enum ContentChangeMode { + kDiscard_ContentChangeMode, //!< discards surface on change + kRetain_ContentChangeMode, //!< preserves surface on change + }; + + /** Notifies that SkSurface contents will be changed by code outside of Skia. + Subsequent calls to generationID() return a different value. + + TODO: Can kRetain_ContentChangeMode be deprecated? + + example: https://fiddle.skia.org/c/@Surface_notifyContentWillChange + */ + void notifyContentWillChange(ContentChangeMode mode); + + /** Returns the recording context being used by the SkSurface. + + @return the recording context, if available; nullptr otherwise + */ + GrRecordingContext* recordingContext(); + + /** Returns the recorder being used by the SkSurface. + + @return the recorder, if available; nullptr otherwise + */ + skgpu::graphite::Recorder* recorder(); + +#if defined(SK_GANESH) + enum BackendHandleAccess { + kFlushRead_BackendHandleAccess, //!< back-end object is readable + kFlushWrite_BackendHandleAccess, //!< back-end object is writable + kDiscardWrite_BackendHandleAccess, //!< back-end object must be overwritten + }; + + /** Deprecated. + */ + static const BackendHandleAccess kFlushRead_TextureHandleAccess = + kFlushRead_BackendHandleAccess; + + /** Deprecated. + */ + static const BackendHandleAccess kFlushWrite_TextureHandleAccess = + kFlushWrite_BackendHandleAccess; + + /** Deprecated. + */ + static const BackendHandleAccess kDiscardWrite_TextureHandleAccess = + kDiscardWrite_BackendHandleAccess; + + /** Retrieves the back-end texture. If SkSurface has no back-end texture, an invalid + object is returned. Call GrBackendTexture::isValid to determine if the result + is valid. + + The returned GrBackendTexture should be discarded if the SkSurface is drawn to or deleted. + + @return GPU texture reference; invalid on failure + */ + GrBackendTexture getBackendTexture(BackendHandleAccess backendHandleAccess); + + /** Retrieves the back-end render target. If SkSurface has no back-end render target, an invalid + object is returned. Call GrBackendRenderTarget::isValid to determine if the result + is valid. + + The returned GrBackendRenderTarget should be discarded if the SkSurface is drawn to + or deleted. + + @return GPU render target reference; invalid on failure + */ + GrBackendRenderTarget getBackendRenderTarget(BackendHandleAccess backendHandleAccess); + + /** If the surface was made via MakeFromBackendTexture then it's backing texture may be + substituted with a different texture. The contents of the previous backing texture are + copied into the new texture. SkCanvas state is preserved. The original sample count is + used. The GrBackendFormat and dimensions of replacement texture must match that of + the original. + + Upon success textureReleaseProc is called when it is safe to delete the texture in the + backend API (accounting only for use of the texture by this surface). If SkSurface creation + fails textureReleaseProc is called before this function returns. + + @param backendTexture the new backing texture for the surface + @param mode Retain or discard current Content + @param textureReleaseProc function called when texture can be released + @param releaseContext state passed to textureReleaseProc + */ + bool replaceBackendTexture(const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + ContentChangeMode mode = kRetain_ContentChangeMode, + TextureReleaseProc textureReleaseProc = nullptr, + ReleaseContext releaseContext = nullptr); +#endif + + /** Returns SkCanvas that draws into SkSurface. Subsequent calls return the same SkCanvas. + SkCanvas returned is managed and owned by SkSurface, and is deleted when SkSurface + is deleted. + + @return drawing SkCanvas for SkSurface + + example: https://fiddle.skia.org/c/@Surface_getCanvas + */ + SkCanvas* getCanvas(); + + /** Returns SkCapabilities that describes the capabilities of the SkSurface's device. + + @return SkCapabilities of SkSurface's device. + */ + sk_sp capabilities(); + + /** Returns a compatible SkSurface, or nullptr. Returned SkSurface contains + the same raster, GPU, or null properties as the original. Returned SkSurface + does not share the same pixels. + + Returns nullptr if imageInfo width or height are zero, or if imageInfo + is incompatible with SkSurface. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of SkSurface; width and height must be greater than zero + @return compatible SkSurface or nullptr + + example: https://fiddle.skia.org/c/@Surface_makeSurface + */ + sk_sp makeSurface(const SkImageInfo& imageInfo); + + /** Calls makeSurface(ImageInfo) with the same ImageInfo as this surface, but with the + * specified width and height. + */ + sk_sp makeSurface(int width, int height); + + /** Returns SkImage capturing SkSurface contents. Subsequent drawing to SkSurface contents + are not captured. SkImage allocation is accounted for if SkSurface was created with + skgpu::Budgeted::kYes. + + @return SkImage initialized with SkSurface contents + + example: https://fiddle.skia.org/c/@Surface_makeImageSnapshot + */ + sk_sp makeImageSnapshot(); + + /** + * Like the no-parameter version, this returns an image of the current surface contents. + * This variant takes a rectangle specifying the subset of the surface that is of interest. + * These bounds will be sanitized before being used. + * - If bounds extends beyond the surface, it will be trimmed to just the intersection of + * it and the surface. + * - If bounds does not intersect the surface, then this returns nullptr. + * - If bounds == the surface, then this is the same as calling the no-parameter variant. + + example: https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2 + */ + sk_sp makeImageSnapshot(const SkIRect& bounds); + +#if defined(SK_GRAPHITE) + /** + * The 'asImage' and 'makeImageCopy' API/entry points are currently only available for + * Graphite. + * + * In this API, SkSurface no longer supports copy-on-write behavior. Instead, when creating + * an image for a surface, the client must explicitly indicate if a copy should be made. + * In both of the below calls the resource backing the surface will never change. + * + * The 'asImage' entry point has some major ramifications for the mutability of the + * returned SkImage. Since the originating surface and the returned image share the + * same backing, care must be taken by the client to ensure that the contents of the image + * reflect the desired contents when it is consumed by the gpu. + * Note: if the backing GPU buffer isn't textureable this method will return null. Graphite + * will not attempt to make a copy. + * Note: For 'asImage', the mipmapping of the image will match that of the source surface. + * + * The 'makeImageCopy' entry point allows subsetting and the addition of mipmaps (since + * a copy is already being made). + * + * In Graphite, the legacy API call (i.e., makeImageSnapshot) will just always make a copy. + */ + sk_sp asImage(); + + sk_sp makeImageCopy(const SkIRect* subset = nullptr, + skgpu::Mipmapped mipmapped = skgpu::Mipmapped::kNo); +#endif + + /** Draws SkSurface contents to canvas, with its top-left corner at (x, y). + + If SkPaint paint is not nullptr, apply SkColorFilter, alpha, SkImageFilter, and SkBlendMode. + + @param canvas SkCanvas drawn into + @param x horizontal offset in SkCanvas + @param y vertical offset in SkCanvas + @param sampling what technique to use when sampling the surface pixels + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + + example: https://fiddle.skia.org/c/@Surface_draw + */ + void draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling, + const SkPaint* paint); + + void draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint = nullptr) { + this->draw(canvas, x, y, SkSamplingOptions(), paint); + } + + /** Copies SkSurface pixel address, row bytes, and SkImageInfo to SkPixmap, if address + is available, and returns true. If pixel address is not available, return + false and leave SkPixmap unchanged. + + pixmap contents become invalid on any future change to SkSurface. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkSurface has direct access to pixels + + example: https://fiddle.skia.org/c/@Surface_peekPixels + */ + bool peekPixels(SkPixmap* pixmap); + + /** Copies SkRect of pixels to dst. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (dst.width(), dst.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dst.colorType() and dst.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dst contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkPixmap pixels could not be allocated. + - dst.rowBytes() is too small to contain one row of pixels. + + @param dst storage for pixels copied from SkSurface + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Surface_readPixels + */ + bool readPixels(const SkPixmap& dst, int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into dstPixels. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dstInfo.colorType() and dstInfo.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dstPixels contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkSurface pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). + - dstRowBytes is too small to contain one row of pixels. + + @param dstInfo width, height, SkColorType, and SkAlphaType of dstPixels + @param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger + @param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY); + + /** Copies SkRect of pixels from SkSurface into bitmap. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to bitmap.colorType() and bitmap.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dst contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkSurface pixels could not be converted to dst.colorType() or dst.alphaType(). + - dst pixels could not be allocated. + - dst.rowBytes() is too small to contain one row of pixels. + + @param dst storage for pixels copied from SkSurface + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Surface_readPixels_3 + */ + bool readPixels(const SkBitmap& dst, int srcX, int srcY); + + using AsyncReadResult = SkImage::AsyncReadResult; + + /** Client-provided context that is passed to client-provided ReadPixelsContext. */ + using ReadPixelsContext = void*; + + /** Client-provided callback to asyncRescaleAndReadPixels() or + asyncRescaleAndReadPixelsYUV420() that is called when read result is ready or on failure. + */ + using ReadPixelsCallback = void(ReadPixelsContext, std::unique_ptr); + + /** Controls the gamma that rescaling occurs in for asyncRescaleAndReadPixels() and + asyncRescaleAndReadPixelsYUV420(). + */ + using RescaleGamma = SkImage::RescaleGamma; + using RescaleMode = SkImage::RescaleMode; + + /** Makes surface pixel data available to caller, possibly asynchronously. It can also rescale + the surface pixels. + + Currently asynchronous reads are only supported on the GPU backend and only when the + underlying 3D API supports transfer buffers and CPU/GPU synchronization primitives. In all + other cases this operates synchronously. + + Data is read from the source sub-rectangle, is optionally converted to a linear gamma, is + rescaled to the size indicated by 'info', is then converted to the color space, color type, + and alpha type of 'info'. A 'srcRect' that is not contained by the bounds of the surface + causes failure. + + When the pixel data is ready the caller's ReadPixelsCallback is called with a + AsyncReadResult containing pixel data in the requested color type, alpha type, and color + space. The AsyncReadResult will have count() == 1. Upon failure the callback is called + with nullptr for AsyncReadResult. For a GPU surface this flushes work but a submit must + occur to guarantee a finite time before the callback is called. + + The data is valid for the lifetime of AsyncReadResult with the exception that if the + SkSurface is GPU-backed the data is immediately invalidated if the context is abandoned + or destroyed. + + @param info info of the requested pixels + @param srcRect subrectangle of surface to read + @param rescaleGamma controls whether rescaling is done in the surface's gamma or whether + the source data is transformed to a linear gamma before rescaling. + @param rescaleMode controls the technique of the rescaling + @param callback function to call with result of the read + @param context passed to callback + */ + void asyncRescaleAndReadPixels(const SkImageInfo& info, + const SkIRect& srcRect, + RescaleGamma rescaleGamma, + RescaleMode rescaleMode, + ReadPixelsCallback callback, + ReadPixelsContext context); + + /** + Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The + RGB->YUV conversion is controlled by 'yuvColorSpace'. The YUV data is returned as three + planes ordered y, u, v. The u and v planes are half the width and height of the resized + rectangle. The y, u, and v values are single bytes. Currently this fails if 'dstSize' + width and height are not even. A 'srcRect' that is not contained by the bounds of the + surface causes failure. + + When the pixel data is ready the caller's ReadPixelsCallback is called with a + AsyncReadResult containing the planar data. The AsyncReadResult will have count() == 3. + Upon failure the callback is called with nullptr for AsyncReadResult. For a GPU surface this + flushes work but a submit must occur to guarantee a finite time before the callback is + called. + + The data is valid for the lifetime of AsyncReadResult with the exception that if the + SkSurface is GPU-backed the data is immediately invalidated if the context is abandoned + or destroyed. + + @param yuvColorSpace The transformation from RGB to YUV. Applied to the resized image + after it is converted to dstColorSpace. + @param dstColorSpace The color space to convert the resized image to, after rescaling. + @param srcRect The portion of the surface to rescale and convert to YUV planes. + @param dstSize The size to rescale srcRect to + @param rescaleGamma controls whether rescaling is done in the surface's gamma or whether + the source data is transformed to a linear gamma before rescaling. + @param rescaleMode controls the sampling technique of the rescaling + @param callback function to call with the planar read result + @param context passed to callback + */ + void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace, + sk_sp dstColorSpace, + const SkIRect& srcRect, + const SkISize& dstSize, + RescaleGamma rescaleGamma, + RescaleMode rescaleMode, + ReadPixelsCallback callback, + ReadPixelsContext context); + + /** Copies SkRect of pixels from the src SkPixmap to the SkSurface. + + Source SkRect corners are (0, 0) and (src.width(), src.height()). + Destination SkRect corners are (dstX, dstY) and + (dstX + Surface width(), dstY + Surface height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to SkSurface colorType() and SkSurface alphaType() if required. + + @param src storage for pixels to copy to SkSurface + @param dstX x-axis position relative to SkSurface to begin copy; may be negative + @param dstY y-axis position relative to SkSurface to begin copy; may be negative + + example: https://fiddle.skia.org/c/@Surface_writePixels + */ + void writePixels(const SkPixmap& src, int dstX, int dstY); + + /** Copies SkRect of pixels from the src SkBitmap to the SkSurface. + + Source SkRect corners are (0, 0) and (src.width(), src.height()). + Destination SkRect corners are (dstX, dstY) and + (dstX + Surface width(), dstY + Surface height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to SkSurface colorType() and SkSurface alphaType() if required. + + @param src storage for pixels to copy to SkSurface + @param dstX x-axis position relative to SkSurface to begin copy; may be negative + @param dstY y-axis position relative to SkSurface to begin copy; may be negative + + example: https://fiddle.skia.org/c/@Surface_writePixels_2 + */ + void writePixels(const SkBitmap& src, int dstX, int dstY); + + /** Returns SkSurfaceProps for surface. + + @return LCD striping orientation and setting for device independent fonts + */ + const SkSurfaceProps& props() const { return fProps; } + + /** Call to ensure all reads/writes of the surface have been issued to the underlying 3D API. + Skia will correctly order its own draws and pixel operations. This must to be used to ensure + correct ordering when the surface backing store is accessed outside Skia (e.g. direct use of + the 3D API or a windowing system). GrDirectContext has additional flush and submit methods + that apply to all surfaces and images created from a GrDirectContext. This is equivalent to + calling SkSurface::flush with a default GrFlushInfo followed by + GrDirectContext::submit(syncCpu). + */ + void flushAndSubmit(bool syncCpu = false); + + enum class BackendSurfaceAccess { + kNoAccess, //!< back-end object will not be used by client + kPresent, //!< back-end surface will be used for presenting to screen + }; + +#if defined(SK_GANESH) + /** If a surface is GPU texture backed, is being drawn with MSAA, and there is a resolve + texture, this call will insert a resolve command into the stream of gpu commands. In order + for the resolve to actually have an effect, the work still needs to be flushed and submitted + to the GPU after recording the resolve command. If a resolve is not supported or the + SkSurface has no dirty work to resolve, then this call is a no-op. + + This call is most useful when the SkSurface is created by wrapping a single sampled gpu + texture, but asking Skia to render with MSAA. If the client wants to use the wrapped texture + outside of Skia, the only way to trigger a resolve is either to call this command or use + SkSurface::flush. + */ + void resolveMSAA(); + + /** Issues pending SkSurface commands to the GPU-backed API objects and resolves any SkSurface + MSAA. A call to GrDirectContext::submit is always required to ensure work is actually sent + to the gpu. Some specific API details: + GL: Commands are actually sent to the driver, but glFlush is never called. Thus some + sync objects from the flush will not be valid until a submission occurs. + + Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command + buffer or encoder objects. However, these objects are not sent to the gpu until a + submission occurs. + + The work that is submitted to the GPU will be dependent on the BackendSurfaceAccess that is + passed in. + + If BackendSurfaceAccess::kNoAccess is passed in all commands will be issued to the GPU. + + If BackendSurfaceAccess::kPresent is passed in and the backend API is not Vulkan, it is + treated the same as kNoAccess. If the backend API is Vulkan, the VkImage that backs the + SkSurface will be transferred back to its original queue. If the SkSurface was created by + wrapping a VkImage, the queue will be set to the queue which was originally passed in on + the GrVkImageInfo. Additionally, if the original queue was not external or foreign the + layout of the VkImage will be set to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR. + + The GrFlushInfo describes additional options to flush. Please see documentation at + GrFlushInfo for more info. + + If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be + submitted to the gpu during the next submit call (it is possible Skia failed to create a + subset of the semaphores). The client should not wait on these semaphores until after submit + has been called, but must keep them alive until then. If a submit flag was passed in with + the flush these valid semaphores can we waited on immediately. If this call returns + GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on + the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in + with the GrFlushInfo. Regardless of whether semaphores were submitted to the GPU or not, the + client is still responsible for deleting any initialized semaphores. + Regardless of semaphore submission the context will still be flushed. It should be + emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not + happen. It simply means there were no semaphores submitted to the GPU. A caller should only + take this as a failure if they passed in semaphores to be submitted. + + Pending surface commands are flushed regardless of the return result. + + @param access type of access the call will do on the backend object after flush + @param info flush options + */ + GrSemaphoresSubmitted flush(BackendSurfaceAccess access, const GrFlushInfo& info); + + /** Issues pending SkSurface commands to the GPU-backed API objects and resolves any SkSurface + MSAA. A call to GrDirectContext::submit is always required to ensure work is actually sent + to the gpu. Some specific API details: + GL: Commands are actually sent to the driver, but glFlush is never called. Thus some + sync objects from the flush will not be valid until a submission occurs. + + Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command + buffer or encoder objects. However, these objects are not sent to the gpu until a + submission occurs. + + The GrFlushInfo describes additional options to flush. Please see documentation at + GrFlushInfo for more info. + + If a skgpu::MutableTextureState is passed in, at the end of the flush we will transition + the surface to be in the state requested by the skgpu::MutableTextureState. If the surface + (or SkImage or GrBackendSurface wrapping the same backend object) is used again after this + flush the state may be changed and no longer match what is requested here. This is often + used if the surface will be used for presenting or external use and the client wants backend + object to be prepped for that use. A finishedProc or semaphore on the GrFlushInfo will also + include the work for any requested state change. + + If the backend API is Vulkan, the caller can set the skgpu::MutableTextureState's + VkImageLayout to VK_IMAGE_LAYOUT_UNDEFINED or queueFamilyIndex to VK_QUEUE_FAMILY_IGNORED to + tell Skia to not change those respective states. + + If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be + submitted to the gpu during the next submit call (it is possible Skia failed to create a + subset of the semaphores). The client should not wait on these semaphores until after submit + has been called, but must keep them alive until then. If a submit flag was passed in with + the flush these valid semaphores can we waited on immediately. If this call returns + GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on + the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in + with the GrFlushInfo. Regardless of whether semaphores were submitted to the GPU or not, the + client is still responsible for deleting any initialized semaphores. + Regardleess of semaphore submission the context will still be flushed. It should be + emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not + happen. It simply means there were no semaphores submitted to the GPU. A caller should only + take this as a failure if they passed in semaphores to be submitted. + + Pending surface commands are flushed regardless of the return result. + + @param info flush options + @param access optional state change request after flush + */ + GrSemaphoresSubmitted flush(const GrFlushInfo& info, + const skgpu::MutableTextureState* newState = nullptr); +#endif // defined(SK_GANESH) + + void flush(); + + /** Inserts a list of GPU semaphores that the current GPU-backed API must wait on before + executing any more commands on the GPU for this surface. If this call returns false, then + the GPU back-end will not wait on any passed in semaphores, and the client will still own + the semaphores, regardless of the value of deleteSemaphoresAfterWait. + + If deleteSemaphoresAfterWait is false then Skia will not delete the semaphores. In this case + it is the client's responsibility to not destroy or attempt to reuse the semaphores until it + knows that Skia has finished waiting on them. This can be done by using finishedProcs + on flush calls. + + @param numSemaphores size of waitSemaphores array + @param waitSemaphores array of semaphore containers + @paramm deleteSemaphoresAfterWait who owns and should delete the semaphores + @return true if GPU is waiting on semaphores + */ + bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores, + bool deleteSemaphoresAfterWait = true); + + /** Initializes SkSurfaceCharacterization that can be used to perform GPU back-end + processing in a separate thread. Typically this is used to divide drawing + into multiple tiles. SkDeferredDisplayListRecorder records the drawing commands + for each tile. + + Return true if SkSurface supports characterization. raster surface returns false. + + @param characterization properties for parallel drawing + @return true if supported + + example: https://fiddle.skia.org/c/@Surface_characterize + */ + bool characterize(SkSurfaceCharacterization* characterization) const; + + /** Draws the deferred display list created via a SkDeferredDisplayListRecorder. + If the deferred display list is not compatible with this SkSurface, the draw is skipped + and false is return. + + The xOffset and yOffset parameters are experimental and, if not both zero, will cause + the draw to be ignored. + When implemented, if xOffset or yOffset are non-zero, the DDL will be drawn offset by that + amount into the surface. + + @param deferredDisplayList drawing commands + @param xOffset x-offset at which to draw the DDL + @param yOffset y-offset at which to draw the DDL + @return false if deferredDisplayList is not compatible + + example: https://fiddle.skia.org/c/@Surface_draw_2 + */ + bool draw(sk_sp deferredDisplayList, + int xOffset = 0, + int yOffset = 0); + +protected: + SkSurface(int width, int height, const SkSurfaceProps* surfaceProps); + SkSurface(const SkImageInfo& imageInfo, const SkSurfaceProps* surfaceProps); + + // called by subclass if their contents have changed + void dirtyGenerationID() { + fGenerationID = 0; + } + +private: + const SkSurfaceProps fProps; + const int fWidth; + const int fHeight; + uint32_t fGenerationID; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurfaceCharacterization.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurfaceCharacterization.h new file mode 100644 index 00000000000000..0b65a10d03c4b4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurfaceCharacterization.h @@ -0,0 +1,263 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSurfaceCharacterization_DEFINED +#define SkSurfaceCharacterization_DEFINED + + +#include "include/core/SkColorSpace.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSurfaceProps.h" + +class SkColorSpace; + + +#if defined(SK_GANESH) +#include "include/gpu/GrBackendSurface.h" +#include "include/gpu/GrContextThreadSafeProxy.h" +#include "include/gpu/GrTypes.h" + +/** \class SkSurfaceCharacterization + A surface characterization contains all the information Ganesh requires to makes its internal + rendering decisions. When passed into a SkDeferredDisplayListRecorder it will copy the + data and pass it on to the SkDeferredDisplayList if/when it is created. Note that both of + those objects (the Recorder and the DisplayList) will take a ref on the + GrContextThreadSafeProxy and SkColorSpace objects. +*/ +class SK_API SkSurfaceCharacterization { +public: + enum class Textureable : bool { kNo = false, kYes = true }; + enum class MipMapped : bool { kNo = false, kYes = true }; + enum class UsesGLFBO0 : bool { kNo = false, kYes = true }; + // This flag indicates that the backing VkImage for this Vulkan surface will have the + // VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set. This bit allows skia to handle advanced blends + // more optimally in a shader by being able to directly read the dst values. + enum class VkRTSupportsInputAttachment : bool { kNo = false, kYes = true }; + // This flag indicates if the surface is wrapping a raw Vulkan secondary command buffer. + enum class VulkanSecondaryCBCompatible : bool { kNo = false, kYes = true }; + + SkSurfaceCharacterization() + : fCacheMaxResourceBytes(0) + , fOrigin(kBottomLeft_GrSurfaceOrigin) + , fSampleCnt(0) + , fIsTextureable(Textureable::kYes) + , fIsMipMapped(MipMapped::kYes) + , fUsesGLFBO0(UsesGLFBO0::kNo) + , fVulkanSecondaryCBCompatible(VulkanSecondaryCBCompatible::kNo) + , fIsProtected(GrProtected::kNo) + , fSurfaceProps(0, kUnknown_SkPixelGeometry) { + } + + SkSurfaceCharacterization(SkSurfaceCharacterization&&) = default; + SkSurfaceCharacterization& operator=(SkSurfaceCharacterization&&) = default; + + SkSurfaceCharacterization(const SkSurfaceCharacterization&) = default; + SkSurfaceCharacterization& operator=(const SkSurfaceCharacterization& other) = default; + bool operator==(const SkSurfaceCharacterization& other) const; + bool operator!=(const SkSurfaceCharacterization& other) const { + return !(*this == other); + } + + /* + * Return a new surface characterization with the only difference being a different width + * and height + */ + SkSurfaceCharacterization createResized(int width, int height) const; + + /* + * Return a new surface characterization with only a replaced color space + */ + SkSurfaceCharacterization createColorSpace(sk_sp) const; + + /* + * Return a new surface characterization with the backend format replaced. A colorType + * must also be supplied to indicate the interpretation of the new format. + */ + SkSurfaceCharacterization createBackendFormat(SkColorType colorType, + const GrBackendFormat& backendFormat) const; + + /* + * Return a new surface characterization with just a different use of FBO0 (in GL) + */ + SkSurfaceCharacterization createFBO0(bool usesGLFBO0) const; + + GrContextThreadSafeProxy* contextInfo() const { return fContextInfo.get(); } + sk_sp refContextInfo() const { return fContextInfo; } + size_t cacheMaxResourceBytes() const { return fCacheMaxResourceBytes; } + + bool isValid() const { return kUnknown_SkColorType != fImageInfo.colorType(); } + + const SkImageInfo& imageInfo() const { return fImageInfo; } + const GrBackendFormat& backendFormat() const { return fBackendFormat; } + GrSurfaceOrigin origin() const { return fOrigin; } + SkISize dimensions() const { return fImageInfo.dimensions(); } + int width() const { return fImageInfo.width(); } + int height() const { return fImageInfo.height(); } + SkColorType colorType() const { return fImageInfo.colorType(); } + int sampleCount() const { return fSampleCnt; } + bool isTextureable() const { return Textureable::kYes == fIsTextureable; } + bool isMipMapped() const { return MipMapped::kYes == fIsMipMapped; } + bool usesGLFBO0() const { return UsesGLFBO0::kYes == fUsesGLFBO0; } + bool vkRTSupportsInputAttachment() const { + return VkRTSupportsInputAttachment::kYes == fVkRTSupportsInputAttachment; + } + bool vulkanSecondaryCBCompatible() const { + return VulkanSecondaryCBCompatible::kYes == fVulkanSecondaryCBCompatible; + } + GrProtected isProtected() const { return fIsProtected; } + SkColorSpace* colorSpace() const { return fImageInfo.colorSpace(); } + sk_sp refColorSpace() const { return fImageInfo.refColorSpace(); } + const SkSurfaceProps& surfaceProps()const { return fSurfaceProps; } + + // Is the provided backend texture compatible with this surface characterization? + bool isCompatible(const GrBackendTexture&) const; + +private: + friend class SkSurface_Ganesh; // for 'set' & 'config' + friend class GrVkSecondaryCBDrawContext; // for 'set' & 'config' + friend class GrContextThreadSafeProxy; // for private ctor + friend class SkDeferredDisplayListRecorder; // for 'config' + friend class SkSurface; // for 'config' + + SkDEBUGCODE(void validate() const;) + + SkSurfaceCharacterization(sk_sp contextInfo, + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + const GrBackendFormat& backendFormat, + GrSurfaceOrigin origin, + int sampleCnt, + Textureable isTextureable, + MipMapped isMipMapped, + UsesGLFBO0 usesGLFBO0, + VkRTSupportsInputAttachment vkRTSupportsInputAttachment, + VulkanSecondaryCBCompatible vulkanSecondaryCBCompatible, + GrProtected isProtected, + const SkSurfaceProps& surfaceProps) + : fContextInfo(std::move(contextInfo)) + , fCacheMaxResourceBytes(cacheMaxResourceBytes) + , fImageInfo(ii) + , fBackendFormat(backendFormat) + , fOrigin(origin) + , fSampleCnt(sampleCnt) + , fIsTextureable(isTextureable) + , fIsMipMapped(isMipMapped) + , fUsesGLFBO0(usesGLFBO0) + , fVkRTSupportsInputAttachment(vkRTSupportsInputAttachment) + , fVulkanSecondaryCBCompatible(vulkanSecondaryCBCompatible) + , fIsProtected(isProtected) + , fSurfaceProps(surfaceProps) { + if (fSurfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) { + // Dynamic MSAA is not currently supported with DDL. + *this = {}; + } + SkDEBUGCODE(this->validate()); + } + + void set(sk_sp contextInfo, + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + const GrBackendFormat& backendFormat, + GrSurfaceOrigin origin, + int sampleCnt, + Textureable isTextureable, + MipMapped isMipMapped, + UsesGLFBO0 usesGLFBO0, + VkRTSupportsInputAttachment vkRTSupportsInputAttachment, + VulkanSecondaryCBCompatible vulkanSecondaryCBCompatible, + GrProtected isProtected, + const SkSurfaceProps& surfaceProps) { + if (surfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) { + // Dynamic MSAA is not currently supported with DDL. + *this = {}; + } else { + fContextInfo = contextInfo; + fCacheMaxResourceBytes = cacheMaxResourceBytes; + + fImageInfo = ii; + fBackendFormat = backendFormat; + fOrigin = origin; + fSampleCnt = sampleCnt; + fIsTextureable = isTextureable; + fIsMipMapped = isMipMapped; + fUsesGLFBO0 = usesGLFBO0; + fVkRTSupportsInputAttachment = vkRTSupportsInputAttachment; + fVulkanSecondaryCBCompatible = vulkanSecondaryCBCompatible; + fIsProtected = isProtected; + fSurfaceProps = surfaceProps; + } + SkDEBUGCODE(this->validate()); + } + + sk_sp fContextInfo; + size_t fCacheMaxResourceBytes; + + SkImageInfo fImageInfo; + GrBackendFormat fBackendFormat; + GrSurfaceOrigin fOrigin; + int fSampleCnt; + Textureable fIsTextureable; + MipMapped fIsMipMapped; + UsesGLFBO0 fUsesGLFBO0; + VkRTSupportsInputAttachment fVkRTSupportsInputAttachment; + VulkanSecondaryCBCompatible fVulkanSecondaryCBCompatible; + GrProtected fIsProtected; + SkSurfaceProps fSurfaceProps; +}; + +#else// !defined(SK_GANESH) +class GrBackendFormat; + +class SK_API SkSurfaceCharacterization { +public: + SkSurfaceCharacterization() : fSurfaceProps(0, kUnknown_SkPixelGeometry) { } + + SkSurfaceCharacterization createResized(int width, int height) const { + return *this; + } + + SkSurfaceCharacterization createColorSpace(sk_sp) const { + return *this; + } + + SkSurfaceCharacterization createBackendFormat(SkColorType, const GrBackendFormat&) const { + return *this; + } + + SkSurfaceCharacterization createFBO0(bool usesGLFBO0) const { + return *this; + } + + bool operator==(const SkSurfaceCharacterization& other) const { return false; } + bool operator!=(const SkSurfaceCharacterization& other) const { + return !(*this == other); + } + + size_t cacheMaxResourceBytes() const { return 0; } + + bool isValid() const { return false; } + + int width() const { return 0; } + int height() const { return 0; } + int stencilCount() const { return 0; } + bool isTextureable() const { return false; } + bool isMipMapped() const { return false; } + bool usesGLFBO0() const { return false; } + bool vkRTSupportsAttachmentInput() const { return false; } + bool vulkanSecondaryCBCompatible() const { return false; } + SkColorSpace* colorSpace() const { return nullptr; } + sk_sp refColorSpace() const { return nullptr; } + const SkSurfaceProps& surfaceProps()const { return fSurfaceProps; } + +private: + SkSurfaceProps fSurfaceProps; +}; + +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurfaceProps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurfaceProps.h new file mode 100644 index 00000000000000..4790f258e4ad59 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSurfaceProps.h @@ -0,0 +1,100 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSurfaceProps_DEFINED +#define SkSurfaceProps_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/base/SkTo.h" + +/** + * Description of how the LCD strips are arranged for each pixel. If this is unknown, or the + * pixels are meant to be "portable" and/or transformed before showing (e.g. rotated, scaled) + * then use kUnknown_SkPixelGeometry. + */ +enum SkPixelGeometry { + kUnknown_SkPixelGeometry, + kRGB_H_SkPixelGeometry, + kBGR_H_SkPixelGeometry, + kRGB_V_SkPixelGeometry, + kBGR_V_SkPixelGeometry, +}; + +// Returns true iff geo is a known geometry and is RGB. +static inline bool SkPixelGeometryIsRGB(SkPixelGeometry geo) { + return kRGB_H_SkPixelGeometry == geo || kRGB_V_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is BGR. +static inline bool SkPixelGeometryIsBGR(SkPixelGeometry geo) { + return kBGR_H_SkPixelGeometry == geo || kBGR_V_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is horizontal. +static inline bool SkPixelGeometryIsH(SkPixelGeometry geo) { + return kRGB_H_SkPixelGeometry == geo || kBGR_H_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is vertical. +static inline bool SkPixelGeometryIsV(SkPixelGeometry geo) { + return kRGB_V_SkPixelGeometry == geo || kBGR_V_SkPixelGeometry == geo; +} + +/** + * Describes properties and constraints of a given SkSurface. The rendering engine can parse these + * during drawing, and can sometimes optimize its performance (e.g. disabling an expensive + * feature). + */ +class SK_API SkSurfaceProps { +public: + enum Flags { + kUseDeviceIndependentFonts_Flag = 1 << 0, + // Use internal MSAA to render to non-MSAA GPU surfaces. + kDynamicMSAA_Flag = 1 << 1, + // If set, all rendering will have dithering enabled + // Currently this only impacts GPU backends + kAlwaysDither_Flag = 1 << 2, + }; + /** Deprecated alias used by Chromium. Will be removed. */ + static const Flags kUseDistanceFieldFonts_Flag = kUseDeviceIndependentFonts_Flag; + + /** No flags, unknown pixel geometry. */ + SkSurfaceProps(); + SkSurfaceProps(uint32_t flags, SkPixelGeometry); + + SkSurfaceProps(const SkSurfaceProps&); + SkSurfaceProps& operator=(const SkSurfaceProps&); + + SkSurfaceProps cloneWithPixelGeometry(SkPixelGeometry newPixelGeometry) const { + return SkSurfaceProps(fFlags, newPixelGeometry); + } + + uint32_t flags() const { return fFlags; } + SkPixelGeometry pixelGeometry() const { return fPixelGeometry; } + + bool isUseDeviceIndependentFonts() const { + return SkToBool(fFlags & kUseDeviceIndependentFonts_Flag); + } + + bool isAlwaysDither() const { + return SkToBool(fFlags & kAlwaysDither_Flag); + } + + bool operator==(const SkSurfaceProps& that) const { + return fFlags == that.fFlags && fPixelGeometry == that.fPixelGeometry; + } + + bool operator!=(const SkSurfaceProps& that) const { + return !(*this == that); + } + +private: + uint32_t fFlags; + SkPixelGeometry fPixelGeometry; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSwizzle.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSwizzle.h new file mode 100644 index 00000000000000..61e93b2da700b7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkSwizzle.h @@ -0,0 +1,19 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSwizzle_DEFINED +#define SkSwizzle_DEFINED + +#include "include/core/SkTypes.h" + +/** + Swizzles byte order of |count| 32-bit pixels, swapping R and B. + (RGBA <-> BGRA) +*/ +SK_API void SkSwapRB(uint32_t* dest, const uint32_t* src, int count); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTextBlob.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTextBlob.h new file mode 100644 index 00000000000000..8f6cb01c045ffe --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTextBlob.h @@ -0,0 +1,506 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTextBlob_DEFINED +#define SkTextBlob_DEFINED + +#include "include/core/SkFont.h" +#include "include/core/SkPaint.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkString.h" +#include "include/private/base/SkTemplates.h" + +#include + +struct SkRSXform; +struct SkSerialProcs; +struct SkDeserialProcs; + +namespace sktext { +class GlyphRunList; +} + +/** \class SkTextBlob + SkTextBlob combines multiple text runs into an immutable container. Each text + run consists of glyphs, SkPaint, and position. Only parts of SkPaint related to + fonts and text rendering are used by run. +*/ +class SK_API SkTextBlob final : public SkNVRefCnt { +private: + class RunRecord; + +public: + + /** Returns conservative bounding box. Uses SkPaint associated with each glyph to + determine glyph bounds, and unions all bounds. Returned bounds may be + larger than the bounds of all glyphs in runs. + + @return conservative bounding box + */ + const SkRect& bounds() const { return fBounds; } + + /** Returns a non-zero value unique among all text blobs. + + @return identifier for SkTextBlob + */ + uint32_t uniqueID() const { return fUniqueID; } + + /** Returns the number of intervals that intersect bounds. + bounds describes a pair of lines parallel to the text advance. + The return count is zero or a multiple of two, and is at most twice the number of glyphs in + the the blob. + + Pass nullptr for intervals to determine the size of the interval array. + + Runs within the blob that contain SkRSXform are ignored when computing intercepts. + + @param bounds lower and upper line parallel to the advance + @param intervals returned intersections; may be nullptr + @param paint specifies stroking, SkPathEffect that affects the result; may be nullptr + @return number of intersections; may be zero + */ + int getIntercepts(const SkScalar bounds[2], SkScalar intervals[], + const SkPaint* paint = nullptr) const; + + /** Creates SkTextBlob with a single run. + + font contains attributes used to define the run text. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32, this function uses the default + character-to-glyph mapping from the SkTypeface in font. It does not + perform typeface fallback for characters not found in the SkTypeface. + It does not perform kerning or other complex shaping; glyphs are + positioned based on their default advances. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param font text size, typeface, text scale, and so on, used to draw + @param encoding text encoding used in the text array + @return SkTextBlob constructed from one run + */ + static sk_sp MakeFromText(const void* text, size_t byteLength, const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + /** Creates SkTextBlob with a single run. string meaning depends on SkTextEncoding; + by default, string is encoded as UTF-8. + + font contains attributes used to define the run text. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32, this function uses the default + character-to-glyph mapping from the SkTypeface in font. It does not + perform typeface fallback for characters not found in the SkTypeface. + It does not perform kerning or other complex shaping; glyphs are + positioned based on their default advances. + + @param string character code points or glyphs drawn + @param font text size, typeface, text scale, and so on, used to draw + @param encoding text encoding used in the text array + @return SkTextBlob constructed from one run + */ + static sk_sp MakeFromString(const char* string, const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8) { + if (!string) { + return nullptr; + } + return MakeFromText(string, strlen(string), font, encoding); + } + + /** Returns a textblob built from a single run of text with x-positions and a single y value. + This is equivalent to using SkTextBlobBuilder and calling allocRunPosH(). + Returns nullptr if byteLength is zero. + + @param text character code points or glyphs drawn (based on encoding) + @param byteLength byte length of text array + @param xpos array of x-positions, must contain values for all of the character points. + @param constY shared y-position for each character point, to be paired with each xpos. + @param font SkFont used for this run + @param encoding specifies the encoding of the text array. + @return new textblob or nullptr + */ + static sk_sp MakeFromPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + /** Returns a textblob built from a single run of text with positions. + This is equivalent to using SkTextBlobBuilder and calling allocRunPos(). + Returns nullptr if byteLength is zero. + + @param text character code points or glyphs drawn (based on encoding) + @param byteLength byte length of text array + @param pos array of positions, must contain values for all of the character points. + @param font SkFont used for this run + @param encoding specifies the encoding of the text array. + @return new textblob or nullptr + */ + static sk_sp MakeFromPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + static sk_sp MakeFromRSXform(const void* text, size_t byteLength, + const SkRSXform xform[], const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage + to receive the encoded data, and memory_size describes the size of storage. + Returns bytes used if provided storage is large enough to hold all data; + otherwise, returns zero. + + procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. + If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface and user context. + + @param procs custom serial data encoders; may be nullptr + @param memory storage for data + @param memory_size size of storage + @return bytes written, or zero if required storage is larger than memory_size + + example: https://fiddle.skia.org/c/@TextBlob_serialize + */ + size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const; + + /** Returns storage containing SkData describing SkTextBlob, using optional custom + encoders. + + procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. + If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface and user context. + + @param procs custom serial data encoders; may be nullptr + @return storage containing serialized SkTextBlob + + example: https://fiddle.skia.org/c/@TextBlob_serialize_2 + */ + sk_sp serialize(const SkSerialProcs& procs) const; + + /** Recreates SkTextBlob that was serialized into data. Returns constructed SkTextBlob + if successful; otherwise, returns nullptr. Fails if size is smaller than + required data length, or if data does not permit constructing valid SkTextBlob. + + procs.fTypefaceProc permits supplying a custom function to decode SkTypeface. + If procs.fTypefaceProc is nullptr, default decoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface data, data byte length, and user context. + + @param data pointer for serial data + @param size size of data + @param procs custom serial data decoders; may be nullptr + @return SkTextBlob constructed from data in memory + */ + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs& procs); + + class SK_API Iter { + public: + struct Run { + SkTypeface* fTypeface; + int fGlyphCount; + const uint16_t* fGlyphIndices; +#ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED + const uint32_t* fClusterIndex_forTest; + int fUtf8Size_forTest; + const char* fUtf8_forTest; +#endif + }; + + Iter(const SkTextBlob&); + + /** + * Returns true for each "run" inside the textblob, setting the Run fields (if not null). + * If this returns false, there are no more runs, and the Run parameter will be ignored. + */ + bool next(Run*); + + // Experimental, DO NO USE, will change/go-away + struct ExperimentalRun { + SkFont font; + int count; + const uint16_t* glyphs; + const SkPoint* positions; + }; + bool experimentalNext(ExperimentalRun*); + + private: + const RunRecord* fRunRecord; + }; + +private: + friend class SkNVRefCnt; + + enum GlyphPositioning : uint8_t; + + explicit SkTextBlob(const SkRect& bounds); + + ~SkTextBlob(); + + // Memory for objects of this class is created with sk_malloc rather than operator new and must + // be freed with sk_free. + void operator delete(void* p); + void* operator new(size_t); + void* operator new(size_t, void* p); + + static unsigned ScalarsPerGlyph(GlyphPositioning pos); + + // Call when this blob is part of the key to a cache entry. This allows the cache + // to know automatically those entries can be purged when this SkTextBlob is deleted. + void notifyAddedToCache(uint32_t cacheID) const { + fCacheID.store(cacheID); + } + + friend class sktext::GlyphRunList; + friend class SkTextBlobBuilder; + friend class SkTextBlobPriv; + friend class SkTextBlobRunIterator; + + const SkRect fBounds; + const uint32_t fUniqueID; + mutable std::atomic fCacheID; + + SkDEBUGCODE(size_t fStorageSize;) + + // The actual payload resides in externally-managed storage, following the object. + // (see the .cpp for more details) + + using INHERITED = SkRefCnt; +}; + +/** \class SkTextBlobBuilder + Helper class for constructing SkTextBlob. +*/ +class SK_API SkTextBlobBuilder { +public: + + /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs. + + @return empty SkTextBlobBuilder + + example: https://fiddle.skia.org/c/@TextBlobBuilder_empty_constructor + */ + SkTextBlobBuilder(); + + /** Deletes data allocated internally by SkTextBlobBuilder. + */ + ~SkTextBlobBuilder(); + + /** Returns SkTextBlob built from runs of glyphs added by builder. Returned + SkTextBlob is immutable; it may be copied, but its contents may not be altered. + Returns nullptr if no runs of glyphs were added by builder. + + Resets SkTextBlobBuilder to its initial empty state, allowing it to be + reused to build a new set of runs. + + @return SkTextBlob or nullptr + + example: https://fiddle.skia.org/c/@TextBlobBuilder_make + */ + sk_sp make(); + + /** \struct SkTextBlobBuilder::RunBuffer + RunBuffer supplies storage for glyphs and positions within a run. + + A run is a sequence of glyphs sharing font metrics and positioning. + Each run may position its glyphs in one of three ways: + by specifying where the first glyph is drawn, and allowing font metrics to + determine the advance to subsequent glyphs; by specifying a baseline, and + the position on that baseline for each glyph in run; or by providing SkPoint + array, one per glyph. + */ + struct RunBuffer { + SkGlyphID* glyphs; //!< storage for glyph indexes in run + SkScalar* pos; //!< storage for glyph positions in run + char* utf8text; //!< storage for text UTF-8 code units in run + uint32_t* clusters; //!< storage for glyph clusters (index of UTF-8 code unit) + + // Helpers, since the "pos" field can be different types (always some number of floats). + SkPoint* points() const { return reinterpret_cast(pos); } + SkRSXform* xforms() const { return reinterpret_cast(pos); } + }; + + /** Returns run with storage for glyphs. Caller must write count glyphs to + RunBuffer::glyphs before next call to SkTextBlobBuilder. + + RunBuffer::pos, RunBuffer::utf8text, and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at (x, y), using font metrics to + determine their relative placement. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from (x, y) and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param x horizontal offset within the blob + @param y vertical offset within the blob + @param bounds optional run bounding box + @return writable glyph buffer + */ + const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs and positions along baseline. Caller must + write count glyphs to RunBuffer::glyphs and count scalars to RunBuffer::pos + before next call to SkTextBlobBuilder. + + RunBuffer::utf8text and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at y, using x-axis positions written by + caller to RunBuffer::pos. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param y vertical offset within the blob + @param bounds optional run bounding box + @return writable glyph buffer and x-axis position buffer + */ + const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs and SkPoint positions. Caller must + write count glyphs to RunBuffer::glyphs and count SkPoint to RunBuffer::pos + before next call to SkTextBlobBuilder. + + RunBuffer::utf8text and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using + two scalar values for each SkPoint. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param bounds optional run bounding box + @return writable glyph buffer and SkPoint buffer + */ + const RunBuffer& allocRunPos(const SkFont& font, int count, + const SkRect* bounds = nullptr); + + // RunBuffer.pos points to SkRSXform array + const RunBuffer& allocRunRSXform(const SkFont& font, int count); + + /** Returns run with storage for glyphs, text, and clusters. Caller must + write count glyphs to RunBuffer::glyphs, textByteCount UTF-8 code units + into RunBuffer::utf8text, and count monotonic indexes into utf8text + into RunBuffer::clusters before next call to SkTextBlobBuilder. + + RunBuffer::pos should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at (x, y), using font metrics to + determine their relative placement. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from (x, y) and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param x horizontal offset within the blob + @param y vertical offset within the blob + @param textByteCount number of UTF-8 code units + @param bounds optional run bounding box + @return writable glyph buffer, text buffer, and cluster buffer + */ + const RunBuffer& allocRunText(const SkFont& font, int count, SkScalar x, SkScalar y, + int textByteCount, const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs, positions along baseline, text, + and clusters. Caller must write count glyphs to RunBuffer::glyphs, + count scalars to RunBuffer::pos, textByteCount UTF-8 code units into + RunBuffer::utf8text, and count monotonic indexes into utf8text into + RunBuffer::clusters before next call to SkTextBlobBuilder. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at y, using x-axis positions written by + caller to RunBuffer::pos. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param y vertical offset within the blob + @param textByteCount number of UTF-8 code units + @param bounds optional run bounding box + @return writable glyph buffer, x-axis position buffer, text buffer, and cluster buffer + */ + const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, int textByteCount, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs, SkPoint positions, text, and + clusters. Caller must write count glyphs to RunBuffer::glyphs, count + SkPoint to RunBuffer::pos, textByteCount UTF-8 code units into + RunBuffer::utf8text, and count monotonic indexes into utf8text into + RunBuffer::clusters before next call to SkTextBlobBuilder. + + Glyphs share metrics in font. + + Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using + two scalar values for each SkPoint. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param textByteCount number of UTF-8 code units + @param bounds optional run bounding box + @return writable glyph buffer, SkPoint buffer, text buffer, and cluster buffer + */ + const RunBuffer& allocRunTextPos(const SkFont& font, int count, int textByteCount, + const SkRect* bounds = nullptr); + + // RunBuffer.pos points to SkRSXform array + const RunBuffer& allocRunTextRSXform(const SkFont& font, int count, int textByteCount, + const SkRect* bounds = nullptr); + +private: + void reserve(size_t size); + void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning, + int count, int textBytes, SkPoint offset, const SkRect* bounds); + bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning, + uint32_t count, SkPoint offset); + void updateDeferredBounds(); + + static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); + static SkRect TightRunBounds(const SkTextBlob::RunRecord&); + + friend class SkTextBlobPriv; + friend class SkTextBlobBuilderPriv; + + skia_private::AutoTMalloc fStorage; + size_t fStorageSize; + size_t fStorageUsed; + + SkRect fBounds; + int fRunCount; + bool fDeferredBounds; + size_t fLastRun; // index into fStorage + + RunBuffer fCurrentRunBuffer; +}; + +#endif // SkTextBlob_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTextureCompressionType.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTextureCompressionType.h new file mode 100644 index 00000000000000..e9b441378d0c4c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTextureCompressionType.h @@ -0,0 +1,30 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTextureCompressionType_DEFINED +#define SkTextureCompressionType_DEFINED +/* + * Skia | GL_COMPRESSED_* | MTLPixelFormat* | VK_FORMAT_*_BLOCK + * -------------------------------------------------------------------------------------- + * kETC2_RGB8_UNORM | ETC1_RGB8 | ETC2_RGB8 (iOS-only) | ETC2_R8G8B8_UNORM + * | RGB8_ETC2 | | + * -------------------------------------------------------------------------------------- + * kBC1_RGB8_UNORM | RGB_S3TC_DXT1_EXT | N/A | BC1_RGB_UNORM + * -------------------------------------------------------------------------------------- + * kBC1_RGBA8_UNORM | RGBA_S3TC_DXT1_EXT | BC1_RGBA (macOS-only)| BC1_RGBA_UNORM + */ +enum class SkTextureCompressionType { + kNone, + kETC2_RGB8_UNORM, + + kBC1_RGB8_UNORM, + kBC1_RGBA8_UNORM, + kLast = kBC1_RGBA8_UNORM, + kETC1_RGB8 = kETC2_RGB8_UNORM, +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTileMode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTileMode.h new file mode 100644 index 00000000000000..8a9d0209589daa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTileMode.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTileModes_DEFINED +#define SkTileModes_DEFINED + +#include "include/core/SkTypes.h" + +enum class SkTileMode { + /** + * Replicate the edge color if the shader draws outside of its + * original bounds. + */ + kClamp, + + /** + * Repeat the shader's image horizontally and vertically. + */ + kRepeat, + + /** + * Repeat the shader's image horizontally and vertically, alternating + * mirror images so that adjacent images always seam. + */ + kMirror, + + /** + * Only draw within the original domain, return transparent-black everywhere else. + */ + kDecal, + + kLastTileMode = kDecal, +}; + +static constexpr int kSkTileModeCount = static_cast(SkTileMode::kLastTileMode) + 1; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTime.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTime.h new file mode 100644 index 00000000000000..9135c7e113c0dc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTime.h @@ -0,0 +1,63 @@ + +/* + * 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 SkTime_DEFINED +#define SkTime_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/base/SkMacros.h" + +#include + +class SkString; + +/** \class SkTime + Platform-implemented utilities to return time of day, and millisecond counter. +*/ +class SK_API SkTime { +public: + struct DateTime { + int16_t fTimeZoneMinutes; // The number of minutes that GetDateTime() + // is ahead of or behind UTC. + uint16_t fYear; //!< e.g. 2005 + uint8_t fMonth; //!< 1..12 + uint8_t fDayOfWeek; //!< 0..6, 0==Sunday + uint8_t fDay; //!< 1..31 + uint8_t fHour; //!< 0..23 + uint8_t fMinute; //!< 0..59 + uint8_t fSecond; //!< 0..59 + + void toISO8601(SkString* dst) const; + }; + static void GetDateTime(DateTime*); + + static double GetSecs() { return GetNSecs() * 1e-9; } + static double GetMSecs() { return GetNSecs() * 1e-6; } + static double GetNSecs(); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkAutoTime { +public: + // The label is not deep-copied, so its address must remain valid for the + // lifetime of this object + SkAutoTime(const char* label = nullptr) + : fLabel(label) + , fNow(SkTime::GetMSecs()) {} + ~SkAutoTime() { + uint64_t dur = static_cast(SkTime::GetMSecs() - fNow); + SkDebugf("%s %" PRIu64 "\n", fLabel ? fLabel : "", dur); + } +private: + const char* fLabel; + double fNow; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTraceMemoryDump.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTraceMemoryDump.h new file mode 100644 index 00000000000000..7837bfbd8983c7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTraceMemoryDump.h @@ -0,0 +1,99 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTraceMemoryDump_DEFINED +#define SkTraceMemoryDump_DEFINED + +#include "include/core/SkTypes.h" + +class SkDiscardableMemory; + +/** + * Interface for memory tracing. + * This interface is meant to be passed as argument to the memory dump methods of Skia objects. + * The implementation of this interface is provided by the embedder. + */ +class SK_API SkTraceMemoryDump { +public: + /** + * Enum to specify the level of the requested details for the dump from the Skia objects. + */ + enum LevelOfDetail { + // Dump only the minimal details to get the total memory usage (Usually just the totals). + kLight_LevelOfDetail, + + // Dump the detailed breakdown of the objects in the caches. + kObjectsBreakdowns_LevelOfDetail + }; + + /** + * Appends a new memory dump (i.e. a row) to the trace memory infrastructure. + * If dumpName does not exist yet, a new one is created. Otherwise, a new column is appended to + * the previously created dump. + * Arguments: + * dumpName: an absolute, slash-separated, name for the item being dumped + * e.g., "skia/CacheX/EntryY". + * valueName: a string indicating the name of the column. + * e.g., "size", "active_size", "number_of_objects". + * This string is supposed to be long lived and is NOT copied. + * units: a string indicating the units for the value. + * e.g., "bytes", "objects". + * This string is supposed to be long lived and is NOT copied. + * value: the actual value being dumped. + */ + virtual void dumpNumericValue(const char* dumpName, + const char* valueName, + const char* units, + uint64_t value) = 0; + + virtual void dumpStringValue(const char* /*dumpName*/, + const char* /*valueName*/, + const char* /*value*/) { } + + /** + * Sets the memory backing for an existing dump. + * backingType and backingObjectId are used by the embedder to associate the memory dumped via + * dumpNumericValue with the corresponding dump that backs the memory. + */ + virtual void setMemoryBacking(const char* dumpName, + const char* backingType, + const char* backingObjectId) = 0; + + /** + * Specialization for memory backed by discardable memory. + */ + virtual void setDiscardableMemoryBacking( + const char* dumpName, + const SkDiscardableMemory& discardableMemoryObject) = 0; + + /** + * Returns the type of details requested in the dump. The granularity of the dump is supposed to + * match the LevelOfDetail argument. The level of detail must not affect the total size + * reported, but only granularity of the child entries. + */ + virtual LevelOfDetail getRequestedDetails() const = 0; + + /** + * Returns true if we should dump wrapped objects. Wrapped objects come from outside Skia, and + * may be independently tracked there. + */ + virtual bool shouldDumpWrappedObjects() const { return true; } + + /** + * If shouldDumpWrappedObjects() returns true then this function will be called to populate + * the output with information on whether the item being dumped is a wrapped object. + */ + virtual void dumpWrappedState(const char* /*dumpName*/, bool /*isWrappedObject*/) {} + +protected: + virtual ~SkTraceMemoryDump() = default; + SkTraceMemoryDump() = default; + SkTraceMemoryDump(const SkTraceMemoryDump&) = delete; + SkTraceMemoryDump& operator=(const SkTraceMemoryDump&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTypeface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTypeface.h new file mode 100644 index 00000000000000..9e099d41e37f52 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTypeface.h @@ -0,0 +1,477 @@ +/* + * 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 SkTypeface_DEFINED +#define SkTypeface_DEFINED + +#include "include/core/SkFontArguments.h" +#include "include/core/SkFontParameters.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkFontTypes.h" +#include "include/core/SkRect.h" +#include "include/core/SkString.h" +#include "include/private/SkWeakRefCnt.h" +#include "include/private/base/SkOnce.h" + +class SkData; +class SkDescriptor; +class SkFontData; +class SkFontDescriptor; +class SkScalerContext; +class SkStream; +class SkStreamAsset; +class SkWStream; +struct SkAdvancedTypefaceMetrics; +struct SkScalerContextEffects; +struct SkScalerContextRec; + +using SkTypefaceID = uint32_t; + +// SkFontID is deprecated, please use SkTypefaceID. +using SkFontID = SkTypefaceID; + + +/** Machine endian. */ +typedef uint32_t SkFontTableTag; + +/** \class SkTypeface + + The SkTypeface class specifies the typeface and intrinsic style of a font. + This is used in the paint, along with optionally algorithmic settings like + textSize, textSkewX, textScaleX, kFakeBoldText_Mask, to specify + how text appears when drawn (and measured). + + Typeface objects are immutable, and so they can be shared between threads. +*/ +class SK_API SkTypeface : public SkWeakRefCnt { +public: + /** Returns the typeface's intrinsic style attributes. */ + SkFontStyle fontStyle() const { + return fStyle; + } + + /** Returns true if style() has the kBold bit set. */ + bool isBold() const { return fStyle.weight() >= SkFontStyle::kSemiBold_Weight; } + + /** Returns true if style() has the kItalic bit set. */ + bool isItalic() const { return fStyle.slant() != SkFontStyle::kUpright_Slant; } + + /** Returns true if the typeface claims to be fixed-pitch. + * This is a style bit, advance widths may vary even if this returns true. + */ + bool isFixedPitch() const { return fIsFixedPitch; } + + /** Copy into 'coordinates' (allocated by the caller) the design variation coordinates. + * + * @param coordinates the buffer into which to write the design variation coordinates. + * @param coordinateCount the number of entries available through 'coordinates'. + * + * @return The number of axes, or -1 if there is an error. + * If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be + * filled with the variation coordinates describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual position + * cannot. + */ + int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const; + + /** Copy into 'parameters' (allocated by the caller) the design variation parameters. + * + * @param parameters the buffer into which to write the design variation parameters. + * @param coordinateCount the number of entries available through 'parameters'. + * + * @return The number of axes, or -1 if there is an error. + * If 'parameters != nullptr' and 'parameterCount >= numAxes' then 'parameters' will be + * filled with the variation parameters describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual parameters + * cannot. + */ + int getVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], + int parameterCount) const; + + /** Return a 32bit value for this typeface, unique for the underlying font + data. Will never return 0. + */ + SkTypefaceID uniqueID() const { return fUniqueID; } + + /** Return the uniqueID for the specified typeface. If the face is null, + resolve it to the default font and return its uniqueID. Will never + return 0. + */ + static SkTypefaceID UniqueID(const SkTypeface* face); + + /** Returns true if the two typefaces reference the same underlying font, + handling either being null (treating null as the default font) + */ + static bool Equal(const SkTypeface* facea, const SkTypeface* faceb); + + /** Returns the default normal typeface, which is never nullptr. */ + static sk_sp MakeDefault(); + + /** Creates a new reference to the typeface that most closely matches the + requested familyName and fontStyle. This method allows extended font + face specifiers as in the SkFontStyle type. Will never return null. + + @param familyName May be NULL. The name of the font family. + @param fontStyle The style of the typeface. + @return reference to the closest-matching typeface. Call must call + unref() when they are done. + */ + static sk_sp MakeFromName(const char familyName[], SkFontStyle fontStyle); + + /** Return a new typeface given a file. If the file does not exist, or is + not a valid font file, returns nullptr. + */ + static sk_sp MakeFromFile(const char path[], int index = 0); + + /** Return a new typeface given a stream. If the stream is + not a valid font file, returns nullptr. Ownership of the stream is + transferred, so the caller must not reference it again. + */ + static sk_sp MakeFromStream(std::unique_ptr stream, int index = 0); + + /** Return a new typeface given a SkData. If the data is null, or is not a valid font file, + * returns nullptr. + */ + static sk_sp MakeFromData(sk_sp, int index = 0); + + /** Return a new typeface based on this typeface but parameterized as specified in the + SkFontArguments. If the SkFontArguments does not supply an argument for a parameter + in the font then the value from this typeface will be used as the value for that + argument. If the cloned typeface would be exaclty the same as this typeface then + this typeface may be ref'ed and returned. May return nullptr on failure. + */ + sk_sp makeClone(const SkFontArguments&) const; + + /** + * A typeface can serialize just a descriptor (names, etc.), or it can also include the + * actual font data (which can be large). This enum controls how serialize() decides what + * to serialize. + */ + enum class SerializeBehavior { + kDoIncludeData, + kDontIncludeData, + kIncludeDataIfLocal, + }; + + /** Write a unique signature to a stream, sufficient to reconstruct a + typeface referencing the same font when Deserialize is called. + */ + void serialize(SkWStream*, SerializeBehavior = SerializeBehavior::kIncludeDataIfLocal) const; + + /** + * Same as serialize(SkWStream*, ...) but returns the serialized data in SkData, instead of + * writing it to a stream. + */ + sk_sp serialize(SerializeBehavior = SerializeBehavior::kIncludeDataIfLocal) const; + + /** Given the data previously written by serialize(), return a new instance + of a typeface referring to the same font. If that font is not available, + return nullptr. + Does not affect ownership of SkStream. + */ + static sk_sp MakeDeserialize(SkStream*); + + /** + * Given an array of UTF32 character codes, return their corresponding glyph IDs. + * + * @param chars pointer to the array of UTF32 chars + * @param number of chars and glyphs + * @param glyphs returns the corresponding glyph IDs for each character. + */ + void unicharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const; + + int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding, + SkGlyphID glyphs[], int maxGlyphCount) const; + + /** + * Return the glyphID that corresponds to the specified unicode code-point + * (in UTF32 encoding). If the unichar is not supported, returns 0. + * + * This is a short-cut for calling unicharsToGlyphs(). + */ + SkGlyphID unicharToGlyph(SkUnichar unichar) const; + + /** + * Return the number of glyphs in the typeface. + */ + int countGlyphs() const; + + // Table getters -- may fail if the underlying font format is not organized + // as 4-byte tables. + + /** Return the number of tables in the font. */ + int countTables() const; + + /** Copy into tags[] (allocated by the caller) the list of table tags in + * the font, and return the number. This will be the same as CountTables() + * or 0 if an error occured. If tags == NULL, this only returns the count + * (the same as calling countTables()). + */ + int getTableTags(SkFontTableTag tags[]) const; + + /** Given a table tag, return the size of its contents, or 0 if not present + */ + size_t getTableSize(SkFontTableTag) const; + + /** Copy the contents of a table into data (allocated by the caller). Note + * that the contents of the table will be in their native endian order + * (which for most truetype tables is big endian). If the table tag is + * not found, or there is an error copying the data, then 0 is returned. + * If this happens, it is possible that some or all of the memory pointed + * to by data may have been written to, even though an error has occured. + * + * @param tag The table tag whose contents are to be copied + * @param offset The offset in bytes into the table's contents where the + * copy should start from. + * @param length The number of bytes, starting at offset, of table data + * to copy. + * @param data storage address where the table contents are copied to + * @return the number of bytes actually copied into data. If offset+length + * exceeds the table's size, then only the bytes up to the table's + * size are actually copied, and this is the value returned. If + * offset > the table's size, or tag is not a valid table, + * then 0 is returned. + */ + size_t getTableData(SkFontTableTag tag, size_t offset, size_t length, + void* data) const; + + /** + * Return an immutable copy of the requested font table, or nullptr if that table was + * not found. This can sometimes be faster than calling getTableData() twice: once to find + * the length, and then again to copy the data. + * + * @param tag The table tag whose contents are to be copied + * @return an immutable copy of the table's data, or nullptr. + */ + sk_sp copyTableData(SkFontTableTag tag) const; + + /** + * Return the units-per-em value for this typeface, or zero if there is an + * error. + */ + int getUnitsPerEm() const; + + /** + * Given a run of glyphs, return the associated horizontal adjustments. + * Adjustments are in "design units", which are integers relative to the + * typeface's units per em (see getUnitsPerEm). + * + * Some typefaces are known to never support kerning. Calling this method + * with all zeros (e.g. getKerningPairAdustments(NULL, 0, NULL)) returns + * a boolean indicating if the typeface might support kerning. If it + * returns false, then it will always return false (no kerning) for all + * possible glyph runs. If it returns true, then it *may* return true for + * somne glyph runs. + * + * If count is non-zero, then the glyphs parameter must point to at least + * [count] valid glyph IDs, and the adjustments parameter must be + * sized to at least [count - 1] entries. If the method returns true, then + * [count-1] entries in the adjustments array will be set. If the method + * returns false, then no kerning should be applied, and the adjustments + * array will be in an undefined state (possibly some values may have been + * written, but none of them should be interpreted as valid values). + */ + bool getKerningPairAdjustments(const SkGlyphID glyphs[], int count, + int32_t adjustments[]) const; + + struct LocalizedString { + SkString fString; + SkString fLanguage; + }; + class LocalizedStrings { + public: + LocalizedStrings() = default; + virtual ~LocalizedStrings() { } + virtual bool next(LocalizedString* localizedString) = 0; + void unref() { delete this; } + + private: + LocalizedStrings(const LocalizedStrings&) = delete; + LocalizedStrings& operator=(const LocalizedStrings&) = delete; + }; + /** + * Returns an iterator which will attempt to enumerate all of the + * family names specified by the font. + * It is the caller's responsibility to unref() the returned pointer. + */ + LocalizedStrings* createFamilyNameIterator() const; + + /** + * Return the family name for this typeface. It will always be returned + * encoded as UTF8, but the language of the name is whatever the host + * platform chooses. + */ + void getFamilyName(SkString* name) const; + + /** + * Return the PostScript name for this typeface. + * Value may change based on variation parameters. + * Returns false if no PostScript name is available. + */ + bool getPostScriptName(SkString* name) const; + + /** + * Return a stream for the contents of the font data, or NULL on failure. + * If ttcIndex is not null, it is set to the TrueTypeCollection index + * of this typeface within the stream, or 0 if the stream is not a + * collection. + * The caller is responsible for deleting the stream. + */ + std::unique_ptr openStream(int* ttcIndex) const; + + /** + * Return a stream for the contents of the font data. + * Returns nullptr on failure or if the font data isn't already available in stream form. + * Use when the stream can be used opportunistically but the calling code would prefer + * to fall back to table access if creating the stream would be expensive. + * Otherwise acts the same as openStream. + */ + std::unique_ptr openExistingStream(int* ttcIndex) const; + + /** + * Return a scalercontext for the given descriptor. It may return a + * stub scalercontext that will not crash, but will draw nothing. + */ + std::unique_ptr createScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const; + + /** + * Return a rectangle (scaled to 1-pt) that represents the union of the bounds of all + * of the glyphs, but each one positioned at (0,). This may be conservatively large, and + * will not take into account any hinting or other size-specific adjustments. + */ + SkRect getBounds() const; + + // PRIVATE / EXPERIMENTAL -- do not call + void filterRec(SkScalerContextRec* rec) const { + this->onFilterRec(rec); + } + // PRIVATE / EXPERIMENTAL -- do not call + void getFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { + this->onGetFontDescriptor(desc, isLocal); + } + // PRIVATE / EXPERIMENTAL -- do not call + void* internal_private_getCTFontRef() const { + return this->onGetCTFontRef(); + } + + /* Skia reserves all tags that begin with a lower case letter and 0 */ + using FactoryId = SkFourByteTag; + static void Register( + FactoryId id, + sk_sp (*make)(std::unique_ptr, const SkFontArguments&)); + +protected: + explicit SkTypeface(const SkFontStyle& style, bool isFixedPitch = false); + ~SkTypeface() override; + + virtual sk_sp onMakeClone(const SkFontArguments&) const = 0; + + /** Sets the fixedPitch bit. If used, must be called in the constructor. */ + void setIsFixedPitch(bool isFixedPitch) { fIsFixedPitch = isFixedPitch; } + /** Sets the font style. If used, must be called in the constructor. */ + void setFontStyle(SkFontStyle style) { fStyle = style; } + + // Must return a valid scaler context. It can not return nullptr. + virtual std::unique_ptr onCreateScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const = 0; + virtual void onFilterRec(SkScalerContextRec*) const = 0; + friend class SkScalerContext; // onFilterRec + + // Subclasses *must* override this method to work with the PDF backend. + virtual std::unique_ptr onGetAdvancedMetrics() const = 0; + // For type1 postscript fonts only, set the glyph names for each glyph. + // destination array is non-null, and points to an array of size this->countGlyphs(). + // Backends that do not suport type1 fonts should not override. + virtual void getPostScriptGlyphNames(SkString*) const = 0; + + // The mapping from glyph to Unicode; array indices are glyph ids. + // For each glyph, give the default Unicode value, if it exists. + // dstArray is non-null, and points to an array of size this->countGlyphs(). + virtual void getGlyphToUnicodeMap(SkUnichar* dstArray) const = 0; + + virtual std::unique_ptr onOpenStream(int* ttcIndex) const = 0; + + virtual std::unique_ptr onOpenExistingStream(int* ttcIndex) const; + + virtual bool onGlyphMaskNeedsCurrentColor() const = 0; + + virtual int onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const = 0; + + virtual int onGetVariationDesignParameters( + SkFontParameters::Variation::Axis parameters[], int parameterCount) const = 0; + + virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; + + virtual void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const = 0; + virtual int onCountGlyphs() const = 0; + + virtual int onGetUPEM() const = 0; + virtual bool onGetKerningPairAdjustments(const SkGlyphID glyphs[], int count, + int32_t adjustments[]) const; + + /** Returns the family name of the typeface as known by its font manager. + * This name may or may not be produced by the family name iterator. + */ + virtual void onGetFamilyName(SkString* familyName) const = 0; + virtual bool onGetPostScriptName(SkString*) const = 0; + + /** Returns an iterator over the family names in the font. */ + virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0; + + virtual int onGetTableTags(SkFontTableTag tags[]) const = 0; + virtual size_t onGetTableData(SkFontTableTag, size_t offset, + size_t length, void* data) const = 0; + virtual sk_sp onCopyTableData(SkFontTableTag) const; + + virtual bool onComputeBounds(SkRect*) const; + + virtual void* onGetCTFontRef() const { return nullptr; } + +private: + /** Returns true if the typeface's glyph masks may refer to the foreground + * paint foreground color. This is needed to determine caching requirements. Usually true for + * typefaces that contain a COLR table. + */ + bool glyphMaskNeedsCurrentColor() const; + friend class SkStrikeServerImpl; // glyphMaskNeedsCurrentColor + friend class SkTypefaceProxyPrototype; // glyphMaskNeedsCurrentColor + + /** Retrieve detailed typeface metrics. Used by the PDF backend. */ + std::unique_ptr getAdvancedMetrics() const; + friend class SkRandomTypeface; // getAdvancedMetrics + friend class SkPDFFont; // getAdvancedMetrics + + /** Style specifies the intrinsic style attributes of a given typeface */ + enum Style { + kNormal = 0, + kBold = 0x01, + kItalic = 0x02, + + // helpers + kBoldItalic = 0x03 + }; + static SkFontStyle FromOldStyle(Style oldStyle); + static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal); + + friend class SkFontPriv; // GetDefaultTypeface + friend class SkPaintPriv; // GetDefaultTypeface + friend class SkFont; // getGlyphToUnicodeMap + +private: + SkTypefaceID fUniqueID; + SkFontStyle fStyle; + mutable SkRect fBounds; + mutable SkOnce fBoundsOnce; + bool fIsFixedPitch; + + using INHERITED = SkWeakRefCnt; +}; +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTypes.h new file mode 100644 index 00000000000000..5530cc4463b39f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkTypes.h @@ -0,0 +1,197 @@ +/* + * 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 SkTypes_DEFINED +#define SkTypes_DEFINED + +// All of these files should be independent of things users can set via the user config file. +// They should also be able to be included in any order. +// IWYU pragma: begin_exports +#include "include/private/base/SkFeatures.h" + +// Load and verify defines from the user config file. +#include "include/private/base/SkLoadUserConfig.h" + +// Any includes or defines below can be configured by the user config file. +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkDebug.h" +// IWYU pragma: end_exports + +#include +#include + +#if defined(SK_GANESH) || defined(SK_GRAPHITE) +# if !defined(SK_ENABLE_SKSL) +# define SK_ENABLE_SKSL +# endif +#else +# undef SK_GL +# undef SK_VULKAN +# undef SK_METAL +# undef SK_DAWN +# undef SK_DIRECT3D +#endif + +// If SK_R32_SHIFT is set, we'll use that to choose RGBA or BGRA. +// If not, we'll default to RGBA everywhere except BGRA on Windows. +#if defined(SK_R32_SHIFT) + static_assert(SK_R32_SHIFT == 0 || SK_R32_SHIFT == 16, ""); +#elif defined(SK_BUILD_FOR_WIN) + #define SK_R32_SHIFT 16 +#else + #define SK_R32_SHIFT 0 +#endif + +#if defined(SK_B32_SHIFT) + static_assert(SK_B32_SHIFT == (16-SK_R32_SHIFT), ""); +#else + #define SK_B32_SHIFT (16-SK_R32_SHIFT) +#endif + +#define SK_G32_SHIFT 8 +#define SK_A32_SHIFT 24 + +/** + * SK_PMCOLOR_BYTE_ORDER can be used to query the byte order of SkPMColor at compile time. + */ +#ifdef SK_CPU_BENDIAN +# define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C3 ## 32_SHIFT == 0 && \ + SK_ ## C2 ## 32_SHIFT == 8 && \ + SK_ ## C1 ## 32_SHIFT == 16 && \ + SK_ ## C0 ## 32_SHIFT == 24) +#else +# define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C0 ## 32_SHIFT == 0 && \ + SK_ ## C1 ## 32_SHIFT == 8 && \ + SK_ ## C2 ## 32_SHIFT == 16 && \ + SK_ ## C3 ## 32_SHIFT == 24) +#endif + +#if defined SK_DEBUG && defined SK_BUILD_FOR_WIN + #ifdef free + #undef free + #endif + #include + #undef free +#endif + +#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS + #define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 0 +#endif + +#if !defined(SK_GAMMA_EXPONENT) + #define SK_GAMMA_EXPONENT (0.0f) // SRGB +#endif + +#ifndef GR_TEST_UTILS +# define GR_TEST_UTILS 0 +#endif + + +#if defined(SK_HISTOGRAM_ENUMERATION) || \ + defined(SK_HISTOGRAM_BOOLEAN) || \ + defined(SK_HISTOGRAM_EXACT_LINEAR) || \ + defined(SK_HISTOGRAM_MEMORY_KB) +# define SK_HISTOGRAMS_ENABLED 1 +#else +# define SK_HISTOGRAMS_ENABLED 0 +#endif + +#ifndef SK_HISTOGRAM_BOOLEAN +# define SK_HISTOGRAM_BOOLEAN(name, sample) +#endif + +#ifndef SK_HISTOGRAM_ENUMERATION +# define SK_HISTOGRAM_ENUMERATION(name, sample, enum_size) +#endif + +#ifndef SK_HISTOGRAM_EXACT_LINEAR +# define SK_HISTOGRAM_EXACT_LINEAR(name, sample, value_max) +#endif + +#ifndef SK_HISTOGRAM_MEMORY_KB +# define SK_HISTOGRAM_MEMORY_KB(name, sample) +#endif + +#define SK_HISTOGRAM_PERCENTAGE(name, percent_as_int) \ + SK_HISTOGRAM_EXACT_LINEAR(name, percent_as_int, 101) + +// The top-level define SK_ENABLE_OPTIMIZE_SIZE can be used to remove several large features at once +#if defined(SK_ENABLE_OPTIMIZE_SIZE) +# define SK_FORCE_RASTER_PIPELINE_BLITTER +# define SK_DISABLE_SDF_TEXT +#endif + +#ifndef SK_DISABLE_LEGACY_SHADERCONTEXT +# define SK_ENABLE_LEGACY_SHADERCONTEXT +#endif + +#if defined(SK_BUILD_FOR_LIBFUZZER) || defined(SK_BUILD_FOR_AFL_FUZZ) +#if !defined(SK_BUILD_FOR_FUZZER) + #define SK_BUILD_FOR_FUZZER +#endif +#endif + +/** + * Gr defines are set to 0 or 1, rather than being undefined or defined + */ + +#if !defined(GR_CACHE_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) + #define GR_CACHE_STATS 1 + #else + #define GR_CACHE_STATS 0 + #endif +#endif + +#if !defined(GR_GPU_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) || GR_TEST_UTILS + #define GR_GPU_STATS 1 + #else + #define GR_GPU_STATS 0 + #endif +#endif + +//////////////////////////////////////////////////////////////////////////////// + +typedef uint32_t SkFourByteTag; +static inline constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d) { + return (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** 32 bit integer to hold a unicode value +*/ +typedef int32_t SkUnichar; + +/** 16 bit unsigned integer to hold a glyph index +*/ +typedef uint16_t SkGlyphID; + +/** 32 bit value to hold a millisecond duration + Note that SK_MSecMax is about 25 days. +*/ +typedef uint32_t SkMSec; + +/** Maximum representable milliseconds; 24d 20h 31m 23.647s. +*/ +static constexpr SkMSec SK_MSecMax = INT32_MAX; + +/** The generation IDs in Skia reserve 0 has an invalid marker. +*/ +static constexpr uint32_t SK_InvalidGenID = 0; + +/** The unique IDs in Skia reserve 0 has an invalid marker. +*/ +static constexpr uint32_t SK_InvalidUniqueID = 0; + + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkUnPreMultiply.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkUnPreMultiply.h new file mode 100644 index 00000000000000..b492619d0793c8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkUnPreMultiply.h @@ -0,0 +1,56 @@ + +/* + * Copyright 2008 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 SkUnPreMultiply_DEFINED +#define SkUnPreMultiply_DEFINED + +#include "include/core/SkColor.h" + +class SK_API SkUnPreMultiply { +public: + typedef uint32_t Scale; + + // index this table with alpha [0..255] + static const Scale* GetScaleTable() { + return gTable; + } + + static Scale GetScale(U8CPU alpha) { + SkASSERT(alpha <= 255); + return gTable[alpha]; + } + + /** Usage: + + const Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (...) { + unsigned a = ... + SkUnPreMultiply::Scale scale = table[a]; + + red = SkUnPreMultiply::ApplyScale(scale, red); + ... + // now red is unpremultiplied + } + */ + static U8CPU ApplyScale(Scale scale, U8CPU component) { + SkASSERT(component <= 255); + return (scale * component + (1 << 23)) >> 24; + } + + static SkColor PMColorToColor(SkPMColor c); + +private: + static const uint32_t gTable[256]; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkVertices.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkVertices.h new file mode 100644 index 00000000000000..2c3f784a42674b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkVertices.h @@ -0,0 +1,134 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkVertices_DEFINED +#define SkVertices_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" + +#include + +class SkData; +struct SkPoint; +class SkVerticesPriv; + +/** + * An immutable set of vertex data that can be used with SkCanvas::drawVertices. + */ +class SK_API SkVertices : public SkNVRefCnt { + struct Desc; + struct Sizes; +public: + enum VertexMode { + kTriangles_VertexMode, + kTriangleStrip_VertexMode, + kTriangleFan_VertexMode, + + kLast_VertexMode = kTriangleFan_VertexMode, + }; + + /** + * Create a vertices by copying the specified arrays. texs, colors may be nullptr, + * and indices is ignored if indexCount == 0. + */ + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + int indexCount, + const uint16_t indices[]); + + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[]) { + return MakeCopy(mode, + vertexCount, + positions, + texs, + colors, + 0, + nullptr); + } + + enum BuilderFlags { + kHasTexCoords_BuilderFlag = 1 << 0, + kHasColors_BuilderFlag = 1 << 1, + }; + class Builder { + public: + Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags); + + bool isValid() const { return fVertices != nullptr; } + + SkPoint* positions(); + uint16_t* indices(); // returns null if there are no indices + + // If we have custom attributes, these will always be null + SkPoint* texCoords(); // returns null if there are no texCoords + SkColor* colors(); // returns null if there are no colors + + // Detach the built vertices object. After the first call, this will always return null. + sk_sp detach(); + + private: + Builder(const Desc&); + + void init(const Desc&); + + // holds a partially complete object. only completed in detach() + sk_sp fVertices; + // Extra storage for intermediate vertices in the case where the client specifies indexed + // triangle fans. These get converted to indexed triangles when the Builder is finalized. + std::unique_ptr fIntermediateFanIndices; + + friend class SkVertices; + friend class SkVerticesPriv; + }; + + uint32_t uniqueID() const { return fUniqueID; } + const SkRect& bounds() const { return fBounds; } + + // returns approximate byte size of the vertices object + size_t approximateSize() const; + + // Provides access to functions that aren't part of the public API. + SkVerticesPriv priv(); + const SkVerticesPriv priv() const; // NOLINT(readability-const-return-type) + +private: + SkVertices() {} + + friend class SkVerticesPriv; + + // these are needed since we've manually sized our allocation (see Builder::init) + friend class SkNVRefCnt; + void operator delete(void* p); + + Sizes getSizes() const; + + // we store this first, to pair with the refcnt in our base-class, so we don't have an + // unnecessary pad between it and the (possibly 8-byte aligned) ptrs. + uint32_t fUniqueID; + + // these point inside our allocation, so none of these can be "freed" + SkPoint* fPositions; // [vertexCount] + uint16_t* fIndices; // [indexCount] or null + SkPoint* fTexs; // [vertexCount] or null + SkColor* fColors; // [vertexCount] or null + + SkRect fBounds; // computed to be the union of the fPositions[] + int fVertexCount; + int fIndexCount; + + VertexMode fMode; + // below here is where the actual array data is stored. +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkYUVAInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkYUVAInfo.h new file mode 100644 index 00000000000000..bbbae5d383d94a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkYUVAInfo.h @@ -0,0 +1,308 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkYUVAInfo_DEFINED +#define SkYUVAInfo_DEFINED + +#include "include/codec/SkEncodedOrigin.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" + +#include +#include +#include +#include + +/** + * Specifies the structure of planes for a YUV image with optional alpha. The actual planar data + * is not part of this structure and depending on usage is in external textures or pixmaps. + */ +class SK_API SkYUVAInfo { +public: + enum YUVAChannels { kY, kU, kV, kA, kLast = kA }; + static constexpr int kYUVAChannelCount = static_cast(YUVAChannels::kLast + 1); + + struct YUVALocation; // For internal use. + using YUVALocations = std::array; + + /** + * Specifies how YUV (and optionally A) are divided among planes. Planes are separated by + * underscores in the enum value names. Within each plane the pixmap/texture channels are + * mapped to the YUVA channels in the order specified, e.g. for kY_UV Y is in channel 0 of plane + * 0, U is in channel 0 of plane 1, and V is in channel 1 of plane 1. Channel ordering + * within a pixmap/texture given the channels it contains: + * A: 0:A + * Luminance/Gray: 0:Gray + * Luminance/Gray + Alpha: 0:Gray, 1:A + * RG 0:R, 1:G + * RGB 0:R, 1:G, 2:B + * RGBA 0:R, 1:G, 2:B, 3:A + */ + enum class PlaneConfig { + kUnknown, + + kY_U_V, ///< Plane 0: Y, Plane 1: U, Plane 2: V + kY_V_U, ///< Plane 0: Y, Plane 1: V, Plane 2: U + kY_UV, ///< Plane 0: Y, Plane 1: UV + kY_VU, ///< Plane 0: Y, Plane 1: VU + kYUV, ///< Plane 0: YUV + kUYV, ///< Plane 0: UYV + + kY_U_V_A, ///< Plane 0: Y, Plane 1: U, Plane 2: V, Plane 3: A + kY_V_U_A, ///< Plane 0: Y, Plane 1: V, Plane 2: U, Plane 3: A + kY_UV_A, ///< Plane 0: Y, Plane 1: UV, Plane 2: A + kY_VU_A, ///< Plane 0: Y, Plane 1: VU, Plane 2: A + kYUVA, ///< Plane 0: YUVA + kUYVA, ///< Plane 0: UYVA + + kLast = kUYVA + }; + + /** + * UV subsampling is also specified in the enum value names using J:a:b notation (e.g. 4:2:0 is + * 1/2 horizontal and 1/2 vertical resolution for U and V). If alpha is present it is not sub- + * sampled. Note that Subsampling values other than k444 are only valid with PlaneConfig values + * that have U and V in different planes than Y (and A, if present). + */ + enum class Subsampling { + kUnknown, + + k444, ///< No subsampling. UV values for each Y. + k422, ///< 1 set of UV values for each 2x1 block of Y values. + k420, ///< 1 set of UV values for each 2x2 block of Y values. + k440, ///< 1 set of UV values for each 1x2 block of Y values. + k411, ///< 1 set of UV values for each 4x1 block of Y values. + k410, ///< 1 set of UV values for each 4x2 block of Y values. + + kLast = k410 + }; + + /** + * Describes how subsampled chroma values are sited relative to luma values. + * + * Currently only centered siting is supported but will expand to support additional sitings. + */ + enum class Siting { + /** + * Subsampled chroma value is sited at the center of the block of corresponding luma values. + */ + kCentered, + }; + + static constexpr int kMaxPlanes = 4; + + /** ratio of Y/A values to U/V values in x and y. */ + static std::tuple SubsamplingFactors(Subsampling); + + /** + * SubsamplingFactors(Subsampling) if planedIdx refers to a U/V plane and otherwise {1, 1} if + * inputs are valid. Invalid inputs consist of incompatible PlaneConfig/Subsampling/planeIdx + * combinations. {0, 0} is returned for invalid inputs. + */ + static std::tuple PlaneSubsamplingFactors(PlaneConfig, Subsampling, int planeIdx); + + /** + * Given image dimensions, a planer configuration, subsampling, and origin, determine the + * expected size of each plane. Returns the number of expected planes. planeDimensions[0] + * through planeDimensions[] are written. The input image dimensions are as displayed + * (after the planes have been transformed to the intended display orientation). The plane + * dimensions are output as the planes are stored in memory (may be rotated from image + * dimensions). + */ + static int PlaneDimensions(SkISize imageDimensions, + PlaneConfig, + Subsampling, + SkEncodedOrigin, + SkISize planeDimensions[kMaxPlanes]); + + /** Number of planes for a given PlaneConfig. */ + static constexpr int NumPlanes(PlaneConfig); + + /** + * Number of Y, U, V, A channels in the ith plane for a given PlaneConfig (or 0 if i is + * invalid). + */ + static constexpr int NumChannelsInPlane(PlaneConfig, int i); + + /** + * Given a PlaneConfig and a set of channel flags for each plane, convert to YUVALocations + * representation. Fails if channel flags aren't valid for the PlaneConfig (i.e. don't have + * enough channels in a plane) by returning an invalid set of locations (plane indices are -1). + */ + static YUVALocations GetYUVALocations(PlaneConfig, const uint32_t* planeChannelFlags); + + /** Does the PlaneConfig have alpha values? */ + static bool HasAlpha(PlaneConfig); + + SkYUVAInfo() = default; + SkYUVAInfo(const SkYUVAInfo&) = default; + + /** + * 'dimensions' should specify the size of the full resolution image (after planes have been + * oriented to how the image is displayed as indicated by 'origin'). + */ + SkYUVAInfo(SkISize dimensions, + PlaneConfig, + Subsampling, + SkYUVColorSpace, + SkEncodedOrigin origin = kTopLeft_SkEncodedOrigin, + Siting sitingX = Siting::kCentered, + Siting sitingY = Siting::kCentered); + + SkYUVAInfo& operator=(const SkYUVAInfo& that) = default; + + PlaneConfig planeConfig() const { return fPlaneConfig; } + Subsampling subsampling() const { return fSubsampling; } + + std::tuple planeSubsamplingFactors(int planeIdx) const { + return PlaneSubsamplingFactors(fPlaneConfig, fSubsampling, planeIdx); + } + + /** + * Dimensions of the full resolution image (after planes have been oriented to how the image + * is displayed as indicated by fOrigin). + */ + SkISize dimensions() const { return fDimensions; } + int width() const { return fDimensions.width(); } + int height() const { return fDimensions.height(); } + + SkYUVColorSpace yuvColorSpace() const { return fYUVColorSpace; } + Siting sitingX() const { return fSitingX; } + Siting sitingY() const { return fSitingY; } + + SkEncodedOrigin origin() const { return fOrigin; } + + SkMatrix originMatrix() const { + return SkEncodedOriginToMatrix(fOrigin, this->width(), this->height()); + } + + bool hasAlpha() const { return HasAlpha(fPlaneConfig); } + + /** + * Returns the number of planes and initializes planeDimensions[0]..planeDimensions[] to + * the expected dimensions for each plane. Dimensions are as stored in memory, before + * transformation to image display space as indicated by origin(). + */ + int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const { + return PlaneDimensions(fDimensions, fPlaneConfig, fSubsampling, fOrigin, planeDimensions); + } + + /** + * Given a per-plane row bytes, determine size to allocate for all planes. Optionally retrieves + * the per-plane byte sizes in planeSizes if not null. If total size overflows will return + * SIZE_MAX and set all planeSizes to SIZE_MAX. + */ + size_t computeTotalBytes(const size_t rowBytes[kMaxPlanes], + size_t planeSizes[kMaxPlanes] = nullptr) const; + + int numPlanes() const { return NumPlanes(fPlaneConfig); } + + int numChannelsInPlane(int i) const { return NumChannelsInPlane(fPlaneConfig, i); } + + /** + * Given a set of channel flags for each plane, converts this->planeConfig() to YUVALocations + * representation. Fails if the channel flags aren't valid for the PlaneConfig (i.e. don't have + * enough channels in a plane) by returning default initialized locations (all plane indices are + * -1). + */ + YUVALocations toYUVALocations(const uint32_t* channelFlags) const; + + /** + * Makes a SkYUVAInfo that is identical to this one but with the passed Subsampling. If the + * passed Subsampling is not k444 and this info's PlaneConfig is not compatible with chroma + * subsampling (because Y is in the same plane as UV) then the result will be an invalid + * SkYUVAInfo. + */ + SkYUVAInfo makeSubsampling(SkYUVAInfo::Subsampling) const; + + /** + * Makes a SkYUVAInfo that is identical to this one but with the passed dimensions. If the + * passed dimensions is empty then the result will be an invalid SkYUVAInfo. + */ + SkYUVAInfo makeDimensions(SkISize) const; + + bool operator==(const SkYUVAInfo& that) const; + bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); } + + bool isValid() const { return fPlaneConfig != PlaneConfig::kUnknown; } + +private: + SkISize fDimensions = {0, 0}; + + PlaneConfig fPlaneConfig = PlaneConfig::kUnknown; + Subsampling fSubsampling = Subsampling::kUnknown; + + SkYUVColorSpace fYUVColorSpace = SkYUVColorSpace::kIdentity_SkYUVColorSpace; + + /** + * YUVA data often comes from formats like JPEG that support EXIF orientation. + * Code that operates on the raw YUV data often needs to know that orientation. + */ + SkEncodedOrigin fOrigin = kTopLeft_SkEncodedOrigin; + + Siting fSitingX = Siting::kCentered; + Siting fSitingY = Siting::kCentered; +}; + +constexpr int SkYUVAInfo::NumPlanes(PlaneConfig planeConfig) { + switch (planeConfig) { + case PlaneConfig::kUnknown: return 0; + case PlaneConfig::kY_U_V: return 3; + case PlaneConfig::kY_V_U: return 3; + case PlaneConfig::kY_UV: return 2; + case PlaneConfig::kY_VU: return 2; + case PlaneConfig::kYUV: return 1; + case PlaneConfig::kUYV: return 1; + case PlaneConfig::kY_U_V_A: return 4; + case PlaneConfig::kY_V_U_A: return 4; + case PlaneConfig::kY_UV_A: return 3; + case PlaneConfig::kY_VU_A: return 3; + case PlaneConfig::kYUVA: return 1; + case PlaneConfig::kUYVA: return 1; + } + SkUNREACHABLE; +} + +constexpr int SkYUVAInfo::NumChannelsInPlane(PlaneConfig config, int i) { + switch (config) { + case PlaneConfig::kUnknown: + return 0; + + case SkYUVAInfo::PlaneConfig::kY_U_V: + case SkYUVAInfo::PlaneConfig::kY_V_U: + return i >= 0 && i < 3 ? 1 : 0; + case SkYUVAInfo::PlaneConfig::kY_UV: + case SkYUVAInfo::PlaneConfig::kY_VU: + switch (i) { + case 0: return 1; + case 1: return 2; + default: return 0; + } + case SkYUVAInfo::PlaneConfig::kYUV: + case SkYUVAInfo::PlaneConfig::kUYV: + return i == 0 ? 3 : 0; + case SkYUVAInfo::PlaneConfig::kY_U_V_A: + case SkYUVAInfo::PlaneConfig::kY_V_U_A: + return i >= 0 && i < 4 ? 1 : 0; + case SkYUVAInfo::PlaneConfig::kY_UV_A: + case SkYUVAInfo::PlaneConfig::kY_VU_A: + switch (i) { + case 0: return 1; + case 1: return 2; + case 2: return 1; + default: return 0; + } + case SkYUVAInfo::PlaneConfig::kYUVA: + case SkYUVAInfo::PlaneConfig::kUYVA: + return i == 0 ? 4 : 0; + } + return 0; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkYUVAPixmaps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkYUVAPixmaps.h new file mode 100644 index 00000000000000..2ecb9005df1afc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/core/SkYUVAPixmaps.h @@ -0,0 +1,342 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkYUVAPixmaps_DEFINED +#define SkYUVAPixmaps_DEFINED + +#include "include/core/SkColorType.h" +#include "include/core/SkData.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/core/SkYUVAInfo.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include + +class GrImageContext; + +/** + * SkYUVAInfo combined with per-plane SkColorTypes and row bytes. Fully specifies the SkPixmaps + * for a YUVA image without the actual pixel memory and data. + */ +class SK_API SkYUVAPixmapInfo { +public: + static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; + + using PlaneConfig = SkYUVAInfo::PlaneConfig; + using Subsampling = SkYUVAInfo::Subsampling; + + /** + * Data type for Y, U, V, and possibly A channels independent of how values are packed into + * planes. + **/ + enum class DataType { + kUnorm8, ///< 8 bit unsigned normalized + kUnorm16, ///< 16 bit unsigned normalized + kFloat16, ///< 16 bit (half) floating point + kUnorm10_Unorm2, ///< 10 bit unorm for Y, U, and V. 2 bit unorm for alpha (if present). + + kLast = kUnorm10_Unorm2 + }; + static constexpr int kDataTypeCnt = static_cast(DataType::kLast) + 1; + + class SK_API SupportedDataTypes { + public: + /** Defaults to nothing supported. */ + constexpr SupportedDataTypes() = default; + + /** Init based on texture formats supported by the context. */ + SupportedDataTypes(const GrImageContext&); + + /** All legal combinations of PlaneConfig and DataType are supported. */ + static constexpr SupportedDataTypes All(); + + /** + * Checks whether there is a supported combination of color types for planes structured + * as indicated by PlaneConfig with channel data types as indicated by DataType. + */ + constexpr bool supported(PlaneConfig, DataType) const; + + /** + * Update to add support for pixmaps with numChannel channels where each channel is + * represented as DataType. + */ + void enableDataType(DataType, int numChannels); + + private: + // The bit for DataType dt with n channels is at index kDataTypeCnt*(n-1) + dt. + std::bitset fDataTypeSupport = {}; + }; + + /** + * Gets the default SkColorType to use with numChannels channels, each represented as DataType. + * Returns kUnknown_SkColorType if no such color type. + */ + static constexpr SkColorType DefaultColorTypeForDataType(DataType dataType, int numChannels); + + /** + * If the SkColorType is supported for YUVA pixmaps this will return the number of YUVA channels + * that can be stored in a plane of this color type and what the DataType is of those channels. + * If the SkColorType is not supported as a YUVA plane the number of channels is reported as 0 + * and the DataType returned should be ignored. + */ + static std::tuple NumChannelsAndDataType(SkColorType); + + /** Default SkYUVAPixmapInfo is invalid. */ + SkYUVAPixmapInfo() = default; + + /** + * Initializes the SkYUVAPixmapInfo from a SkYUVAInfo with per-plane color types and row bytes. + * This will be invalid if the colorTypes aren't compatible with the SkYUVAInfo or if a + * rowBytes entry is not valid for the plane dimensions and color type. Color type and + * row byte values beyond the number of planes in SkYUVAInfo are ignored. All SkColorTypes + * must have the same DataType or this will be invalid. + * + * If rowBytes is nullptr then bpp*width is assumed for each plane. + */ + SkYUVAPixmapInfo(const SkYUVAInfo&, + const SkColorType[kMaxPlanes], + const size_t rowBytes[kMaxPlanes]); + /** + * Like above but uses DefaultColorTypeForDataType to determine each plane's SkColorType. If + * rowBytes is nullptr then bpp*width is assumed for each plane. + */ + SkYUVAPixmapInfo(const SkYUVAInfo&, DataType, const size_t rowBytes[kMaxPlanes]); + + SkYUVAPixmapInfo(const SkYUVAPixmapInfo&) = default; + + SkYUVAPixmapInfo& operator=(const SkYUVAPixmapInfo&) = default; + + bool operator==(const SkYUVAPixmapInfo&) const; + bool operator!=(const SkYUVAPixmapInfo& that) const { return !(*this == that); } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); } + + /** The number of SkPixmap planes, 0 if this SkYUVAPixmapInfo is invalid. */ + int numPlanes() const { return fYUVAInfo.numPlanes(); } + + /** The per-YUV[A] channel data type. */ + DataType dataType() const { return fDataType; } + + /** + * Row bytes for the ith plane. Returns zero if i >= numPlanes() or this SkYUVAPixmapInfo is + * invalid. + */ + size_t rowBytes(int i) const { return fRowBytes[static_cast(i)]; } + + /** Image info for the ith plane, or default SkImageInfo if i >= numPlanes() */ + const SkImageInfo& planeInfo(int i) const { return fPlaneInfos[static_cast(i)]; } + + /** + * Determine size to allocate for all planes. Optionally retrieves the per-plane sizes in + * planeSizes if not null. If total size overflows will return SIZE_MAX and set all planeSizes + * to SIZE_MAX. Returns 0 and fills planesSizes with 0 if this SkYUVAPixmapInfo is not valid. + */ + size_t computeTotalBytes(size_t planeSizes[kMaxPlanes] = nullptr) const; + + /** + * Takes an allocation that is assumed to be at least computeTotalBytes() in size and configures + * the first numPlanes() entries in pixmaps array to point into that memory. The remaining + * entries of pixmaps are default initialized. Fails if this SkYUVAPixmapInfo not valid. + */ + bool initPixmapsFromSingleAllocation(void* memory, SkPixmap pixmaps[kMaxPlanes]) const; + + /** + * Returns true if this has been configured with a non-empty dimensioned SkYUVAInfo with + * compatible color types and row bytes. + */ + bool isValid() const { return fYUVAInfo.isValid(); } + + /** Is this valid and does it use color types allowed by the passed SupportedDataTypes? */ + bool isSupported(const SupportedDataTypes&) const; + +private: + SkYUVAInfo fYUVAInfo; + std::array fPlaneInfos = {}; + std::array fRowBytes = {}; + DataType fDataType = DataType::kUnorm8; + static_assert(kUnknown_SkColorType == 0, "default init isn't kUnknown"); +}; + +/** + * Helper to store SkPixmap planes as described by a SkYUVAPixmapInfo. Can be responsible for + * allocating/freeing memory for pixmaps or use external memory. + */ +class SK_API SkYUVAPixmaps { +public: + using DataType = SkYUVAPixmapInfo::DataType; + static constexpr auto kMaxPlanes = SkYUVAPixmapInfo::kMaxPlanes; + + static SkColorType RecommendedRGBAColorType(DataType); + + /** Allocate space for pixmaps' pixels in the SkYUVAPixmaps. */ + static SkYUVAPixmaps Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo); + + /** + * Use storage in SkData as backing store for pixmaps' pixels. SkData is retained by the + * SkYUVAPixmaps. + */ + static SkYUVAPixmaps FromData(const SkYUVAPixmapInfo&, sk_sp); + + /** + * Makes a deep copy of the src SkYUVAPixmaps. The returned SkYUVAPixmaps owns its planes' + * backing stores. + */ + static SkYUVAPixmaps MakeCopy(const SkYUVAPixmaps& src); + + /** + * Use passed in memory as backing store for pixmaps' pixels. Caller must ensure memory remains + * allocated while pixmaps are in use. There must be at least + * SkYUVAPixmapInfo::computeTotalBytes() allocated starting at memory. + */ + static SkYUVAPixmaps FromExternalMemory(const SkYUVAPixmapInfo&, void* memory); + + /** + * Wraps existing SkPixmaps. The SkYUVAPixmaps will have no ownership of the SkPixmaps' pixel + * memory so the caller must ensure it remains valid. Will return an invalid SkYUVAPixmaps if + * the SkYUVAInfo isn't compatible with the SkPixmap array (number of planes, plane dimensions, + * sufficient color channels in planes, ...). + */ + static SkYUVAPixmaps FromExternalPixmaps(const SkYUVAInfo&, const SkPixmap[kMaxPlanes]); + + /** Default SkYUVAPixmaps is invalid. */ + SkYUVAPixmaps() = default; + ~SkYUVAPixmaps() = default; + + SkYUVAPixmaps(SkYUVAPixmaps&& that) = default; + SkYUVAPixmaps& operator=(SkYUVAPixmaps&& that) = default; + SkYUVAPixmaps(const SkYUVAPixmaps&) = default; + SkYUVAPixmaps& operator=(const SkYUVAPixmaps& that) = default; + + /** Does have initialized pixmaps compatible with its SkYUVAInfo. */ + bool isValid() const { return !fYUVAInfo.dimensions().isEmpty(); } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + DataType dataType() const { return fDataType; } + + SkYUVAPixmapInfo pixmapsInfo() const; + + /** Number of pixmap planes or 0 if this SkYUVAPixmaps is invalid. */ + int numPlanes() const { return this->isValid() ? fYUVAInfo.numPlanes() : 0; } + + /** + * Access the SkPixmap planes. They are default initialized if this is not a valid + * SkYUVAPixmaps. + */ + const std::array& planes() const { return fPlanes; } + + /** + * Get the ith SkPixmap plane. SkPixmap will be default initialized if i >= numPlanes or this + * SkYUVAPixmaps is invalid. + */ + const SkPixmap& plane(int i) const { return fPlanes[SkToSizeT(i)]; } + + /** + * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be + * valid if this->isValid(). + */ + SkYUVAInfo::YUVALocations toYUVALocations() const; + + /** Does this SkPixmaps own the backing store of the planes? */ + bool ownsStorage() const { return SkToBool(fData); } + +private: + SkYUVAPixmaps(const SkYUVAPixmapInfo&, sk_sp); + SkYUVAPixmaps(const SkYUVAInfo&, DataType, const SkPixmap[kMaxPlanes]); + + std::array fPlanes = {}; + sk_sp fData; + SkYUVAInfo fYUVAInfo; + DataType fDataType; +}; + +////////////////////////////////////////////////////////////////////////////// + +constexpr SkYUVAPixmapInfo::SupportedDataTypes SkYUVAPixmapInfo::SupportedDataTypes::All() { + using ULL = unsigned long long; // bitset cons. takes this. + ULL bits = 0; + for (ULL c = 1; c <= 4; ++c) { + for (ULL dt = 0; dt <= ULL(kDataTypeCnt); ++dt) { + if (DefaultColorTypeForDataType(static_cast(dt), + static_cast(c)) != kUnknown_SkColorType) { + bits |= ULL(1) << (dt + static_cast(kDataTypeCnt)*(c - 1)); + } + } + } + SupportedDataTypes combinations; + combinations.fDataTypeSupport = bits; + return combinations; +} + +constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlaneConfig config, + DataType type) const { + int n = SkYUVAInfo::NumPlanes(config); + for (int i = 0; i < n; ++i) { + auto c = static_cast(SkYUVAInfo::NumChannelsInPlane(config, i)); + SkASSERT(c >= 1 && c <= 4); + if (!fDataTypeSupport[static_cast(type) + + (c - 1)*static_cast(kDataTypeCnt)]) { + return false; + } + } + return true; +} + +constexpr SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType, + int numChannels) { + switch (numChannels) { + case 1: + switch (dataType) { + case DataType::kUnorm8: return kGray_8_SkColorType; + case DataType::kUnorm16: return kA16_unorm_SkColorType; + case DataType::kFloat16: return kA16_float_SkColorType; + case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType; + } + break; + case 2: + switch (dataType) { + case DataType::kUnorm8: return kR8G8_unorm_SkColorType; + case DataType::kUnorm16: return kR16G16_unorm_SkColorType; + case DataType::kFloat16: return kR16G16_float_SkColorType; + case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType; + } + break; + case 3: + // None of these are tightly packed. The intended use case is for interleaved YUVA + // planes where we're forcing opaqueness by ignoring the alpha values. + // There are "x" rather than "A" variants for Unorm8 and Unorm10_Unorm2 but we don't + // choose them because 1) there is no inherent advantage and 2) there is better support + // in the GPU backend for the "A" versions. + switch (dataType) { + case DataType::kUnorm8: return kRGBA_8888_SkColorType; + case DataType::kUnorm16: return kR16G16B16A16_unorm_SkColorType; + case DataType::kFloat16: return kRGBA_F16_SkColorType; + case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType; + } + break; + case 4: + switch (dataType) { + case DataType::kUnorm8: return kRGBA_8888_SkColorType; + case DataType::kUnorm16: return kR16G16B16A16_unorm_SkColorType; + case DataType::kFloat16: return kRGBA_F16_SkColorType; + case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType; + } + break; + } + return kUnknown_SkColorType; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/docs/SkPDFDocument.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/docs/SkPDFDocument.h new file mode 100644 index 00000000000000..16e953be5e5edf --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/docs/SkPDFDocument.h @@ -0,0 +1,202 @@ +// Copyright 2018 Google LLC. +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +#ifndef SkPDFDocument_DEFINED +#define SkPDFDocument_DEFINED + +#include "include/core/SkDocument.h" + +#include + +#include "include/core/SkColor.h" +#include "include/core/SkMilestone.h" +#include "include/core/SkScalar.h" +#include "include/core/SkString.h" +#include "include/core/SkTime.h" +#include "include/private/base/SkNoncopyable.h" + +#define SKPDF_STRING(X) SKPDF_STRING_IMPL(X) +#define SKPDF_STRING_IMPL(X) #X + +class SkExecutor; +class SkPDFArray; +class SkPDFTagTree; + +namespace SkPDF { + +/** Attributes for nodes in the PDF tree. */ +class SK_API AttributeList : SkNoncopyable { +public: + AttributeList(); + ~AttributeList(); + + // Each attribute must have an owner (e.g. "Layout", "List", "Table", etc) + // and an attribute name (e.g. "BBox", "RowSpan", etc.) from PDF32000_2008 14.8.5, + // and then a value of the proper type according to the spec. + void appendInt(const char* owner, const char* name, int value); + void appendFloat(const char* owner, const char* name, float value); + void appendName(const char* owner, const char* attrName, const char* value); + void appendFloatArray(const char* owner, + const char* name, + const std::vector& value); + void appendNodeIdArray(const char* owner, + const char* attrName, + const std::vector& nodeIds); + +private: + friend class ::SkPDFTagTree; + + std::unique_ptr fAttrs; +}; + +/** A node in a PDF structure tree, giving a semantic representation + of the content. Each node ID is associated with content + by passing the SkCanvas and node ID to SkPDF::SetNodeId() when drawing. + NodeIDs should be unique within each tree. +*/ +struct StructureElementNode { + SkString fTypeString; + std::vector> fChildVector; + int fNodeId = 0; + std::vector fAdditionalNodeIds; + AttributeList fAttributes; + SkString fAlt; + SkString fLang; +}; + +/** Optional metadata to be passed into the PDF factory function. +*/ +struct Metadata { + /** The document's title. + */ + SkString fTitle; + + /** The name of the person who created the document. + */ + SkString fAuthor; + + /** The subject of the document. + */ + SkString fSubject; + + /** Keywords associated with the document. Commas may be used to delineate + keywords within the string. + */ + SkString fKeywords; + + /** If the document was converted to PDF from another format, + the name of the conforming product that created the + original document from which it was converted. + */ + SkString fCreator; + + /** The product that is converting this document to PDF. + */ + SkString fProducer = SkString("Skia/PDF m" SKPDF_STRING(SK_MILESTONE)); + + /** The date and time the document was created. + The zero default value represents an unknown/unset time. + */ + SkTime::DateTime fCreation = {0, 0, 0, 0, 0, 0, 0, 0}; + + /** The date and time the document was most recently modified. + The zero default value represents an unknown/unset time. + */ + SkTime::DateTime fModified = {0, 0, 0, 0, 0, 0, 0, 0}; + + /** The DPI (pixels-per-inch) at which features without native PDF support + will be rasterized (e.g. draw image with perspective, draw text with + perspective, ...) A larger DPI would create a PDF that reflects the + original intent with better fidelity, but it can make for larger PDF + files too, which would use more memory while rendering, and it would be + slower to be processed or sent online or to printer. + */ + SkScalar fRasterDPI = SK_ScalarDefaultRasterDPI; + + /** If true, include XMP metadata, a document UUID, and sRGB output intent + information. This adds length to the document and makes it + non-reproducable, but are necessary features for PDF/A-2b conformance + */ + bool fPDFA = false; + + /** Encoding quality controls the trade-off between size and quality. By + default this is set to 101 percent, which corresponds to lossless + encoding. If this value is set to a value <= 100, and the image is + opaque, it will be encoded (using JPEG) with that quality setting. + */ + int fEncodingQuality = 101; + + /** An optional tree of structured document tags that provide + a semantic representation of the content. The caller + should retain ownership. + */ + StructureElementNode* fStructureElementTreeRoot = nullptr; + + /** Executor to handle threaded work within PDF Backend. If this is nullptr, + then all work will be done serially on the main thread. To have worker + threads assist with various tasks, set this to a valid SkExecutor + instance. Currently used for executing Deflate algorithm in parallel. + + If set, the PDF output will be non-reproducible in the order and + internal numbering of objects, but should render the same. + + Experimental. + */ + SkExecutor* fExecutor = nullptr; + + /** PDF streams may be compressed to save space. + Use this to specify the desired compression vs time tradeoff. + */ + enum class CompressionLevel : int { + Default = -1, + None = 0, + LowButFast = 1, + Average = 6, + HighButSlow = 9, + } fCompressionLevel = CompressionLevel::Default; + + /** Preferred Subsetter. Only respected if both are compiled in. + + The Sfntly subsetter is deprecated. + + Experimental. + */ + enum Subsetter { + kHarfbuzz_Subsetter, + kSfntly_Subsetter, + } fSubsetter = kHarfbuzz_Subsetter; +}; + +/** Associate a node ID with subsequent drawing commands in an + SkCanvas. The same node ID can appear in a StructureElementNode + in order to associate a document's structure element tree with + its content. + + A node ID of zero indicates no node ID. + + @param canvas The canvas used to draw to the PDF. + @param nodeId The node ID for subsequent drawing commands. +*/ +SK_API void SetNodeId(SkCanvas* dst, int nodeID); + +/** Create a PDF-backed document, writing the results into a SkWStream. + + PDF pages are sized in point units. 1 pt == 1/72 inch == 127/360 mm. + + @param stream A PDF document will be written to this stream. The document may write + to the stream at anytime during its lifetime, until either close() is + called or the document is deleted. + @param metadata a PDFmetadata object. Any fields may be left empty. + + @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument. +*/ +SK_API sk_sp MakeDocument(SkWStream* stream, const Metadata& metadata); + +static inline sk_sp MakeDocument(SkWStream* stream) { + return MakeDocument(stream, Metadata()); +} + +} // namespace SkPDF + +#undef SKPDF_STRING +#undef SKPDF_STRING_IMPL +#endif // SkPDFDocument_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/docs/SkXPSDocument.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/docs/SkXPSDocument.h new file mode 100644 index 00000000000000..5cd0777c9b17c7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/docs/SkXPSDocument.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkXPSDocument_DEFINED +#define SkXPSDocument_DEFINED + +#include "include/core/SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN + +#include "include/core/SkDocument.h" + +struct IXpsOMObjectFactory; + +namespace SkXPS { + +SK_API sk_sp MakeDocument(SkWStream* stream, + IXpsOMObjectFactory* xpsFactory, + SkScalar dpi = SK_ScalarDefaultRasterDPI); + +} // namespace SkXPS +#endif // SK_BUILD_FOR_WIN +#endif // SkXPSDocument_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/Sk1DPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/Sk1DPathEffect.h new file mode 100644 index 00000000000000..fd05c52df7c8b9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/Sk1DPathEffect.h @@ -0,0 +1,40 @@ +/* + * 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 Sk1DPathEffect_DEFINED +#define Sk1DPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPath; +class SkPathEffect; + +class SK_API SkPath1DPathEffect { +public: + enum Style { + kTranslate_Style, // translate the shape to each position + kRotate_Style, // rotate the shape about its center + kMorph_Style, // transform each point, and turn lines into curves + + kLastEnum_Style = kMorph_Style, + }; + + /** Dash by replicating the specified path. + @param path The path to replicate (dash) + @param advance The space between instances of path + @param phase distance (mod advance) along path for its initial position + @param style how to transform path at each point (based on the current + position and tangent) + */ + static sk_sp Make(const SkPath& path, SkScalar advance, SkScalar phase, Style); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/Sk2DPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/Sk2DPathEffect.h new file mode 100644 index 00000000000000..b8b3ba39817b4c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/Sk2DPathEffect.h @@ -0,0 +1,33 @@ +/* + * 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 Sk2DPathEffect_DEFINED +#define Sk2DPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkMatrix; +class SkPath; +class SkPathEffect; + +class SK_API SkLine2DPathEffect { +public: + static sk_sp Make(SkScalar width, const SkMatrix& matrix); + + static void RegisterFlattenables(); +}; + +class SK_API SkPath2DPathEffect { +public: + static sk_sp Make(const SkMatrix& matrix, const SkPath& path); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlenders.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlenders.h new file mode 100644 index 00000000000000..7507071b056135 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlenders.h @@ -0,0 +1,27 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlenders_DEFINED +#define SkBlenders_DEFINED + +#include "include/core/SkBlender.h" + +class SK_API SkBlenders { +public: + /** + * Create a blender that implements the following: + * k1 * src * dst + k2 * src + k3 * dst + k4 + * @param k1, k2, k3, k4 The four coefficients. + * @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha. + */ + static sk_sp Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul); + +private: + SkBlenders() = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlurDrawLooper.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlurDrawLooper.h new file mode 100644 index 00000000000000..fc766f807aa47f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlurDrawLooper.h @@ -0,0 +1,26 @@ +/* + * Copyright 2008 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 SkBlurDrawLooper_DEFINED +#define SkBlurDrawLooper_DEFINED + +#include "include/core/SkDrawLooper.h" + +#ifndef SK_SUPPORT_LEGACY_DRAWLOOPER +#error "SkDrawLooper is unsupported" +#endif + +/** + * DEPRECATED: No longer supported in Skia. + */ +namespace SkBlurDrawLooper { + sk_sp SK_API Make(SkColor4f color, SkColorSpace* cs, + SkScalar sigma, SkScalar dx, SkScalar dy); + sk_sp SK_API Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy); +} // namespace SkBlurDrawLooper + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlurMaskFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlurMaskFilter.h new file mode 100644 index 00000000000000..1b9319869ed8ed --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkBlurMaskFilter.h @@ -0,0 +1,35 @@ +/* + * 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 SkBlurMaskFilter_DEFINED +#define SkBlurMaskFilter_DEFINED + +// we include this since our callers will need to at least be able to ref/unref +#include "include/core/SkBlurTypes.h" +#include "include/core/SkMaskFilter.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" + +class SkRRect; + +class SK_API SkBlurMaskFilter { +public: +#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER + /** Create an emboss maskfilter + @param blurSigma standard deviation of the Gaussian blur to apply + before applying lighting (e.g. 3) + @param direction array of 3 scalars [x, y, z] specifying the direction of the light source + @param ambient 0...1 amount of ambient light + @param specular coefficient for specular highlights (e.g. 8) + @return the emboss maskfilter + */ + static sk_sp MakeEmboss(SkScalar blurSigma, const SkScalar direction[3], + SkScalar ambient, SkScalar specular); +#endif +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkColorMatrix.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkColorMatrix.h new file mode 100644 index 00000000000000..5092278f0def35 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkColorMatrix.h @@ -0,0 +1,57 @@ +/* + * Copyright 2007 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 SkColorMatrix_DEFINED +#define SkColorMatrix_DEFINED + +#include "include/core/SkTypes.h" + +#include +#include + +enum SkYUVColorSpace : int; + +class SK_API SkColorMatrix { +public: + constexpr SkColorMatrix() : SkColorMatrix(1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0) {} + + constexpr SkColorMatrix(float m00, float m01, float m02, float m03, float m04, + float m10, float m11, float m12, float m13, float m14, + float m20, float m21, float m22, float m23, float m24, + float m30, float m31, float m32, float m33, float m34) + : fMat { m00, m01, m02, m03, m04, + m10, m11, m12, m13, m14, + m20, m21, m22, m23, m24, + m30, m31, m32, m33, m34 } {} + + static SkColorMatrix RGBtoYUV(SkYUVColorSpace); + static SkColorMatrix YUVtoRGB(SkYUVColorSpace); + + void setIdentity(); + void setScale(float rScale, float gScale, float bScale, float aScale = 1.0f); + + void postTranslate(float dr, float dg, float db, float da); + + void setConcat(const SkColorMatrix& a, const SkColorMatrix& b); + void preConcat(const SkColorMatrix& mat) { this->setConcat(*this, mat); } + void postConcat(const SkColorMatrix& mat) { this->setConcat(mat, *this); } + + void setSaturation(float sat); + + void setRowMajor(const float src[20]) { std::copy_n(src, 20, fMat.begin()); } + void getRowMajor(float dst[20]) const { std::copy_n(fMat.begin(), 20, dst); } + +private: + std::array fMat; + + friend class SkColorFilters; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkColorMatrixFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkColorMatrixFilter.h new file mode 100644 index 00000000000000..3e5337b0cf94a2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkColorMatrixFilter.h @@ -0,0 +1,22 @@ +/* + * Copyright 2007 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 SkColorMatrixFilter_DEFINED +#define SkColorMatrixFilter_DEFINED + +#include "include/core/SkColorFilter.h" + +// (DEPRECATED) This factory function is deprecated. Please use the one in +// SkColorFilters (i.e., Lighting). +class SK_API SkColorMatrixFilter : public SkColorFilter { +public: + static sk_sp MakeLightingFilter(SkColor mul, SkColor add) { + return SkColorFilters::Lighting(mul, add); + } +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkCornerPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkCornerPathEffect.h new file mode 100644 index 00000000000000..7f7e7159f3fba3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkCornerPathEffect.h @@ -0,0 +1,32 @@ +/* + * 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 SkCornerPathEffect_DEFINED +#define SkCornerPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPathEffect; + +/** \class SkCornerPathEffect + + SkCornerPathEffect is a subclass of SkPathEffect that can turn sharp corners + into various treatments (e.g. rounded corners) +*/ +class SK_API SkCornerPathEffect { +public: + /** radius must be > 0 to have an effect. It specifies the distance from each corner + that should be "rounded". + */ + static sk_sp Make(SkScalar radius); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkDashPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkDashPathEffect.h new file mode 100644 index 00000000000000..f30064aa9476f9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkDashPathEffect.h @@ -0,0 +1,43 @@ +/* + * 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 SkDashPathEffect_DEFINED +#define SkDashPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPathEffect; + +class SK_API SkDashPathEffect { +public: + /** intervals: array containing an even number of entries (>=2), with + the even indices specifying the length of "on" intervals, and the odd + indices specifying the length of "off" intervals. This array will be + copied in Make, and can be disposed of freely after. + count: number of elements in the intervals array + phase: offset into the intervals array (mod the sum of all of the + intervals). + + For example: if intervals[] = {10, 20}, count = 2, and phase = 25, + this will set up a dashed path like so: + 5 pixels off + 10 pixels on + 20 pixels off + 10 pixels on + 20 pixels off + ... + A phase of -5, 25, 55, 85, etc. would all result in the same path, + because the sum of all the intervals is 30. + + Note: only affects stroked paths. + */ + static sk_sp Make(const SkScalar intervals[], int count, SkScalar phase); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkDiscretePathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkDiscretePathEffect.h new file mode 100644 index 00000000000000..6054cbdc9915e0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkDiscretePathEffect.h @@ -0,0 +1,37 @@ +/* + * 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 SkDiscretePathEffect_DEFINED +#define SkDiscretePathEffect_DEFINED + +#include "include/core/SkPathEffect.h" + +/** \class SkDiscretePathEffect + + This path effect chops a path into discrete segments, and randomly displaces them. +*/ +class SK_API SkDiscretePathEffect { +public: + /** Break the path into segments of segLength length, and randomly move the endpoints + away from the original path by a maximum of deviation. + Note: works on filled or framed paths + + @param seedAssist This is a caller-supplied seedAssist that modifies + the seed value that is used to randomize the path + segments' endpoints. If not supplied it defaults to 0, + in which case filtering a path multiple times will + result in the same set of segments (this is useful for + testing). If a caller does not want this behaviour + they can pass in a different seedAssist to get a + different set of path segments. + */ + static sk_sp Make(SkScalar segLength, SkScalar dev, uint32_t seedAssist = 0); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkGradientShader.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkGradientShader.h new file mode 100644 index 00000000000000..43a67e242e11ee --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkGradientShader.h @@ -0,0 +1,336 @@ +/* + * 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 SkGradientShader_DEFINED +#define SkGradientShader_DEFINED + +#include "include/core/SkColorSpace.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkShader.h" +#include "include/core/SkTileMode.h" + +/** \class SkGradientShader + + SkGradientShader hosts factories for creating subclasses of SkShader that + render linear and radial gradients. In general, degenerate cases should not + produce surprising results, but there are several types of degeneracies: + + * A linear gradient made from the same two points. + * A radial gradient with a radius of zero. + * A sweep gradient where the start and end angle are the same. + * A two point conical gradient where the two centers and the two radii are + the same. + + For any degenerate gradient with a decal tile mode, it will draw empty since the interpolating + region is zero area and the outer region is discarded by the decal mode. + + For any degenerate gradient with a repeat or mirror tile mode, it will draw a solid color that + is the average gradient color, since infinitely many repetitions of the gradients will fill the + shape. + + For a clamped gradient, every type is well-defined at the limit except for linear gradients. The + radial gradient with zero radius becomes the last color. The sweep gradient draws the sector + from 0 to the provided angle with the first color, with a hardstop switching to the last color. + When the provided angle is 0, this is just the solid last color again. Similarly, the two point + conical gradient becomes a circle filled with the first color, sized to the provided radius, + with a hardstop switching to the last color. When the two radii are both zero, this is just the + solid last color. + + As a linear gradient approaches the degenerate case, its shader will approach the appearance of + two half planes, each filled by the first and last colors of the gradient. The planes will be + oriented perpendicular to the vector between the two defining points of the gradient. However, + once they become the same point, Skia cannot reconstruct what that expected orientation is. To + provide a stable and predictable color in this case, Skia just uses the last color as a solid + fill to be similar to many of the other degenerate gradients' behaviors in clamp mode. +*/ +class SK_API SkGradientShader { +public: + enum Flags { + /** By default gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. By setting this flag, the + * gradients will premultiply their colors first, and then interpolate + * between them. + * example: https://fiddle.skia.org/c/@GradientShader_MakeLinear + */ + kInterpolateColorsInPremul_Flag = 1 << 0, + }; + + struct Interpolation { + enum class InPremul : bool { kNo = false, kYes = true }; + + enum class ColorSpace : uint8_t { + // Default Skia behavior: interpolate in the color space of the destination surface + kDestination, + + // https://www.w3.org/TR/css-color-4/#interpolation-space + kSRGBLinear, + kLab, + kOKLab, + kLCH, + kOKLCH, + kSRGB, + kHSL, + kHWB, + + kLastColorSpace = kHWB, + }; + static constexpr int kColorSpaceCount = static_cast(ColorSpace::kLastColorSpace) + 1; + + enum class HueMethod : uint8_t { + // https://www.w3.org/TR/css-color-4/#hue-interpolation + kShorter, + kLonger, + kIncreasing, + kDecreasing, + + kLastHueMethod = kDecreasing, + }; + static constexpr int kHueMethodCount = static_cast(HueMethod::kLastHueMethod) + 1; + + InPremul fInPremul = InPremul::kNo; + ColorSpace fColorSpace = ColorSpace::kDestination; + HueMethod fHueMethod = HueMethod::kShorter; // Only relevant for LCH, OKLCH, HSL, or HWB + + static Interpolation FromFlags(uint32_t flags) { + return {flags & kInterpolateColorsInPremul_Flag ? InPremul::kYes : InPremul::kNo, + ColorSpace::kDestination, + HueMethod::kShorter}; + } + }; + + /** Returns a shader that generates a linear gradient between the two specified points. +

+ @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the start and end point. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + + example: https://fiddle.skia.org/c/@GradientShader_MakeLinear + */ + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor colors[], const SkScalar pos[], int count, + SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr); + + /** Returns a shader that generates a linear gradient between the two specified points. +

+ @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the start and end point. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + + example: https://fiddle.skia.org/c/@GradientShader_MakeLinear + */ + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, + Interpolation::FromFlags(flags), localMatrix); + } + + /** Returns a shader that generates a radial gradient given the center and radius. +

+ @param center The center of the circle for this gradient + @param radius Must be positive. The radius of the circle for this gradient + @param colors The array[count] of colors, to be distributed between the center and edge of the circle + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode The tiling mode + */ + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor colors[], const SkScalar pos[], int count, + SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr); + + /** Returns a shader that generates a radial gradient given the center and radius. +

+ @param center The center of the circle for this gradient + @param radius Must be positive. The radius of the circle for this gradient + @param colors The array[count] of colors, to be distributed between the center and edge of the circle + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode The tiling mode + */ + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode, + Interpolation::FromFlags(flags), localMatrix); + } + + /** + * Returns a shader that generates a conical gradient given two circles, or + * returns NULL if the inputs are invalid. The gradient interprets the + * two circles according to the following HTML spec. + * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient + */ + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor colors[], const SkScalar pos[], + int count, SkTileMode mode, + uint32_t flags = 0, + const SkMatrix* localMatrix = nullptr); + + /** + * Returns a shader that generates a conical gradient given two circles, or + * returns NULL if the inputs are invalid. The gradient interprets the + * two circles according to the following HTML spec. + * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient + */ + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor4f colors[], + sk_sp colorSpace, const SkScalar pos[], + int count, SkTileMode mode, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor4f colors[], + sk_sp colorSpace, const SkScalar pos[], + int count, SkTileMode mode, + uint32_t flags = 0, + const SkMatrix* localMatrix = nullptr) { + return MakeTwoPointConical(start, startRadius, end, endRadius, colors, + std::move(colorSpace), pos, count, mode, + Interpolation::FromFlags(flags), localMatrix); + } + + /** Returns a shader that generates a sweep gradient given a center. + + The shader accepts negative angles and angles larger than 360, draws + between 0 and 360 degrees, similar to the CSS conic-gradient + semantics. 0 degrees means horizontal positive x axis. The start angle + must be less than the end angle, otherwise a null pointer is + returned. If color stops do not contain 0 and 1 but are within this + range, the respective outer color stop is repeated for 0 and 1. Color + stops less than 0 are clamped to 0, and greater than 1 are clamped to 1. +

+ @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center, within + the gradient angle range. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative + position of each corresponding color in the colors array. If this is + NULL, then the colors are distributed evenly within the angular range. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode Tiling mode: controls drawing outside of the gradient angular range. + @param startAngle Start of the angular range, corresponding to pos == 0. + @param endAngle End of the angular range, corresponding to pos == 1. + */ + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count, + SkTileMode mode, + SkScalar startAngle, SkScalar endAngle, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeSweep(cx, cy, colors, pos, count, SkTileMode::kClamp, 0, 360, flags, + localMatrix); + } + + /** Returns a shader that generates a sweep gradient given a center. + + The shader accepts negative angles and angles larger than 360, draws + between 0 and 360 degrees, similar to the CSS conic-gradient + semantics. 0 degrees means horizontal positive x axis. The start angle + must be less than the end angle, otherwise a null pointer is + returned. If color stops do not contain 0 and 1 but are within this + range, the respective outer color stop is repeated for 0 and 1. Color + stops less than 0 are clamped to 0, and greater than 1 are clamped to 1. +

+ @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center, within + the gradient angle range. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative + position of each corresponding color in the colors array. If this is + NULL, then the colors are distributed evenly within the angular range. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode Tiling mode: controls drawing outside of the gradient angular range. + @param startAngle Start of the angular range, corresponding to pos == 0. + @param endAngle End of the angular range, corresponding to pos == 1. + */ + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + SkTileMode mode, + SkScalar startAngle, SkScalar endAngle, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + SkTileMode mode, + SkScalar startAngle, SkScalar endAngle, + uint32_t flags, const SkMatrix* localMatrix) { + return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, mode, startAngle, + endAngle, Interpolation::FromFlags(flags), localMatrix); + } + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, SkTileMode::kClamp, + 0, 360, flags, localMatrix); + } +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkHighContrastFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkHighContrastFilter.h new file mode 100644 index 00000000000000..1224ade5e456fe --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkHighContrastFilter.h @@ -0,0 +1,84 @@ +/* +* Copyright 2017 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef SkHighContrastFilter_DEFINED +#define SkHighContrastFilter_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkColorFilter; + +/** + * Configuration struct for SkHighContrastFilter. + * + * Provides transformations to improve contrast for users with low vision. + */ +struct SkHighContrastConfig { + enum class InvertStyle { + kNoInvert, + kInvertBrightness, + kInvertLightness, + + kLast = kInvertLightness + }; + + SkHighContrastConfig() { + fGrayscale = false; + fInvertStyle = InvertStyle::kNoInvert; + fContrast = 0.0f; + } + + SkHighContrastConfig(bool grayscale, + InvertStyle invertStyle, + SkScalar contrast) + : fGrayscale(grayscale), + fInvertStyle(invertStyle), + fContrast(contrast) {} + + // Returns true if all of the fields are set within the valid range. + bool isValid() const { + return fInvertStyle >= InvertStyle::kNoInvert && + fInvertStyle <= InvertStyle::kInvertLightness && + fContrast >= -1.0 && + fContrast <= 1.0; + } + + // If true, the color will be converted to grayscale. + bool fGrayscale; + + // Whether to invert brightness, lightness, or neither. + InvertStyle fInvertStyle; + + // After grayscale and inverting, the contrast can be adjusted linearly. + // The valid range is -1.0 through 1.0, where 0.0 is no adjustment. + SkScalar fContrast; +}; + +/** + * Color filter that provides transformations to improve contrast + * for users with low vision. + * + * Applies the following transformations in this order. Each of these + * can be configured using SkHighContrastConfig. + * + * - Conversion to grayscale + * - Color inversion (either in RGB or HSL space) + * - Increasing the resulting contrast. + * + * Calling SkHighContrastFilter::Make will return nullptr if the config is + * not valid, e.g. if you try to call it with a contrast outside the range of + * -1.0 to 1.0. + */ + +struct SK_API SkHighContrastFilter { + // Returns the filter, or nullptr if the config is invalid. + static sk_sp Make(const SkHighContrastConfig& config); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkImageFilters.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkImageFilters.h new file mode 100644 index 00000000000000..75d2cb0bcc54f1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkImageFilters.h @@ -0,0 +1,541 @@ +/* + * Copyright 2019 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageFilters_DEFINED +#define SkImageFilters_DEFINED + +#include "include/core/SkBlendMode.h" +#include "include/core/SkColor.h" +#include "include/core/SkImage.h" +#include "include/core/SkImageFilter.h" +#include "include/core/SkPicture.h" +#include "include/core/SkRect.h" +#include "include/core/SkTileMode.h" +#include "include/core/SkTypes.h" +#include "include/effects/SkRuntimeEffect.h" + +#include + +class SkBlender; +class SkColorFilter; +class SkPaint; +class SkRegion; + +namespace skif { + static constexpr SkRect kNoCropRect = {SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity, + SK_ScalarInfinity, SK_ScalarInfinity}; +} + +// A set of factory functions providing useful SkImageFilter effects. For image filters that take an +// input filter, providing nullptr means it will automatically use the dynamic source image. This +// source depends on how the filter is applied, but is either the contents of a saved layer when +// drawing with SkCanvas, or an explicit SkImage if using SkImage::makeWithFilter. +class SK_API SkImageFilters { +public: + // This is just a convenience type to allow passing SkIRects, SkRects, and optional pointers + // to those types as a crop rect for the image filter factories. It's not intended to be used + // directly. + struct CropRect { + CropRect() : fCropRect(skif::kNoCropRect) {} + // Intentionally not explicit so callers don't have to use this type but can use SkIRect or + // SkRect as desired. + CropRect(std::nullptr_t) : fCropRect(skif::kNoCropRect) {} + CropRect(const SkIRect& crop) : fCropRect(SkRect::Make(crop)) {} + CropRect(const SkRect& crop) : fCropRect(crop) {} + CropRect(const SkIRect* optionalCrop) : fCropRect(optionalCrop ? SkRect::Make(*optionalCrop) + : skif::kNoCropRect) {} + CropRect(const SkRect* optionalCrop) : fCropRect(optionalCrop ? *optionalCrop + : skif::kNoCropRect) {} + + operator const SkRect*() const { return fCropRect == skif::kNoCropRect ? nullptr : &fCropRect; } + + SkRect fCropRect; + }; + + /** + * Create a filter that updates the alpha of the image based on 'region'. Pixels inside the + * region are made more opaque and pixels outside are made more transparent. + * + * Specifically, if a pixel is inside the region, its alpha will be set to + * max(innerMin, pixel's alpha). If a pixel is outside the region, its alpha will be updated to + * min(outerMax, pixel's alpha). + * @param region The geometric region controlling the inner and outer alpha thresholds. + * @param innerMin The minimum alpha value for pixels inside 'region'. + * @param outerMax The maximum alpha value for pixels outside of 'region'. + * @param input The input filter, or uses the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp AlphaThreshold(const SkRegion& region, SkScalar innerMin, + SkScalar outerMax, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that implements a custom blend mode. Each output pixel is the result of + * combining the corresponding background and foreground pixels using the 4 coefficients: + * k1 * foreground * background + k2 * foreground + k3 * background + k4 + * @param k1, k2, k3, k4 The four coefficients used to combine the foreground and background. + * @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha. + * @param background The background content, using the source bitmap when this is null. + * @param foreground The foreground content, using the source bitmap when this is null. + * @param cropRect Optional rectangle that crops the inputs and output. + */ + static sk_sp Arithmetic(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, + bool enforcePMColor, sk_sp background, + sk_sp foreground, + const CropRect& cropRect = {}); + + /** + * This filter takes an SkBlendMode and uses it to composite the two filters together. + * @param mode The blend mode that defines the compositing operation + * @param background The Dst pixels used in blending, if null the source bitmap is used. + * @param foreground The Src pixels used in blending, if null the source bitmap is used. + * @cropRect Optional rectangle to crop input and output. + */ + static sk_sp Blend(SkBlendMode mode, sk_sp background, + sk_sp foreground = nullptr, + const CropRect& cropRect = {}); + + /** + * This filter takes an SkBlendMode and uses it to composite the two filters together. + * @param blender The blender that defines the compositing operation + * @param background The Dst pixels used in blending, if null the source bitmap is used. + * @param foreground The Src pixels used in blending, if null the source bitmap is used. + * @cropRect Optional rectangle to crop input and output. + */ + static sk_sp Blend(sk_sp blender, sk_sp background, + sk_sp foreground = nullptr, + const CropRect& cropRect = {}); + + /** + * Create a filter that blurs its input by the separate X and Y sigmas. The provided tile mode + * is used when the blur kernel goes outside the input image. + * @param sigmaX The Gaussian sigma value for blurring along the X axis. + * @param sigmaY The Gaussian sigma value for blurring along the Y axis. + * @param tileMode The tile mode applied at edges . + * TODO (michaelludwig) - kMirror is not supported yet + * @param input The input filter that is blurred, uses source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, + sk_sp input, const CropRect& cropRect = {}); + // As above, but defaults to the decal tile mode. + static sk_sp Blur(SkScalar sigmaX, SkScalar sigmaY, sk_sp input, + const CropRect& cropRect = {}) { + return Blur(sigmaX, sigmaY, SkTileMode::kDecal, std::move(input), cropRect); + } + + /** + * Create a filter that applies the color filter to the input filter results. + * @param cf The color filter that transforms the input image. + * @param input The input filter, or uses the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp ColorFilter(sk_sp cf, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are + * treated as the source bitmap passed to 'outer', i.e. result = outer(inner(source)). + * @param outer The outer filter that evaluates the results of inner. + * @param inner The inner filter that produces the input to outer. + */ + static sk_sp Compose(sk_sp outer, sk_sp inner); + + /** + * Create a filter that moves each pixel in its color input based on an (x,y) vector encoded + * in its displacement input filter. Two color components of the displacement image are + * mapped into a vector as scale * (color[xChannel], color[yChannel]), where the channel + * selectors are one of R, G, B, or A. + * @param xChannelSelector RGBA channel that encodes the x displacement per pixel. + * @param yChannelSelector RGBA channel that encodes the y displacement per pixel. + * @param scale Scale applied to displacement extracted from image. + * @param displacement The filter defining the displacement image, or null to use source. + * @param color The filter providing the color pixels to be displaced. If null, + * it will use the source. + * @param cropRect Optional rectangle that crops the color input and output. + */ + static sk_sp DisplacementMap(SkColorChannel xChannelSelector, + SkColorChannel yChannelSelector, + SkScalar scale, sk_sp displacement, + sk_sp color, + const CropRect& cropRect = {}); + + /** + * Create a filter that draws a drop shadow under the input content. This filter produces an + * image that includes the inputs' content. + * @param dx The X offset of the shadow. + * @param dy The Y offset of the shadow. + * @param sigmaX The blur radius for the shadow, along the X axis. + * @param sigmaY The blur radius for the shadow, along the Y axis. + * @param color The color of the drop shadow. + * @param input The input filter, or will use the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DropShadow(SkScalar dx, SkScalar dy, + SkScalar sigmaX, SkScalar sigmaY, + SkColor color, sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that renders a drop shadow, in exactly the same manner as ::DropShadow, + * except that the resulting image does not include the input content. This allows the shadow + * and input to be composed by a filter DAG in a more flexible manner. + * @param dx The X offset of the shadow. + * @param dy The Y offset of the shadow. + * @param sigmaX The blur radius for the shadow, along the X axis. + * @param sigmaY The blur radius for the shadow, along the Y axis. + * @param color The color of the drop shadow. + * @param input The input filter, or will use the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DropShadowOnly(SkScalar dx, SkScalar dy, + SkScalar sigmaX, SkScalar sigmaY, + SkColor color, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that draws the 'srcRect' portion of image into 'dstRect' using the given + * filter quality. Similar to SkCanvas::drawImageRect. Returns null if 'image' is null. + * @param image The image that is output by the filter, subset by 'srcRect'. + * @param srcRect The source pixels sampled into 'dstRect' + * @param dstRect The local rectangle to draw the image into. + * @param sampling The sampling to use when drawing the image. + */ + static sk_sp Image(sk_sp image, const SkRect& srcRect, + const SkRect& dstRect, const SkSamplingOptions& sampling); + + /** + * Create a filter that draws the image using the given sampling. + * Similar to SkCanvas::drawImage. Returns null if 'image' is null. + * @param image The image that is output by the filter. + * @param sampling The sampling to use when drawing the image. + */ + static sk_sp Image(sk_sp image, const SkSamplingOptions& sampling) { + if (image) { + SkRect r = SkRect::Make(image->bounds()); + return Image(std::move(image), r, r, sampling); + } else { + return nullptr; + } + } + + /** + * Create a filter that draws the image using Mitchel cubic resampling. + * @param image The image that is output by the filter. + */ + static sk_sp Image(sk_sp image) { + return Image(std::move(image), SkSamplingOptions({1/3.0f, 1/3.0f})); + } + + /** + * Create a filter that mimics a zoom/magnifying lens effect. + * @param srcRect + * @param inset + * @param input The input filter that is magnified, if null the source bitmap is used. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Magnifier(const SkRect& srcRect, SkScalar inset, + sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that applies an NxM image processing kernel to the input image. This can be + * used to produce effects such as sharpening, blurring, edge detection, etc. + * @param kernelSize The kernel size in pixels, in each dimension (N by M). + * @param kernel The image processing kernel. Must contain N * M elements, in row order. + * @param gain A scale factor applied to each pixel after convolution. This can be + * used to normalize the kernel, if it does not already sum to 1. + * @param bias A bias factor added to each pixel after convolution. + * @param kernelOffset An offset applied to each pixel coordinate before convolution. + * This can be used to center the kernel over the image + * (e.g., a 3x3 kernel should have an offset of {1, 1}). + * @param tileMode How accesses outside the image are treated. + * TODO (michaelludwig) - kMirror is not supported yet + * @param convolveAlpha If true, all channels are convolved. If false, only the RGB channels + * are convolved, and alpha is copied from the source image. + * @param input The input image filter, if null the source bitmap is used instead. + * @param cropRect Optional rectangle to which the output processing will be limited. + */ + static sk_sp MatrixConvolution(const SkISize& kernelSize, + const SkScalar kernel[], SkScalar gain, + SkScalar bias, const SkIPoint& kernelOffset, + SkTileMode tileMode, bool convolveAlpha, + sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that transforms the input image by 'matrix'. This matrix transforms the + * local space, which means it effectively happens prior to any transformation coming from the + * SkCanvas initiating the filtering. + * @param matrix The matrix to apply to the original content. + * @param sampling How the image will be sampled when it is transformed + * @param input The image filter to transform, or null to use the source image. + */ + static sk_sp MatrixTransform(const SkMatrix& matrix, + const SkSamplingOptions& sampling, + sk_sp input); + + /** + * Create a filter that merges the 'count' filters together by drawing their results in order + * with src-over blending. + * @param filters The input filter array to merge, which must have 'count' elements. Any null + * filter pointers will use the source bitmap instead. + * @param count The number of input filters to be merged. + * @param cropRect Optional rectangle that crops all input filters and the output. + */ + static sk_sp Merge(sk_sp* const filters, int count, + const CropRect& cropRect = {}); + /** + * Create a filter that merges the results of the two filters together with src-over blending. + * @param first The first input filter, or the source bitmap if this is null. + * @param second The second input filter, or the source bitmap if this null. + * @param cropRect Optional rectangle that crops the inputs and output. + */ + static sk_sp Merge(sk_sp first, sk_sp second, + const CropRect& cropRect = {}) { + sk_sp array[] = { std::move(first), std::move(second) }; + return Merge(array, 2, cropRect); + } + + /** + * Create a filter that offsets the input filter by the given vector. + * @param dx The x offset in local space that the image is shifted. + * @param dy The y offset in local space that the image is shifted. + * @param input The input that will be moved, if null the source bitmap is used instead. + * @param cropRect Optional rectangle to crop the input and output. + */ + static sk_sp Offset(SkScalar dx, SkScalar dy, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that produces the SkPicture as its output, drawn into targetRect. Note that + * the targetRect is not the same as the SkIRect cropRect that many filters accept. Returns + * null if 'pic' is null. + * @param pic The picture that is drawn for the filter output. + * @param targetRect The drawing region for the picture. + */ + static sk_sp Picture(sk_sp pic, const SkRect& targetRect); + // As above, but uses SkPicture::cullRect for the drawing region. + static sk_sp Picture(sk_sp pic) { + SkRect target = pic ? pic->cullRect() : SkRect::MakeEmpty(); + return Picture(std::move(pic), target); + } + +#ifdef SK_ENABLE_SKSL + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced + * by the SkRuntimeShaderBuilder. The shader is defined in the image filter's local coordinate + * system, so it will automatically be affected by SkCanvas' transform. + * + * @param builder The builder used to produce the runtime shader, that will in turn + * fill the result image + * @param childShaderName The name of the child shader defined in the builder that will be + * bound to the input param (or the source image if the input param + * is null). If empty, the builder can have exactly one child shader, + * which automatically binds the input param. + * @param input The image filter that will be provided as input to the runtime + * shader. If null the implicit source image is used instead + */ + static sk_sp RuntimeShader(const SkRuntimeShaderBuilder& builder, + std::string_view childShaderName, + sk_sp input); + + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced + * by the SkRuntimeShaderBuilder. The shader is defined in the image filter's local coordinate + * system, so it will automatically be affected by SkCanvas' transform. + * + * @param builder The builder used to produce the runtime shader, that will in turn + * fill the result image + * @param childShaderNames The names of the child shaders defined in the builder that will be + * bound to the input params (or the source image if the input param + * is null). If any name is null, or appears more than once, factory + * fails and returns nullptr. + * @param inputs The image filters that will be provided as input to the runtime + * shader. If any are null, the implicit source image is used instead. + * @param inputCount How many entries are present in 'childShaderNames' and 'inputs'. + */ + static sk_sp RuntimeShader(const SkRuntimeShaderBuilder& builder, + std::string_view childShaderNames[], + const sk_sp inputs[], + int inputCount); +#endif // SK_ENABLE_SKSL + + enum class Dither : bool { + kNo = false, + kYes = true + }; + + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader. The + * shader is defined in the image filter's local coordinate system, so will automatically + * be affected by SkCanvas' transform. + * + * Like Image() and Picture(), this is a leaf filter that can be used to introduce inputs to + * a complex filter graph, but should generally be combined with a filter that as at least + * one null input to use the implicit source image. + * @param shader The shader that fills the result image + */ + static sk_sp Shader(sk_sp shader, const CropRect& cropRect = {}) { + return Shader(std::move(shader), Dither::kNo, cropRect); + } + static sk_sp Shader(sk_sp shader, Dither dither, + const CropRect& cropRect = {}); + + /** + * Create a tile image filter. + * @param src Defines the pixels to tile + * @param dst Defines the pixel region that the tiles will be drawn to + * @param input The input that will be tiled, if null the source bitmap is used instead. + */ + static sk_sp Tile(const SkRect& src, const SkRect& dst, + sk_sp input); + + // Morphology filter effects + + /** + * Create a filter that dilates each input pixel's channel values to the max value within the + * given radii along the x and y axes. + * @param radiusX The distance to dilate along the x axis to either side of each pixel. + * @param radiusY The distance to dilate along the y axis to either side of each pixel. + * @param input The image filter that is dilated, using source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Dilate(SkScalar radiusX, SkScalar radiusY, + sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that erodes each input pixel's channel values to the minimum channel value + * within the given radii along the x and y axes. + * @param radiusX The distance to erode along the x axis to either side of each pixel. + * @param radiusY The distance to erode along the y axis to either side of each pixel. + * @param input The image filter that is eroded, using source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Erode(SkScalar radiusX, SkScalar radiusY, + sk_sp input, + const CropRect& cropRect = {}); + + // Lighting filter effects + + /** + * Create a filter that calculates the diffuse illumination from a distant light source, + * interpreting the alpha channel of the input as the height profile of the surface (to + * approximate normal vectors). + * @param direction The direction to the distance light. + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DistantLitDiffuse(const SkPoint3& direction, SkColor lightColor, + SkScalar surfaceScale, SkScalar kd, + sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the diffuse illumination from a point light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). + * @param location The location of the point light. + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp PointLitDiffuse(const SkPoint3& location, SkColor lightColor, + SkScalar surfaceScale, SkScalar kd, + sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the diffuse illumination from a spot light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between + * the location and target. + * @param location The location of the spot light. + * @param target The location that the spot light is point towards + * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle + * @param cutoffAngle Maximum angle from lighting direction that receives full light + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp SpotLitDiffuse(const SkPoint3& location, const SkPoint3& target, + SkScalar falloffExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, + SkScalar kd, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that calculates the specular illumination from a distant light source, + * interpreting the alpha channel of the input as the height profile of the surface (to + * approximate normal vectors). + * @param direction The direction to the distance light. + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DistantLitSpecular(const SkPoint3& direction, SkColor lightColor, + SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the specular illumination from a point light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). + * @param location The location of the point light. + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp PointLitSpecular(const SkPoint3& location, SkColor lightColor, + SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the specular illumination from a spot light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between + * the location and target. + * @param location The location of the spot light. + * @param target The location that the spot light is point towards + * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle + * @param cutoffAngle Maximum angle from lighting direction that receives full light + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp SpotLitSpecular(const SkPoint3& location, const SkPoint3& target, + SkScalar falloffExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, + SkScalar ks, SkScalar shininess, + sk_sp input, + const CropRect& cropRect = {}); + +private: + SkImageFilters() = delete; +}; + +#endif // SkImageFilters_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkLayerDrawLooper.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkLayerDrawLooper.h new file mode 100644 index 00000000000000..1e875b58cc1c3d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkLayerDrawLooper.h @@ -0,0 +1,161 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLayerDrawLooper_DEFINED +#define SkLayerDrawLooper_DEFINED + +#include "include/core/SkBlendMode.h" +#include "include/core/SkDrawLooper.h" +#include "include/core/SkPaint.h" +#include "include/core/SkPoint.h" + +#ifndef SK_SUPPORT_LEGACY_DRAWLOOPER +#error "SkDrawLooper is unsupported" +#endif + +/** + * DEPRECATED: No longer supported by Skia. + */ +class SK_API SkLayerDrawLooper : public SkDrawLooper { +public: + ~SkLayerDrawLooper() override; + + /** + * Bits specifies which aspects of the layer's paint should replace the + * corresponding aspects on the draw's paint. + * kEntirePaint_Bits means use the layer's paint completely. + * 0 means ignore the layer's paint... except for fColorMode, which is + * always applied. + */ + enum Bits { + kStyle_Bit = 1 << 0, //!< use this layer's Style/stroke settings + kPathEffect_Bit = 1 << 2, //!< use this layer's patheffect + kMaskFilter_Bit = 1 << 3, //!< use this layer's maskfilter + kShader_Bit = 1 << 4, //!< use this layer's shader + kColorFilter_Bit = 1 << 5, //!< use this layer's colorfilter + kXfermode_Bit = 1 << 6, //!< use this layer's xfermode + + // unsupported kTextSkewX_Bit = 1 << 1, + + /** + * Use the layer's paint entirely, with these exceptions: + * - We never override the draw's paint's text_encoding, since that is + * used to interpret the text/len parameters in draw[Pos]Text. + * - Color is always computed using the LayerInfo's fColorMode. + */ + kEntirePaint_Bits = -1 + + }; + typedef int32_t BitFlags; + + /** + * Info for how to apply the layer's paint and offset. + * + * fColorMode controls how we compute the final color for the layer: + * The layer's paint's color is treated as the SRC + * The draw's paint's color is treated as the DST + * final-color = Mode(layers-color, draws-color); + * Any SkBlendMode will work. Two common choices are: + * kSrc: to use the layer's color, ignoring the draw's + * kDst: to just keep the draw's color, ignoring the layer's + */ + struct SK_API LayerInfo { + BitFlags fPaintBits; + SkBlendMode fColorMode; + SkVector fOffset; + bool fPostTranslate; //!< applies to fOffset + + /** + * Initial the LayerInfo. Defaults to settings that will draw the + * layer with no changes: e.g. + * fPaintBits == 0 + * fColorMode == kDst_Mode + * fOffset == (0, 0) + */ + LayerInfo(); + }; + + SkDrawLooper::Context* makeContext(SkArenaAlloc*) const override; + + bool asABlurShadow(BlurShadowRec* rec) const override; + +protected: + SkLayerDrawLooper(); + + void flatten(SkWriteBuffer&) const override; + +private: + SK_FLATTENABLE_HOOKS(SkLayerDrawLooper) + + struct Rec { + Rec* fNext; + SkPaint fPaint; + LayerInfo fInfo; + }; + Rec* fRecs; + int fCount; + + // state-machine during the init/next cycle + class LayerDrawLooperContext : public SkDrawLooper::Context { + public: + explicit LayerDrawLooperContext(const SkLayerDrawLooper* looper); + + protected: + bool next(Info*, SkPaint* paint) override; + + private: + Rec* fCurrRec; + + static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); + }; + + using INHERITED = SkDrawLooper; + +public: + class SK_API Builder { + public: + Builder(); + + ~Builder(); + + /** + * Call for each layer you want to add (from top to bottom). + * This returns a paint you can modify, but that ptr is only valid until + * the next call made to addLayer(). + */ + SkPaint* addLayer(const LayerInfo&); + + /** + * This layer will draw with the original paint, at the specified offset + */ + void addLayer(SkScalar dx, SkScalar dy); + + /** + * This layer will with the original paint and no offset. + */ + void addLayer() { this->addLayer(0, 0); } + + /// Similar to addLayer, but adds a layer to the top. + SkPaint* addLayerOnTop(const LayerInfo&); + + /** + * Pass list of layers on to newly built looper and return it. This will + * also reset the builder, so it can be used to build another looper. + */ + sk_sp detach(); + + private: + Builder(const Builder&) = delete; + Builder& operator=(const Builder&) = delete; + + Rec* fRecs; + Rec* fTopRec; + int fCount; + }; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkLumaColorFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkLumaColorFilter.h new file mode 100644 index 00000000000000..41a9a45f3fba27 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkLumaColorFilter.h @@ -0,0 +1,37 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLumaColorFilter_DEFINED +#define SkLumaColorFilter_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkColorFilter; + +/** + * SkLumaColorFilter multiplies the luma of its input into the alpha channel, + * and sets the red, green, and blue channels to zero. + * + * SkLumaColorFilter(r,g,b,a) = {0,0,0, a * luma(r,g,b)} + * + * This is similar to a luminanceToAlpha feColorMatrix, + * but note how this filter folds in the previous alpha, + * something an feColorMatrix cannot do. + * + * feColorMatrix(luminanceToAlpha; r,g,b,a) = {0,0,0, luma(r,g,b)} + * + * (Despite its name, an feColorMatrix using luminanceToAlpha does + * actually compute luma, a dot-product of gamma-encoded color channels, + * not luminance, a dot-product of linear color channels. So at least + * SkLumaColorFilter and feColorMatrix+luminanceToAlpha agree there.) + */ +struct SK_API SkLumaColorFilter { + static sk_sp Make(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkOpPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkOpPathEffect.h new file mode 100644 index 00000000000000..3c9110f0cc1aaa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkOpPathEffect.h @@ -0,0 +1,43 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOpPathEffect_DEFINED +#define SkOpPathEffect_DEFINED + +#include "include/core/SkPaint.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/pathops/SkPathOps.h" + +class SkMatrix; +class SkPathEffect; + +class SK_API SkMergePathEffect { +public: + /* Defers to two other patheffects, and then combines their outputs using the specified op. + * e.g. + * result = output_one op output_two + * + * If either one or two is nullptr, then the original path is passed through to the op. + */ + static sk_sp Make(sk_sp one, sk_sp two, SkPathOp op); +}; + +class SK_API SkMatrixPathEffect { +public: + static sk_sp MakeTranslate(SkScalar dx, SkScalar dy); + static sk_sp Make(const SkMatrix&); +}; + +class SK_API SkStrokePathEffect { +public: + static sk_sp Make(SkScalar width, SkPaint::Join, SkPaint::Cap, + SkScalar miter = 4); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkOverdrawColorFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkOverdrawColorFilter.h new file mode 100644 index 00000000000000..5f1642483ae23b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkOverdrawColorFilter.h @@ -0,0 +1,32 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkColor.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkColorFilter; + +#ifndef SkOverdrawColorFilter_DEFINED +#define SkOverdrawColorFilter_DEFINED + +/** + * Uses the value in the src alpha channel to set the dst pixel. + * 0 -> colors[0] + * 1 -> colors[1] + * ... + * 5 (or larger) -> colors[5] + * + */ +class SK_API SkOverdrawColorFilter { +public: + static constexpr int kNumColors = 6; + + static sk_sp MakeWithSkColors(const SkColor[kNumColors]); +}; + +#endif // SkOverdrawColorFilter_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkPerlinNoiseShader.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkPerlinNoiseShader.h new file mode 100644 index 00000000000000..f94b3420fceaa4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkPerlinNoiseShader.h @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPerlinNoiseShader_DEFINED +#define SkPerlinNoiseShader_DEFINED + +#include "include/core/SkShader.h" + +/** \class SkPerlinNoiseShader + + SkPerlinNoiseShader creates an image using the Perlin turbulence function. + + It can produce tileable noise if asked to stitch tiles and provided a tile size. + In order to fill a large area with repeating noise, set the stitchTiles flag to + true, and render exactly a single tile of noise. Without this flag, the result + will contain visible seams between tiles. + + The algorithm used is described here : + http://www.w3.org/TR/SVG/filters.html#feTurbulenceElement +*/ +class SK_API SkPerlinNoiseShader { +public: + /** + * This will construct Perlin noise of the given type (Fractal Noise or Turbulence). + * + * Both base frequencies (X and Y) have a usual range of (0..1) and must be non-negative. + * + * The number of octaves provided should be fairly small, with a limit of 255 enforced. + * Each octave doubles the frequency, so 10 octaves would produce noise from + * baseFrequency * 1, * 2, * 4, ..., * 512, which quickly yields insignificantly small + * periods and resembles regular unstructured noise rather than Perlin noise. + * + * If tileSize isn't NULL or an empty size, the tileSize parameter will be used to modify + * the frequencies so that the noise will be tileable for the given tile size. If tileSize + * is NULL or an empty size, the frequencies will be used as is without modification. + */ + static sk_sp MakeFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = nullptr); + static sk_sp MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = nullptr); + + static void RegisterFlattenables(); + +private: + SkPerlinNoiseShader() = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkRuntimeEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkRuntimeEffect.h new file mode 100644 index 00000000000000..4d3450ee258786 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkRuntimeEffect.h @@ -0,0 +1,544 @@ +/* + * Copyright 2019 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRuntimeEffect_DEFINED +#define SkRuntimeEffect_DEFINED + +#include "include/core/SkBlender.h" +#include "include/core/SkColorFilter.h" +#include "include/core/SkData.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkShader.h" +#include "include/core/SkSpan.h" +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" +#include "include/private/SkSLSampleUsage.h" +#include "include/private/base/SkOnce.h" +#include "include/private/base/SkTemplates.h" + +#include +#include +#include + +#ifdef SK_ENABLE_SKSL + +#include "include/sksl/SkSLVersion.h" + +class GrRecordingContext; +class SkFilterColorProgram; +class SkImage; +class SkRuntimeImageFilter; + +namespace SkSL { +class DebugTrace; +class DebugTracePriv; +class ErrorReporter; +class FunctionDefinition; +struct Program; +enum class ProgramKind : int8_t; +struct ProgramSettings; +} // namespace SkSL + +namespace skvm { +class Program; +} + +namespace SkSL::RP { +class Program; +} + +/* + * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL + * shading language. + * + * NOTE: This API is experimental and subject to change. + */ +class SK_API SkRuntimeEffect : public SkRefCnt { +public: + // Reflected description of a uniform variable in the effect's SkSL + struct Uniform { + enum class Type { + kFloat, + kFloat2, + kFloat3, + kFloat4, + kFloat2x2, + kFloat3x3, + kFloat4x4, + kInt, + kInt2, + kInt3, + kInt4, + }; + + enum Flags { + // Uniform is declared as an array. 'count' contains array length. + kArray_Flag = 0x1, + + // Uniform is declared with layout(color). Colors should be supplied as unpremultiplied, + // extended-range (unclamped) sRGB (ie SkColor4f). The uniform will be automatically + // transformed to unpremultiplied extended-range working-space colors. + kColor_Flag = 0x2, + + // When used with SkMeshSpecification, indicates that the uniform is present in the + // vertex shader. Not used with SkRuntimeEffect. + kVertex_Flag = 0x4, + + // When used with SkMeshSpecification, indicates that the uniform is present in the + // fragment shader. Not used with SkRuntimeEffect. + kFragment_Flag = 0x8, + + // This flag indicates that the SkSL uniform uses a medium-precision type + // (i.e., `half` instead of `float`). + kHalfPrecision_Flag = 0x10, + }; + + std::string_view name; + size_t offset; + Type type; + int count; + uint32_t flags; + + bool isArray() const { return SkToBool(this->flags & kArray_Flag); } + bool isColor() const { return SkToBool(this->flags & kColor_Flag); } + size_t sizeInBytes() const; + }; + + // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL + enum class ChildType { + kShader, + kColorFilter, + kBlender, + }; + + struct Child { + std::string_view name; + ChildType type; + int index; + }; + + class Options { + public: + // For testing purposes, disables optimization and inlining. (Normally, Runtime Effects + // don't run the inliner directly, but they still get an inlining pass once they are + // painted.) + bool forceUnoptimized = false; + + private: + friend class SkRuntimeEffect; + friend class SkRuntimeEffectPriv; + + // This flag allows Runtime Effects to access Skia implementation details like sk_FragCoord + // and functions with private identifiers (e.g. $rgb_to_hsl). + bool allowPrivateAccess = false; + + // TODO(skia:11209) - Replace this with a promised SkCapabilities? + // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the + // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are + // still largely ES3-unaware and can still fail or crash if post-ES2 features are used. + // This is only intended for use by tests and certain internally created effects. + SkSL::Version maxVersionAllowed = SkSL::Version::k100; + }; + + // If the effect is compiled successfully, `effect` will be non-null. + // Otherwise, `errorText` will contain the reason for failure. + struct Result { + sk_sp effect; + SkString errorText; + }; + + // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of + // the Skia pipeline. In all of the signatures described below, color parameters and return + // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or + // 'float4'. ('vec4' is an alias for 'float4'). + + // We can't use a default argument for `options` due to a bug in Clang. + // https://bugs.llvm.org/show_bug.cgi?id=36684 + + // Color filter SkSL requires an entry point that looks like: + // vec4 main(vec4 inColor) { ... } + static Result MakeForColorFilter(SkString sksl, const Options&); + static Result MakeForColorFilter(SkString sksl) { + return MakeForColorFilter(std::move(sksl), Options{}); + } + + // Shader SkSL requires an entry point that looks like: + // vec4 main(vec2 inCoords) { ... } + static Result MakeForShader(SkString sksl, const Options&); + static Result MakeForShader(SkString sksl) { + return MakeForShader(std::move(sksl), Options{}); + } + + // Blend SkSL requires an entry point that looks like: + // vec4 main(vec4 srcColor, vec4 dstColor) { ... } + static Result MakeForBlender(SkString sksl, const Options&); + static Result MakeForBlender(SkString sksl) { + return MakeForBlender(std::move(sksl), Options{}); + } + + // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child + class ChildPtr { + public: + ChildPtr() = default; + ChildPtr(sk_sp s) : fChild(std::move(s)) {} + ChildPtr(sk_sp cf) : fChild(std::move(cf)) {} + ChildPtr(sk_sp b) : fChild(std::move(b)) {} + + // Asserts that the flattenable is either null, or one of the legal derived types + ChildPtr(sk_sp f); + + std::optional type() const; + + SkShader* shader() const; + SkColorFilter* colorFilter() const; + SkBlender* blender() const; + SkFlattenable* flattenable() const { return fChild.get(); } + + using sk_is_trivially_relocatable = std::true_type; + + private: + sk_sp fChild; + + static_assert(::sk_is_trivially_relocatable::value); + }; + + sk_sp makeShader(sk_sp uniforms, + sk_sp children[], + size_t childCount, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeShader(sk_sp uniforms, + SkSpan children, + const SkMatrix* localMatrix = nullptr) const; + + sk_sp makeImage(GrRecordingContext*, + sk_sp uniforms, + SkSpan children, + const SkMatrix* localMatrix, + SkImageInfo resultInfo, + bool mipmapped) const; + + sk_sp makeColorFilter(sk_sp uniforms) const; + sk_sp makeColorFilter(sk_sp uniforms, + sk_sp children[], + size_t childCount) const; + sk_sp makeColorFilter(sk_sp uniforms, + SkSpan children) const; + + sk_sp makeBlender(sk_sp uniforms, + SkSpan children = {}) const; + + /** + * Creates a new Runtime Effect patterned after an already-existing one. The new shader behaves + * like the original, but also creates a debug trace of its execution at the requested + * coordinate. After painting with this shader, the associated DebugTrace object will contain a + * shader execution trace. Call `writeTrace` on the debug trace object to generate a full trace + * suitable for a debugger, or call `dump` to emit a human-readable trace. + * + * Debug traces are only supported on a raster (non-GPU) canvas. + + * Debug traces are currently only supported on shaders. Color filter and blender tracing is a + * work-in-progress. + */ + struct TracedShader { + sk_sp shader; + sk_sp debugTrace; + }; + static TracedShader MakeTraced(sk_sp shader, const SkIPoint& traceCoord); + + // Returns the SkSL source of the runtime effect shader. + const std::string& source() const; + + // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader, + // provide an SkData of this size, containing values for all of those variables. + size_t uniformSize() const; + + SkSpan uniforms() const { return SkSpan(fUniforms); } + SkSpan children() const { return SkSpan(fChildren); } + + // Returns pointer to the named uniform variable's description, or nullptr if not found + const Uniform* findUniform(std::string_view name) const; + + // Returns pointer to the named child's description, or nullptr if not found + const Child* findChild(std::string_view name) const; + + // Allows the runtime effect type to be identified. + bool allowShader() const { return (fFlags & kAllowShader_Flag); } + bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); } + bool allowBlender() const { return (fFlags & kAllowBlender_Flag); } + + static void RegisterFlattenables(); + ~SkRuntimeEffect() override; + +private: + enum Flags { + kUsesSampleCoords_Flag = 0x01, + kAllowColorFilter_Flag = 0x02, + kAllowShader_Flag = 0x04, + kAllowBlender_Flag = 0x08, + kSamplesOutsideMain_Flag = 0x10, + kUsesColorTransform_Flag = 0x20, + kAlwaysOpaque_Flag = 0x40, + kAlphaUnchanged_Flag = 0x80, + }; + + SkRuntimeEffect(std::unique_ptr baseProgram, + const Options& options, + const SkSL::FunctionDefinition& main, + std::vector&& uniforms, + std::vector&& children, + std::vector&& sampleUsages, + uint32_t flags); + + sk_sp makeUnoptimizedClone(); + + static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind); + + static Result MakeInternal(std::unique_ptr program, + const Options& options, + SkSL::ProgramKind kind); + + static SkSL::ProgramSettings MakeSettings(const Options& options); + + uint32_t hash() const { return fHash; } + bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); } + bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); } + bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); } + bool alwaysOpaque() const { return (fFlags & kAlwaysOpaque_Flag); } + bool isAlphaUnchanged() const { return (fFlags & kAlphaUnchanged_Flag); } + + const SkFilterColorProgram* getFilterColorProgram() const; + const SkSL::RP::Program* getRPProgram(SkSL::DebugTracePriv* debugTrace) const; + +#if defined(SK_GANESH) + friend class GrSkSLFP; // fBaseProgram, fSampleUsages + friend class GrGLSLSkSLFP; // +#endif + + friend class SkRTShader; // fBaseProgram, fMain, fSampleUsages, getRPProgram() + friend class SkRuntimeBlender; // + friend class SkRuntimeColorFilter; // + + friend class SkFilterColorProgram; + friend class SkRuntimeEffectPriv; + + uint32_t fHash; + + std::unique_ptr fBaseProgram; + std::unique_ptr fRPProgram; + mutable SkOnce fCompileRPProgramOnce; + const SkSL::FunctionDefinition& fMain; + std::vector fUniforms; + std::vector fChildren; + std::vector fSampleUsages; + + std::unique_ptr fFilterColorProgram; + + uint32_t fFlags; // Flags +}; + +/** Base class for SkRuntimeShaderBuilder, defined below. */ +class SkRuntimeEffectBuilder { +public: + struct BuilderUniform { + // Copy 'val' to this variable. No type conversion is performed - 'val' must be same + // size as expected by the effect. Information about the variable can be queried by + // looking at fVar. If the size is incorrect, no copy will be performed, and debug + // builds will abort. If this is the result of querying a missing variable, fVar will + // be nullptr, and assigning will also do nothing (and abort in debug builds). + template + std::enable_if_t::value, BuilderUniform&> operator=( + const T& val) { + if (!fVar) { + SkDEBUGFAIL("Assigning to missing variable"); + } else if (sizeof(val) != fVar->sizeInBytes()) { + SkDEBUGFAIL("Incorrect value size"); + } else { + memcpy(SkTAddOffset(fOwner->writableUniformData(), fVar->offset), + &val, sizeof(val)); + } + return *this; + } + + BuilderUniform& operator=(const SkMatrix& val) { + if (!fVar) { + SkDEBUGFAIL("Assigning to missing variable"); + } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { + SkDEBUGFAIL("Incorrect value size"); + } else { + float* data = SkTAddOffset(fOwner->writableUniformData(), + (ptrdiff_t)fVar->offset); + data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6); + data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7); + data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8); + } + return *this; + } + + template + bool set(const T val[], const int count) { + static_assert(std::is_trivially_copyable::value, "Value must be trivial copyable"); + if (!fVar) { + SkDEBUGFAIL("Assigning to missing variable"); + return false; + } else if (sizeof(T) * count != fVar->sizeInBytes()) { + SkDEBUGFAIL("Incorrect value size"); + return false; + } else { + memcpy(SkTAddOffset(fOwner->writableUniformData(), fVar->offset), + val, sizeof(T) * count); + } + return true; + } + + SkRuntimeEffectBuilder* fOwner; + const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found + }; + + struct BuilderChild { + template BuilderChild& operator=(sk_sp val) { + if (!fChild) { + SkDEBUGFAIL("Assigning to missing child"); + } else { + fOwner->fChildren[(size_t)fChild->index] = std::move(val); + } + return *this; + } + + BuilderChild& operator=(std::nullptr_t) { + if (!fChild) { + SkDEBUGFAIL("Assigning to missing child"); + } else { + fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{}; + } + return *this; + } + + SkRuntimeEffectBuilder* fOwner; + const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found + }; + + const SkRuntimeEffect* effect() const { return fEffect.get(); } + + BuilderUniform uniform(std::string_view name) { return { this, fEffect->findUniform(name) }; } + BuilderChild child(std::string_view name) { return { this, fEffect->findChild(name) }; } + + // Get access to the collated uniforms and children (in the order expected by APIs like + // makeShader on the effect): + sk_sp uniforms() { return fUniforms; } + SkSpan children() { return fChildren; } + +protected: + SkRuntimeEffectBuilder() = delete; + explicit SkRuntimeEffectBuilder(sk_sp effect) + : fEffect(std::move(effect)) + , fUniforms(SkData::MakeZeroInitialized(fEffect->uniformSize())) + , fChildren(fEffect->children().size()) {} + explicit SkRuntimeEffectBuilder(sk_sp effect, sk_sp uniforms) + : fEffect(std::move(effect)) + , fUniforms(std::move(uniforms)) + , fChildren(fEffect->children().size()) {} + + SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default; + SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default; + + SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete; + SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete; + +private: + void* writableUniformData() { + if (!fUniforms->unique()) { + fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size()); + } + return fUniforms->writable_data(); + } + + sk_sp fEffect; + sk_sp fUniforms; + std::vector fChildren; +}; + +/** + * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects. + * + * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change! + * + * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and + * provides named access to the 'uniform' variables in that block, as well as named access + * to a list of child shader slots. Usage: + * + * sk_sp effect = ...; + * SkRuntimeShaderBuilder builder(effect); + * builder.uniform("some_uniform_float") = 3.14f; + * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...); + * builder.child("some_child_effect") = mySkImage->makeShader(...); + * ... + * sk_sp shader = builder.makeShader(nullptr, false); + * + * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect, + * so can be used as-is or serve as inspiration for other interfaces or binding techniques. + */ +class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder { +public: + explicit SkRuntimeShaderBuilder(sk_sp); + // This is currently required by Android Framework but may go away if that dependency + // can be removed. + SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default; + ~SkRuntimeShaderBuilder(); + + sk_sp makeShader(const SkMatrix* localMatrix = nullptr); + sk_sp makeImage(GrRecordingContext*, + const SkMatrix* localMatrix, + SkImageInfo resultInfo, + bool mipmapped); + +private: + using INHERITED = SkRuntimeEffectBuilder; + + explicit SkRuntimeShaderBuilder(sk_sp effect, sk_sp uniforms) + : INHERITED(std::move(effect), std::move(uniforms)) {} + + friend class SkRuntimeImageFilter; +}; + +/** + * SkRuntimeColorFilterBuilder makes it easy to setup and assign uniforms to runtime color filters. + */ +class SK_API SkRuntimeColorFilterBuilder : public SkRuntimeEffectBuilder { +public: + explicit SkRuntimeColorFilterBuilder(sk_sp); + ~SkRuntimeColorFilterBuilder(); + + SkRuntimeColorFilterBuilder(const SkRuntimeColorFilterBuilder&) = delete; + SkRuntimeColorFilterBuilder& operator=(const SkRuntimeColorFilterBuilder&) = delete; + + sk_sp makeColorFilter(); + +private: + using INHERITED = SkRuntimeEffectBuilder; +}; + +/** + * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders. + */ +class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder { +public: + explicit SkRuntimeBlendBuilder(sk_sp); + ~SkRuntimeBlendBuilder(); + + SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete; + SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete; + + sk_sp makeBlender(); + +private: + using INHERITED = SkRuntimeEffectBuilder; +}; + +#endif // SK_ENABLE_SKSL + +#endif // SkRuntimeEffect_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkShaderMaskFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkShaderMaskFilter.h new file mode 100644 index 00000000000000..84937967bfdab8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkShaderMaskFilter.h @@ -0,0 +1,26 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkShaderMaskFilter_DEFINED +#define SkShaderMaskFilter_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkMaskFilter; +class SkShader; + +class SK_API SkShaderMaskFilter { +public: + static sk_sp Make(sk_sp shader); + +private: + static void RegisterFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkStrokeAndFillPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkStrokeAndFillPathEffect.h new file mode 100644 index 00000000000000..fbde6493340a96 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkStrokeAndFillPathEffect.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStrokeAndFillPathEffect_DEFINED +#define SkStrokeAndFillPathEffect_DEFINED + +#include "include/core/SkPaint.h" +#include "include/core/SkPathEffect.h" +#include "include/pathops/SkPathOps.h" + +class SK_API SkStrokeAndFillPathEffect { +public: + /* If the paint is set to stroke, this will add the stroke and fill geometries + * together (hoping that the winding-direction works out). + * + * If the paint is set to fill, this effect is ignored. + * + * Note that if the paint is set to stroke and the stroke-width is 0, then + * this will turn the geometry into just a fill. + */ + static sk_sp Make(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTableColorFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTableColorFilter.h new file mode 100644 index 00000000000000..9a6ce3253e27d3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTableColorFilter.h @@ -0,0 +1,29 @@ +/* +* Copyright 2015 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef SkTableColorFilter_DEFINED +#define SkTableColorFilter_DEFINED + +#include "include/core/SkColorFilter.h" + +// (DEPRECATED) These factory functions are deprecated. Please use the ones in +// SkColorFilters (i.e., Table and TableARGB). +class SK_API SkTableColorFilter { +public: + static sk_sp Make(const uint8_t table[256]) { + return SkColorFilters::Table(table); + } + + static sk_sp MakeARGB(const uint8_t tableA[256], + const uint8_t tableR[256], + const uint8_t tableG[256], + const uint8_t tableB[256]) { + return SkColorFilters::TableARGB(tableA, tableR, tableG, tableB); + } +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTableMaskFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTableMaskFilter.h new file mode 100644 index 00000000000000..412f138353f336 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTableMaskFilter.h @@ -0,0 +1,41 @@ +/* + * 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 SkTableMaskFilter_DEFINED +#define SkTableMaskFilter_DEFINED + +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include + +class SkMaskFilter; + +/** \class SkTableMaskFilter + + Applies a table lookup on each of the alpha values in the mask. + Helper methods create some common tables (e.g. gamma, clipping) + */ +class SK_API SkTableMaskFilter { +public: + /** Utility that sets the gamma table + */ + static void MakeGammaTable(uint8_t table[256], SkScalar gamma); + + /** Utility that creates a clipping table: clamps values below min to 0 + and above max to 255, and rescales the remaining into 0..255 + */ + static void MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max); + + static SkMaskFilter* Create(const uint8_t table[256]); + static SkMaskFilter* CreateGamma(SkScalar gamma); + static SkMaskFilter* CreateClip(uint8_t min, uint8_t max); + + SkTableMaskFilter() = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTrimPathEffect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTrimPathEffect.h new file mode 100644 index 00000000000000..3e6fb7c3424a79 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/effects/SkTrimPathEffect.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTrimPathEffect_DEFINED +#define SkTrimPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPathEffect; + +class SK_API SkTrimPathEffect { +public: + enum class Mode { + kNormal, // return the subset path [start,stop] + kInverted, // return the complement/subset paths [0,start] + [stop,1] + }; + + /** + * Take start and stop "t" values (values between 0...1), and return a path that is that + * subset of the original path. + * + * e.g. + * Make(0.5, 1.0) --> return the 2nd half of the path + * Make(0.33333, 0.66667) --> return the middle third of the path + * + * The trim values apply to the entire path, so if it contains several contours, all of them + * are including in the calculation. + * + * startT and stopT must be 0..1 inclusive. If they are outside of that interval, they will + * be pinned to the nearest legal value. If either is NaN, null will be returned. + * + * Note: for Mode::kNormal, this will return one (logical) segment (even if it is spread + * across multiple contours). For Mode::kInverted, this will return 2 logical + * segments: stopT..1 and 0...startT, in this order. + */ + static sk_sp Make(SkScalar startT, SkScalar stopT, Mode = Mode::kNormal); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkEncoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkEncoder.h new file mode 100644 index 00000000000000..8f76e8016c8487 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkEncoder.h @@ -0,0 +1,63 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEncoder_DEFINED +#define SkEncoder_DEFINED + +#include "include/core/SkPixmap.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkNoncopyable.h" +#include "include/private/base/SkTemplates.h" + +#include +#include + +class SK_API SkEncoder : SkNoncopyable { +public: + /** + * A single frame to be encoded into an animated image. + * + * If a frame does not fit in the canvas size, this is an error. + * TODO(skia:13705): Add offsets when we have support for an encoder that supports using + * offsets. + */ + struct SK_API Frame { + /** + * Pixmap of the frame. + */ + SkPixmap pixmap; + /** + * Duration of the frame in millseconds. + */ + int duration; + }; + + /** + * Encode |numRows| rows of input. If the caller requests more rows than are remaining + * in the src, this will encode all of the remaining rows. |numRows| must be greater + * than zero. + */ + bool encodeRows(int numRows); + + virtual ~SkEncoder() {} + +protected: + + virtual bool onEncodeRows(int numRows) = 0; + + SkEncoder(const SkPixmap& src, size_t storageBytes) + : fSrc(src) + , fCurrRow(0) + , fStorage(storageBytes) + {} + + const SkPixmap& fSrc; + int fCurrRow; + skia_private::AutoTMalloc fStorage; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkICC.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkICC.h new file mode 100644 index 00000000000000..b14836b2ab6aa3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkICC.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkICC_DEFINED +#define SkICC_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +class SkData; +struct skcms_ICCProfile; +struct skcms_Matrix3x3; +struct skcms_TransferFunction; + +SK_API sk_sp SkWriteICCProfile(const skcms_TransferFunction&, + const skcms_Matrix3x3& toXYZD50); + +SK_API sk_sp SkWriteICCProfile(const skcms_ICCProfile*, const char* description); + +// Utility function for populating the grid_16 member of skcms_A2B and skcms_B2A +// structures. This converts a point in XYZD50 to its representation in grid_16_lab. +// It will write 6 bytes. The behavior of this function matches how skcms will decode +// values, but might not match the specification, see https://crbug.com/skia/13807. +SK_API void SkICCFloatXYZD50ToGrid16Lab(const float* float_xyz, uint8_t* grid16_lab); + +// Utility function for popluating the table_16 member of skcms_Curve structure. +// This converts a float to its representation in table_16. It will write 2 bytes. +SK_API void SkICCFloatToTable16(const float f, uint8_t* table_16); + +#endif//SkICC_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkJpegEncoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkJpegEncoder.h new file mode 100644 index 00000000000000..f7e8effa7fa5b7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkJpegEncoder.h @@ -0,0 +1,128 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJpegEncoder_DEFINED +#define SkJpegEncoder_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +class SkColorSpace; +class SkData; +class SkEncoder; +class SkPixmap; +class SkWStream; +class SkImage; +class GrDirectContext; +class SkYUVAPixmaps; +struct skcms_ICCProfile; + +namespace SkJpegEncoder { + +enum class AlphaOption { + kIgnore, + kBlendOnBlack, +}; + +enum class Downsample { + /** + * Reduction by a factor of two in both the horizontal and vertical directions. + */ + k420, + + /** + * Reduction by a factor of two in the horizontal direction. + */ + k422, + + /** + * No downsampling. + */ + k444, +}; + +struct Options { + /** + * |fQuality| must be in [0, 100] where 0 corresponds to the lowest quality. + */ + int fQuality = 100; + + /** + * Choose the downsampling factor for the U and V components. This is only + * meaningful if the |src| is not kGray, since kGray will not be encoded as YUV. + * This is ignored in favor of |src|'s subsampling when |src| is an SkYUVAPixmaps. + * + * Our default value matches the libjpeg-turbo default. + */ + Downsample fDownsample = Downsample::k420; + + /** + * Jpegs must be opaque. This instructs the encoder on how to handle input + * images with alpha. + * + * The default is to ignore the alpha channel and treat the image as opaque. + * Another option is to blend the pixels onto a black background before encoding. + * In the second case, the encoder supports linear or legacy blending. + */ + AlphaOption fAlphaOption = AlphaOption::kIgnore; + + /** + * Optional XMP metadata. + */ + const SkData* xmpMetadata = nullptr; + + /** + * An optional ICC profile to override the default behavior. + * + * The default behavior is to generate an ICC profile using a primary matrix and + * analytic transfer function. If the color space of |src| cannot be represented + * in this way (e.g, it is HLG or PQ), then no profile will be embedded. + */ + const skcms_ICCProfile* fICCProfile = nullptr; + const char* fICCProfileDescription = nullptr; +}; + +/** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ +SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); +SK_API bool Encode(SkWStream* dst, + const SkYUVAPixmaps& src, + const SkColorSpace* srcColorSpace, + const Options& options); + +/** +* Encode the provided image and return the resulting bytes. If the image was created as +* a texture-backed image on a GPU context, that |ctx| must be provided so the pixels +* can be read before being encoded. For raster-backed images, |ctx| can be nullptr. +* |options| may be used to control the encoding behavior. +* +* Returns nullptr if the pixels could not be read or encoding otherwise fails. +*/ +SK_API sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options); + +/** + * Create a jpeg encoder that will encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * |dst| is unowned but must remain valid for the lifetime of the object. + * + * This returns nullptr on an invalid or unsupported |src|. + */ +SK_API std::unique_ptr Make(SkWStream* dst, const SkPixmap& src, const Options& options); +SK_API std::unique_ptr Make(SkWStream* dst, + const SkYUVAPixmaps& src, + const SkColorSpace* srcColorSpace, + const Options& options); +} // namespace SkJpegEncoder + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkPngEncoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkPngEncoder.h new file mode 100644 index 00000000000000..b26befa323ef30 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkPngEncoder.h @@ -0,0 +1,117 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPngEncoder_DEFINED +#define SkPngEncoder_DEFINED + +#include "include/core/SkDataTable.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +// TODO(kjlubick) update clients to directly include this +#include "include/encode/SkEncoder.h" // IWYU pragma: keep + +#include + +class GrDirectContext; +class SkData; +class SkImage; +class SkPixmap; +class SkWStream; +struct skcms_ICCProfile; + +namespace SkPngEncoder { + +enum class FilterFlag : int { + kZero = 0x00, + kNone = 0x08, + kSub = 0x10, + kUp = 0x20, + kAvg = 0x40, + kPaeth = 0x80, + kAll = kNone | kSub | kUp | kAvg | kPaeth, +}; + +inline FilterFlag operator|(FilterFlag x, FilterFlag y) { return (FilterFlag)((int)x | (int)y); } + +struct Options { + /** + * Selects which filtering strategies to use. + * + * If a single filter is chosen, libpng will use that filter for every row. + * + * If multiple filters are chosen, libpng will use a heuristic to guess which filter + * will encode smallest, then apply that filter. This happens on a per row basis, + * different rows can use different filters. + * + * Using a single filter (or less filters) is typically faster. Trying all of the + * filters may help minimize the output file size. + * + * Our default value matches libpng's default. + */ + FilterFlag fFilterFlags = FilterFlag::kAll; + + /** + * Must be in [0, 9] where 9 corresponds to maximal compression. This value is passed + * directly to zlib. 0 is a special case to skip zlib entirely, creating dramatically + * larger pngs. + * + * Our default value matches libpng's default. + */ + int fZLibLevel = 6; + + /** + * Represents comments in the tEXt ancillary chunk of the png. + * The 2i-th entry is the keyword for the i-th comment, + * and the (2i + 1)-th entry is the text for the i-th comment. + */ + sk_sp fComments; + + /** + * An optional ICC profile to override the default behavior. + * + * The default behavior is to generate an ICC profile using a primary matrix and + * analytic transfer function. If the color space of |src| cannot be represented + * in this way (e.g, it is HLG or PQ), then no profile will be embedded. + */ + const skcms_ICCProfile* fICCProfile = nullptr; + const char* fICCProfileDescription = nullptr; +}; + +/** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ +SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); + +/** +* Encode the provided image and return the resulting bytes. If the image was created as +* a texture-backed image on a GPU context, that |ctx| must be provided so the pixels +* can be read before being encoded. For raster-backed images, |ctx| can be nullptr. +* |options| may be used to control the encoding behavior. +* +* Returns nullptr if the pixels could not be read or encoding otherwise fails. +*/ +SK_API sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options); + +/** + * Create a png encoder that will encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * The primary use of this is incremental encoding of the pixels. + * + * |dst| is unowned but must remain valid for the lifetime of the object. + * + * This returns nullptr on an invalid or unsupported |src|. + */ +SK_API std::unique_ptr Make(SkWStream* dst, const SkPixmap& src, const Options& options); + +} // namespace SkPngEncoder + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkWebpEncoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkWebpEncoder.h new file mode 100644 index 00000000000000..fe11044e738046 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/encode/SkWebpEncoder.h @@ -0,0 +1,92 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkWebpEncoder_DEFINED +#define SkWebpEncoder_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSpan.h" // IWYU pragma: keep +#include "include/encode/SkEncoder.h" +#include "include/private/base/SkAPI.h" + +class SkPixmap; +class SkWStream; +class SkData; +class GrDirectContext; +class SkImage; +struct skcms_ICCProfile; + +namespace SkWebpEncoder { + +enum class Compression { + kLossy, + kLossless, +}; + +struct SK_API Options { + /** + * |fCompression| determines whether we will use webp lossy or lossless compression. + * + * |fQuality| must be in [0.0f, 100.0f]. + * If |fCompression| is kLossy, |fQuality| corresponds to the visual quality of the + * encoding. Decreasing the quality will result in a smaller encoded image. + * If |fCompression| is kLossless, |fQuality| corresponds to the amount of effort + * put into the encoding. Lower values will compress faster into larger files, + * while larger values will compress slower into smaller files. + * + * This scheme is designed to match the libwebp API. + */ + Compression fCompression = Compression::kLossy; + float fQuality = 100.0f; + + /** + * An optional ICC profile to override the default behavior. + * + * The default behavior is to generate an ICC profile using a primary matrix and + * analytic transfer function. If the color space of |src| cannot be represented + * in this way (e.g, it is HLG or PQ), then no profile will be embedded. + */ + const skcms_ICCProfile* fICCProfile = nullptr; + const char* fICCProfileDescription = nullptr; +}; + +/** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ +SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); + +/** +* Encode the provided image and return the resulting bytes. If the image was created as +* a texture-backed image on a GPU context, that |ctx| must be provided so the pixels +* can be read before being encoded. For raster-backed images, |ctx| can be nullptr. +* |options| may be used to control the encoding behavior. +* +* Returns nullptr if the pixels could not be read or encoding otherwise fails. +*/ +SK_API sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options); + +/** + * Encode the |src| frames to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * The size of the first frame will be used as the canvas size. If any other frame does + * not match the canvas size, this is an error. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + * + * Note: libwebp API also supports set background color, loop limit and customize + * lossy/lossless for each frame. These could be added later as needed. + */ +SK_API bool EncodeAnimated(SkWStream* dst, + SkSpan src, + const Options& options); +} // namespace SkWebpEncoder + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GpuTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GpuTypes.h new file mode 100644 index 00000000000000..e2e3961f8b9e5f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GpuTypes.h @@ -0,0 +1,72 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_GpuTypes_DEFINED +#define skgpu_GpuTypes_DEFINED + +#include "include/core/SkTypes.h" + +/** + * This file includes numerous public types that are used by all of our gpu backends. + */ + +namespace skgpu { + +/** + * Possible 3D APIs that may be used by Graphite. + */ +enum class BackendApi : unsigned { + kDawn, + kMetal, + kVulkan, + kMock, +}; + +/** Indicates whether an allocation should count against a cache budget. */ +enum class Budgeted : bool { + kNo = false, + kYes = true, +}; + +/** + * Value passed into various callbacks to tell the client the result of operations connected to a + * specific callback. The actual interpretation of kFailed and kSuccess are dependent on the + * specific callbacks and are documented with the callback itself. + */ +enum class CallbackResult : bool { + kFailed = false, + kSuccess = true, +}; + +/** + * Is the texture mipmapped or not + */ +enum class Mipmapped : bool { + kNo = false, + kYes = true, +}; + +/** + * Is the data protected on the GPU or not. + */ +enum class Protected : bool { + kNo = false, + kYes = true, +}; + +/** + * Is a texture renderable or not + */ +enum class Renderable : bool { + kNo = false, + kYes = true, +}; + +} // namespace skgpu + + +#endif // skgpu_GpuTypes_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendDrawableInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendDrawableInfo.h new file mode 100644 index 00000000000000..bda1e769fd05e3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendDrawableInfo.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendDrawableInfo_DEFINED +#define GrBackendDrawableInfo_DEFINED + +#include "include/gpu/GrTypes.h" + +#include "include/gpu/vk/GrVkTypes.h" + +class SK_API GrBackendDrawableInfo { +public: + // Creates an invalid backend drawable info. + GrBackendDrawableInfo() : fIsValid(false) {} + + GrBackendDrawableInfo(const GrVkDrawableInfo& info) + : fIsValid(true) + , fBackend(GrBackendApi::kVulkan) + , fVkInfo(info) {} + + // Returns true if the backend texture has been initialized. + bool isValid() const { return fIsValid; } + + GrBackendApi backend() const { return fBackend; } + + bool getVkDrawableInfo(GrVkDrawableInfo* outInfo) const { + if (this->isValid() && GrBackendApi::kVulkan == fBackend) { + *outInfo = fVkInfo; + return true; + } + return false; + } + +private: + bool fIsValid; + GrBackendApi fBackend; + GrVkDrawableInfo fVkInfo; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSemaphore.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSemaphore.h new file mode 100644 index 00000000000000..13d07928e71ed4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSemaphore.h @@ -0,0 +1,140 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendSemaphore_DEFINED +#define GrBackendSemaphore_DEFINED + +#include "include/gpu/GrTypes.h" + +#include "include/gpu/gl/GrGLTypes.h" + +#ifdef SK_METAL +#include "include/gpu/mtl/GrMtlTypes.h" +#endif + +#ifdef SK_VULKAN +#include "include/gpu/vk/GrVkTypes.h" +#endif + +#ifdef SK_DIRECT3D +#include "include/private/gpu/ganesh/GrD3DTypesMinimal.h" +#endif + +/** + * Wrapper class for passing into and receiving data from Ganesh about a backend semaphore object. + */ +class GrBackendSemaphore { +public: + // For convenience we just set the backend here to OpenGL. The GrBackendSemaphore cannot be used + // until either init* is called, which will set the appropriate GrBackend. + GrBackendSemaphore() + : fBackend(GrBackendApi::kOpenGL), fGLSync(nullptr), fIsInitialized(false) {} + +#ifdef SK_DIRECT3D + // We only need to specify these if Direct3D is enabled, because it requires special copy + // characteristics. + ~GrBackendSemaphore(); + GrBackendSemaphore(const GrBackendSemaphore&); + GrBackendSemaphore& operator=(const GrBackendSemaphore&); +#endif + + void initGL(GrGLsync sync) { + fBackend = GrBackendApi::kOpenGL; + fGLSync = sync; + fIsInitialized = true; + } + +#ifdef SK_VULKAN + void initVulkan(VkSemaphore semaphore) { + fBackend = GrBackendApi::kVulkan; + fVkSemaphore = semaphore; + + fIsInitialized = true; + } + + VkSemaphore vkSemaphore() const { + if (!fIsInitialized || GrBackendApi::kVulkan != fBackend) { + return VK_NULL_HANDLE; + } + return fVkSemaphore; + } +#endif + +#ifdef SK_METAL + // It is the creator's responsibility to ref the MTLEvent passed in here, via __bridge_retained. + // The other end will wrap this BackendSemaphore and take the ref, via __bridge_transfer. + void initMetal(GrMTLHandle event, uint64_t value) { + fBackend = GrBackendApi::kMetal; + fMtlEvent = event; + fMtlValue = value; + + fIsInitialized = true; + } + + GrMTLHandle mtlSemaphore() const { + if (!fIsInitialized || GrBackendApi::kMetal != fBackend) { + return nullptr; + } + return fMtlEvent; + } + + uint64_t mtlValue() const { + if (!fIsInitialized || GrBackendApi::kMetal != fBackend) { + return 0; + } + return fMtlValue; + } + +#endif + +#ifdef SK_DIRECT3D + void initDirect3D(const GrD3DFenceInfo& info) { + fBackend = GrBackendApi::kDirect3D; + this->assignD3DFenceInfo(info); + fIsInitialized = true; + } +#endif + + bool isInitialized() const { return fIsInitialized; } + + GrGLsync glSync() const { + if (!fIsInitialized || GrBackendApi::kOpenGL != fBackend) { + return nullptr; + } + return fGLSync; + } + + +#ifdef SK_DIRECT3D + bool getD3DFenceInfo(GrD3DFenceInfo* outInfo) const; +#endif + +private: +#ifdef SK_DIRECT3D + void assignD3DFenceInfo(const GrD3DFenceInfo& info); +#endif + + GrBackendApi fBackend; + union { + GrGLsync fGLSync; +#ifdef SK_VULKAN + VkSemaphore fVkSemaphore; +#endif +#ifdef SK_METAL + GrMTLHandle fMtlEvent; // Expected to be an id +#endif +#ifdef SK_DIRECT3D + GrD3DFenceInfo* fD3DFenceInfo; +#endif + }; +#ifdef SK_METAL + uint64_t fMtlValue; +#endif + bool fIsInitialized; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSurface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSurface.h new file mode 100644 index 00000000000000..37ab666d52ec42 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSurface.h @@ -0,0 +1,667 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendSurface_DEFINED +#define GrBackendSurface_DEFINED + +// This include of GrBackendSurfaceMutableState is not needed here, but some clients were depending +// on the include here instead of including it themselves. Adding this back here until we can fix +// up clients so it can be removed. +#include "include/gpu/GrBackendSurfaceMutableState.h" + +#include "include/gpu/GrSurfaceInfo.h" +#include "include/gpu/GrTypes.h" +#include "include/gpu/MutableTextureState.h" +#ifdef SK_GL +#include "include/gpu/gl/GrGLTypes.h" +#include "include/private/gpu/ganesh/GrGLTypesPriv.h" +#endif +#include "include/gpu/mock/GrMockTypes.h" +#ifdef SK_VULKAN +#include "include/gpu/vk/GrVkTypes.h" +#include "include/private/gpu/ganesh/GrVkTypesPriv.h" +#endif + +#ifdef SK_DAWN +#include "include/gpu/dawn/GrDawnTypes.h" +#endif + +#include + +class GrVkImageLayout; +class GrGLTextureParameters; +class GrColorFormatDesc; +enum class SkTextureCompressionType; + +namespace skgpu { +class MutableTextureStateRef; +} + +#ifdef SK_DAWN +#include "webgpu/webgpu_cpp.h" +#endif + +#ifdef SK_METAL +#include "include/gpu/mtl/GrMtlTypes.h" +#endif + +#ifdef SK_DIRECT3D +#include "include/private/gpu/ganesh/GrD3DTypesMinimal.h" +class GrD3DResourceState; +#endif + +#if defined(SK_DEBUG) || GR_TEST_UTILS +class SkString; +#endif + +#if !defined(SK_GANESH) + +// SkSurfaceCharacterization always needs a minimal version of this +class SK_API GrBackendFormat { +public: + bool isValid() const { return false; } +}; + +// SkSurface and SkImage rely on a minimal version of these always being available +class SK_API GrBackendTexture { +public: + GrBackendTexture() {} + + bool isValid() const { return false; } +}; + +class SK_API GrBackendRenderTarget { +public: + GrBackendRenderTarget() {} + + bool isValid() const { return false; } + bool isFramebufferOnly() const { return false; } +}; +#else + +enum class GrGLFormat; + +class SK_API GrBackendFormat { +public: + // Creates an invalid backend format. + GrBackendFormat() {} + GrBackendFormat(const GrBackendFormat&); + GrBackendFormat& operator=(const GrBackendFormat&); + +#ifdef SK_GL + static GrBackendFormat MakeGL(GrGLenum format, GrGLenum target) { + return GrBackendFormat(format, target); + } +#endif + +#ifdef SK_VULKAN + static GrBackendFormat MakeVk(VkFormat format, bool willUseDRMFormatModifiers = false) { + return GrBackendFormat(format, GrVkYcbcrConversionInfo(), willUseDRMFormatModifiers); + } + + static GrBackendFormat MakeVk(const GrVkYcbcrConversionInfo& ycbcrInfo, + bool willUseDRMFormatModifiers = false); +#endif + +#ifdef SK_DAWN + static GrBackendFormat MakeDawn(wgpu::TextureFormat format) { + return GrBackendFormat(format); + } +#endif + +#ifdef SK_METAL + static GrBackendFormat MakeMtl(GrMTLPixelFormat format) { + return GrBackendFormat(format); + } +#endif + +#ifdef SK_DIRECT3D + static GrBackendFormat MakeDxgi(DXGI_FORMAT format) { + return GrBackendFormat(format); + } +#endif + + static GrBackendFormat MakeMock(GrColorType colorType, + SkTextureCompressionType compression, + bool isStencilFormat = false); + + bool operator==(const GrBackendFormat& that) const; + bool operator!=(const GrBackendFormat& that) const { return !(*this == that); } + + GrBackendApi backend() const { return fBackend; } + GrTextureType textureType() const { return fTextureType; } + + /** + * Gets the channels present in the format as a bitfield of SkColorChannelFlag values. + * Luminance channels are reported as kGray_SkColorChannelFlag. + */ + uint32_t channelMask() const; + + GrColorFormatDesc desc() const; + +#ifdef SK_GL + /** + * If the backend API is GL this gets the format as a GrGLFormat. Otherwise, returns + * GrGLFormat::kUnknown. + */ + GrGLFormat asGLFormat() const; + + GrGLenum asGLFormatEnum() const; +#endif + +#ifdef SK_VULKAN + /** + * If the backend API is Vulkan this gets the format as a VkFormat and returns true. Otherwise, + * returns false. + */ + bool asVkFormat(VkFormat*) const; + + const GrVkYcbcrConversionInfo* getVkYcbcrConversionInfo() const; +#endif + +#ifdef SK_DAWN + /** + * If the backend API is Dawn this gets the format as a wgpu::TextureFormat and returns true. + * Otherwise, returns false. + */ + bool asDawnFormat(wgpu::TextureFormat*) const; +#endif + +#ifdef SK_METAL + /** + * If the backend API is Metal this gets the format as a GrMtlPixelFormat. Otherwise, + * Otherwise, returns MTLPixelFormatInvalid. + */ + GrMTLPixelFormat asMtlFormat() const; +#endif + +#ifdef SK_DIRECT3D + /** + * If the backend API is Direct3D this gets the format as a DXGI_FORMAT and returns true. + * Otherwise, returns false. + */ + bool asDxgiFormat(DXGI_FORMAT*) const; +#endif + + /** + * If the backend API is not Mock these three calls will return kUnknown, kNone or false, + * respectively. Otherwise, only one of the following can be true. The GrColorType is not + * kUnknown, the compression type is not kNone, or this is a mock stencil format. + */ + GrColorType asMockColorType() const; + SkTextureCompressionType asMockCompressionType() const; + bool isMockStencilFormat() const; + + // If possible, copies the GrBackendFormat and forces the texture type to be Texture2D. If the + // GrBackendFormat was for Vulkan and it originally had a GrVkYcbcrConversionInfo, we will + // remove the conversion and set the format to be VK_FORMAT_R8G8B8A8_UNORM. + GrBackendFormat makeTexture2D() const; + + // Returns true if the backend format has been initialized. + bool isValid() const { return fValid; } + +#if defined(SK_DEBUG) || GR_TEST_UTILS + SkString toStr() const; +#endif + +private: +#ifdef SK_GL + GrBackendFormat(GrGLenum format, GrGLenum target); +#endif + +#ifdef SK_VULKAN + GrBackendFormat(const VkFormat vkFormat, const GrVkYcbcrConversionInfo&, + bool willUseDRMFormatModifiers); +#endif + +#ifdef SK_DAWN + GrBackendFormat(wgpu::TextureFormat format); +#endif + +#ifdef SK_METAL + GrBackendFormat(const GrMTLPixelFormat mtlFormat); +#endif + +#ifdef SK_DIRECT3D + GrBackendFormat(DXGI_FORMAT dxgiFormat); +#endif + + GrBackendFormat(GrColorType, SkTextureCompressionType, bool isStencilFormat); + +#ifdef SK_DEBUG + bool validateMock() const; +#endif + + GrBackendApi fBackend = GrBackendApi::kMock; + bool fValid = false; + + union { +#ifdef SK_GL + GrGLenum fGLFormat; // the sized, internal format of the GL resource +#endif +#ifdef SK_VULKAN + struct { + VkFormat fFormat; + GrVkYcbcrConversionInfo fYcbcrConversionInfo; + } fVk; +#endif +#ifdef SK_DAWN + wgpu::TextureFormat fDawnFormat; +#endif + +#ifdef SK_METAL + GrMTLPixelFormat fMtlFormat; +#endif + +#ifdef SK_DIRECT3D + DXGI_FORMAT fDxgiFormat; +#endif + struct { + GrColorType fColorType; + SkTextureCompressionType fCompressionType; + bool fIsStencilFormat; + } fMock; + }; + GrTextureType fTextureType = GrTextureType::kNone; +}; + +class SK_API GrBackendTexture { +public: + // Creates an invalid backend texture. + GrBackendTexture(); + +#ifdef SK_GL + // The GrGLTextureInfo must have a valid fFormat. + GrBackendTexture(int width, + int height, + GrMipmapped, + const GrGLTextureInfo& glInfo, + std::string_view label = {}); +#endif + +#ifdef SK_VULKAN + GrBackendTexture(int width, + int height, + const GrVkImageInfo& vkInfo, + std::string_view label = {}); +#endif + +#ifdef SK_METAL + GrBackendTexture(int width, + int height, + GrMipmapped, + const GrMtlTextureInfo& mtlInfo, + std::string_view label = {}); +#endif + +#ifdef SK_DIRECT3D + GrBackendTexture(int width, + int height, + const GrD3DTextureResourceInfo& d3dInfo, + std::string_view label = {}); +#endif + +#ifdef SK_DAWN + GrBackendTexture(int width, + int height, + const GrDawnTextureInfo& dawnInfo, + std::string_view label = {}); +#endif + + GrBackendTexture(int width, + int height, + GrMipmapped, + const GrMockTextureInfo& mockInfo, + std::string_view label = {}); + + GrBackendTexture(const GrBackendTexture& that); + + ~GrBackendTexture(); + + GrBackendTexture& operator=(const GrBackendTexture& that); + + SkISize dimensions() const { return {fWidth, fHeight}; } + int width() const { return fWidth; } + int height() const { return fHeight; } + std::string_view getLabel() const { return fLabel; } + GrMipmapped mipmapped() const { return fMipmapped; } + bool hasMipmaps() const { return fMipmapped == GrMipmapped::kYes; } + /** deprecated alias of hasMipmaps(). */ + bool hasMipMaps() const { return this->hasMipmaps(); } + GrBackendApi backend() const {return fBackend; } + GrTextureType textureType() const { return fTextureType; } + +#ifdef SK_GL + // If the backend API is GL, copies a snapshot of the GrGLTextureInfo struct into the passed in + // pointer and returns true. Otherwise returns false if the backend API is not GL. + bool getGLTextureInfo(GrGLTextureInfo*) const; + + // Call this to indicate that the texture parameters have been modified in the GL context + // externally to GrContext. + void glTextureParametersModified(); +#endif + +#ifdef SK_DAWN + // If the backend API is Dawn, copies a snapshot of the GrDawnTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Dawn. + bool getDawnTextureInfo(GrDawnTextureInfo*) const; +#endif + +#ifdef SK_VULKAN + // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed + // in pointer and returns true. This snapshot will set the fImageLayout to the current layout + // state. Otherwise returns false if the backend API is not Vulkan. + bool getVkImageInfo(GrVkImageInfo*) const; + + // Anytime the client changes the VkImageLayout of the VkImage captured by this + // GrBackendTexture, they must call this function to notify Skia of the changed layout. + void setVkImageLayout(VkImageLayout); +#endif + +#ifdef SK_METAL + // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Metal. + bool getMtlTextureInfo(GrMtlTextureInfo*) const; +#endif + +#ifdef SK_DIRECT3D + // If the backend API is Direct3D, copies a snapshot of the GrD3DTextureResourceInfo struct into + // the passed in pointer and returns true. This snapshot will set the fResourceState to the + // current resource state. Otherwise returns false if the backend API is not D3D. + bool getD3DTextureResourceInfo(GrD3DTextureResourceInfo*) const; + + // Anytime the client changes the D3D12_RESOURCE_STATES of the D3D12_RESOURCE captured by this + // GrBackendTexture, they must call this function to notify Skia of the changed layout. + void setD3DResourceState(GrD3DResourceStateEnum); +#endif + + // Get the GrBackendFormat for this texture (or an invalid format if this is not valid). + GrBackendFormat getBackendFormat() const; + + // If the backend API is Mock, copies a snapshot of the GrMockTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Mock. + bool getMockTextureInfo(GrMockTextureInfo*) const; + + // If the client changes any of the mutable backend of the GrBackendTexture they should call + // this function to inform Skia that those values have changed. The backend API specific state + // that can be set from this function are: + // + // Vulkan: VkImageLayout and QueueFamilyIndex + void setMutableState(const skgpu::MutableTextureState&); + + // Returns true if we are working with protected content. + bool isProtected() const; + + // Returns true if the backend texture has been initialized. + bool isValid() const { return fIsValid; } + + // Returns true if both textures are valid and refer to the same API texture. + bool isSameTexture(const GrBackendTexture&); + +#if GR_TEST_UTILS + static bool TestingOnly_Equals(const GrBackendTexture& , const GrBackendTexture&); +#endif + +private: + friend class GrVkGpu; // for getMutableState + sk_sp getMutableState() const; + +#ifdef SK_GL + friend class GrGLTexture; + friend class GrGLGpu; // for getGLTextureParams + GrBackendTexture(int width, + int height, + GrMipmapped, + const GrGLTextureInfo, + sk_sp, + std::string_view label = {}); + sk_sp getGLTextureParams() const; +#endif + +#ifdef SK_VULKAN + friend class GrVkTexture; + GrBackendTexture(int width, + int height, + const GrVkImageInfo& vkInfo, + sk_sp mutableState, + std::string_view label = {}); +#endif + +#ifdef SK_DIRECT3D + friend class GrD3DTexture; + friend class GrD3DGpu; // for getGrD3DResourceState + GrBackendTexture(int width, + int height, + const GrD3DTextureResourceInfo& vkInfo, + sk_sp state, + std::string_view label = {}); + sk_sp getGrD3DResourceState() const; +#endif + + // Free and release and resources being held by the GrBackendTexture. + void cleanup(); + + bool fIsValid; + int fWidth; // fMutableState; +}; + +class SK_API GrBackendRenderTarget { +public: + // Creates an invalid backend texture. + GrBackendRenderTarget(); + +#ifdef SK_GL + // The GrGLTextureInfo must have a valid fFormat. If wrapping in an SkSurface we require the + // stencil bits to be either 0, 8 or 16. + GrBackendRenderTarget(int width, + int height, + int sampleCnt, + int stencilBits, + const GrGLFramebufferInfo& glInfo); +#endif + +#ifdef SK_DAWN + // If wrapping in an SkSurface we require the stencil bits to be either 0, 8 or 16. + GrBackendRenderTarget(int width, + int height, + int sampleCnt, + int stencilBits, + const GrDawnRenderTargetInfo& dawnInfo); +#endif + +#ifdef SK_VULKAN + /** Deprecated. Sample count is now part of GrVkImageInfo. */ + GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo); + + GrBackendRenderTarget(int width, int height, const GrVkImageInfo& vkInfo); +#endif + +#ifdef SK_METAL + GrBackendRenderTarget(int width, + int height, + const GrMtlTextureInfo& mtlInfo); + /** Deprecated. Sample count is ignored and is instead retrieved from the MtlTexture. */ + GrBackendRenderTarget(int width, + int height, + int sampleCnt, + const GrMtlTextureInfo& mtlInfo); +#endif + +#ifdef SK_DIRECT3D + GrBackendRenderTarget(int width, + int height, + const GrD3DTextureResourceInfo& d3dInfo); +#endif + + GrBackendRenderTarget(int width, + int height, + int sampleCnt, + int stencilBits, + const GrMockRenderTargetInfo& mockInfo); + + ~GrBackendRenderTarget(); + + GrBackendRenderTarget(const GrBackendRenderTarget& that); + GrBackendRenderTarget& operator=(const GrBackendRenderTarget&); + + SkISize dimensions() const { return {fWidth, fHeight}; } + int width() const { return fWidth; } + int height() const { return fHeight; } + int sampleCnt() const { return fSampleCnt; } + int stencilBits() const { return fStencilBits; } + GrBackendApi backend() const {return fBackend; } + bool isFramebufferOnly() const { return fFramebufferOnly; } + +#ifdef SK_GL + // If the backend API is GL, copies a snapshot of the GrGLFramebufferInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not GL. + bool getGLFramebufferInfo(GrGLFramebufferInfo*) const; +#endif + +#ifdef SK_DAWN + // If the backend API is Dawn, copies a snapshot of the GrDawnRenderTargetInfo struct into the + // passed-in pointer and returns true. Otherwise returns false if the backend API is not Dawn. + bool getDawnRenderTargetInfo(GrDawnRenderTargetInfo*) const; +#endif + +#ifdef SK_VULKAN + // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed + // in pointer and returns true. This snapshot will set the fImageLayout to the current layout + // state. Otherwise returns false if the backend API is not Vulkan. + bool getVkImageInfo(GrVkImageInfo*) const; + + // Anytime the client changes the VkImageLayout of the VkImage captured by this + // GrBackendRenderTarget, they must call this function to notify Skia of the changed layout. + void setVkImageLayout(VkImageLayout); +#endif + +#ifdef SK_METAL + // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Metal. + bool getMtlTextureInfo(GrMtlTextureInfo*) const; +#endif + +#ifdef SK_DIRECT3D + // If the backend API is Direct3D, copies a snapshot of the GrMtlTextureInfo struct into the + // passed in pointer and returns true. Otherwise returns false if the backend API is not D3D. + bool getD3DTextureResourceInfo(GrD3DTextureResourceInfo*) const; + + // Anytime the client changes the D3D12_RESOURCE_STATES of the D3D12_RESOURCE captured by this + // GrBackendTexture, they must call this function to notify Skia of the changed layout. + void setD3DResourceState(GrD3DResourceStateEnum); +#endif + + // Get the GrBackendFormat for this render target (or an invalid format if this is not valid). + GrBackendFormat getBackendFormat() const; + + // If the backend API is Mock, copies a snapshot of the GrMockTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Mock. + bool getMockRenderTargetInfo(GrMockRenderTargetInfo*) const; + + // If the client changes any of the mutable backend of the GrBackendTexture they should call + // this function to inform Skia that those values have changed. The backend API specific state + // that can be set from this function are: + // + // Vulkan: VkImageLayout and QueueFamilyIndex + void setMutableState(const skgpu::MutableTextureState&); + + // Returns true if we are working with protected content. + bool isProtected() const; + + // Returns true if the backend texture has been initialized. + bool isValid() const { return fIsValid; } + + +#if GR_TEST_UTILS + static bool TestingOnly_Equals(const GrBackendRenderTarget&, const GrBackendRenderTarget&); +#endif + +private: + friend class GrVkGpu; // for getMutableState + sk_sp getMutableState() const; + +#ifdef SK_VULKAN + friend class GrVkRenderTarget; + GrBackendRenderTarget(int width, + int height, + const GrVkImageInfo& vkInfo, + sk_sp mutableState); +#endif + +#ifdef SK_DIRECT3D + friend class GrD3DGpu; + friend class GrD3DRenderTarget; + GrBackendRenderTarget(int width, + int height, + const GrD3DTextureResourceInfo& d3dInfo, + sk_sp state); + sk_sp getGrD3DResourceState() const; +#endif + + // Free and release and resources being held by the GrBackendTexture. + void cleanup(); + + bool fIsValid; + bool fFramebufferOnly = false; + int fWidth; // fMutableState; +}; + +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSurfaceMutableState.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSurfaceMutableState.h new file mode 100644 index 00000000000000..cbf27bf7e572c9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrBackendSurfaceMutableState.h @@ -0,0 +1,26 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendSurfaceMutableState_DEFINED +#define GrBackendSurfaceMutableState_DEFINED + +#include "include/gpu/MutableTextureState.h" + +class GrBackendSurfaceMutableState : public skgpu::MutableTextureState { +public: + GrBackendSurfaceMutableState() = default; + +#ifdef SK_VULKAN + GrBackendSurfaceMutableState(VkImageLayout layout, uint32_t queueFamilyIndex) + : skgpu::MutableTextureState(layout, queueFamilyIndex) {} +#endif + + GrBackendSurfaceMutableState(const GrBackendSurfaceMutableState& that) + : skgpu::MutableTextureState(that) {} +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrContextOptions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrContextOptions.h new file mode 100644 index 00000000000000..bf4ca409a8f6d8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrContextOptions.h @@ -0,0 +1,374 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContextOptions_DEFINED +#define GrContextOptions_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" +#include "include/gpu/GrDriverBugWorkarounds.h" +#include "include/gpu/GrTypes.h" +#include "include/gpu/ShaderErrorHandler.h" +#include "include/private/gpu/ganesh/GrTypesPriv.h" + +#include + +class SkExecutor; + +#if defined(SK_GANESH) +struct SK_API GrContextOptions { + enum class Enable { + /** Forces an option to be disabled. */ + kNo, + /** Forces an option to be enabled. */ + kYes, + /** + * Uses Skia's default behavior, which may use runtime properties (e.g. driver version). + */ + kDefault + }; + + enum class ShaderCacheStrategy { + kSkSL, + kBackendSource, + kBackendBinary, + }; + + /** + * Abstract class which stores Skia data in a cache that persists between sessions. Currently, + * Skia stores compiled shader binaries (only when glProgramBinary / glGetProgramBinary are + * supported) when provided a persistent cache, but this may extend to other data in the future. + */ + class SK_API PersistentCache { + public: + virtual ~PersistentCache() = default; + + /** + * Returns the data for the key if it exists in the cache, otherwise returns null. + */ + virtual sk_sp load(const SkData& key) = 0; + + // Placeholder until all clients override the 3-parameter store(), then remove this, and + // make that version pure virtual. + virtual void store(const SkData& /*key*/, const SkData& /*data*/) { SkASSERT(false); } + + /** + * Stores data in the cache, indexed by key. description provides a human-readable + * version of the key. + */ + virtual void store(const SkData& key, const SkData& data, const SkString& /*description*/) { + this->store(key, data); + } + + protected: + PersistentCache() = default; + PersistentCache(const PersistentCache&) = delete; + PersistentCache& operator=(const PersistentCache&) = delete; + }; + + using ShaderErrorHandler = skgpu::ShaderErrorHandler; + + GrContextOptions() {} + + // Suppress prints for the GrContext. + bool fSuppressPrints = false; + + /** + * Controls whether we check for GL errors after functions that allocate resources (e.g. + * glTexImage2D), at the end of a GPU submission, or checking framebuffer completeness. The + * results of shader compilation and program linking are always checked, regardless of this + * option. Ignored on backends other than GL. + */ + Enable fSkipGLErrorChecks = Enable::kDefault; + + /** Overrides: These options override feature detection using backend API queries. These + overrides can only reduce the feature set or limits, never increase them beyond the + detected values. */ + + int fMaxTextureSizeOverride = SK_MaxS32; + + /** the threshold in bytes above which we will use a buffer mapping API to map vertex and index + buffers to CPU memory in order to update them. A value of -1 means the GrContext should + deduce the optimal value for this platform. */ + int fBufferMapThreshold = -1; + + /** + * Executor to handle threaded work within Ganesh. If this is nullptr, then all work will be + * done serially on the main thread. To have worker threads assist with various tasks, set this + * to a valid SkExecutor instance. Currently, used for software path rendering, but may be used + * for other tasks. + */ + SkExecutor* fExecutor = nullptr; + + /** Construct mipmaps manually, via repeated downsampling draw-calls. This is used when + the driver's implementation (glGenerateMipmap) contains bugs. This requires mipmap + level control (ie desktop or ES3). */ + bool fDoManualMipmapping = false; + + /** + * Disables the use of coverage counting shortcuts to render paths. Coverage counting can cause + * artifacts along shared edges if care isn't taken to ensure both contours wind in the same + * direction. + */ + // FIXME: Once this is removed from Chrome and Android, rename to fEnable"". + bool fDisableCoverageCountingPaths = true; + + /** + * Disables distance field rendering for paths. Distance field computation can be expensive, + * and yields no benefit if a path is not rendered multiple times with different transforms. + */ + bool fDisableDistanceFieldPaths = false; + + /** + * If true this allows path mask textures to be cached. This is only really useful if paths + * are commonly rendered at the same scale and fractional translation. + */ + bool fAllowPathMaskCaching = true; + + /** + * If true, the GPU will not be used to perform YUV -> RGB conversion when generating + * textures from codec-backed images. + */ + bool fDisableGpuYUVConversion = false; + + /** + * The maximum size of cache textures used for Skia's Glyph cache. + */ + size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4; + + /** + * Below this threshold size in device space distance field fonts won't be used. Distance field + * fonts don't support hinting which is more important at smaller sizes. + */ + float fMinDistanceFieldFontSize = 18; + + /** + * Above this threshold size in device space glyphs are drawn as individual paths. + */ +#if defined(SK_BUILD_FOR_ANDROID) + float fGlyphsAsPathsFontSize = 384; +#elif defined(SK_BUILD_FOR_MAC) + float fGlyphsAsPathsFontSize = 256; +#else + float fGlyphsAsPathsFontSize = 324; +#endif + + /** + * Can the glyph atlas use multiple textures. If allowed, the each texture's size is bound by + * fGlypheCacheTextureMaximumBytes. + */ + Enable fAllowMultipleGlyphCacheTextures = Enable::kDefault; + + /** + * Bugs on certain drivers cause stencil buffers to leak. This flag causes Skia to avoid + * allocating stencil buffers and use alternate rasterization paths, avoiding the leak. + */ + bool fAvoidStencilBuffers = false; + + /** + * Enables driver workaround to use draws instead of HW clears, e.g. glClear on the GL backend. + */ + Enable fUseDrawInsteadOfClear = Enable::kDefault; + + /** + * Allow Ganesh to more aggressively reorder operations to reduce the number of render passes. + * Offscreen draws will be done upfront instead of interrupting the main render pass when + * possible. May increase VRAM usage, but still observes the resource cache limit. + * Enabled by default. + */ + Enable fReduceOpsTaskSplitting = Enable::kDefault; + + /** + * Some ES3 contexts report the ES2 external image extension, but not the ES3 version. + * If support for external images is critical, enabling this option will cause Ganesh to limit + * shaders to the ES2 shading language in that situation. + */ + bool fPreferExternalImagesOverES3 = false; + + /** + * Disables correctness workarounds that are enabled for particular GPUs, OSes, or drivers. + * This does not affect code path choices that are made for perfomance reasons nor does it + * override other GrContextOption settings. + */ + bool fDisableDriverCorrectnessWorkarounds = false; + + /** + * Maximum number of GPU programs or pipelines to keep active in the runtime cache. + */ + int fRuntimeProgramCacheSize = 256; + + /** + * Cache in which to store compiled shader binaries between runs. + */ + PersistentCache* fPersistentCache = nullptr; + + /** + * This affects the usage of the PersistentCache. We can cache SkSL, backend source (GLSL), or + * backend binaries (GL program binaries). By default we cache binaries, but if the driver's + * binary loading/storing is believed to have bugs, this can be limited to caching GLSL. + * Caching GLSL strings still saves CPU work when a GL program is created. + */ + ShaderCacheStrategy fShaderCacheStrategy = ShaderCacheStrategy::kBackendBinary; + + /** + * If present, use this object to report shader compilation failures. If not, report failures + * via SkDebugf and assert. + */ + ShaderErrorHandler* fShaderErrorHandler = nullptr; + + /** + * Specifies the number of samples Ganesh should use when performing internal draws with MSAA + * (hardware capabilities permitting). + * + * If 0, Ganesh will disable internal code paths that use multisampling. + */ + int fInternalMultisampleCount = 4; + + /** + * In Skia's vulkan backend a single GrContext submit equates to the submission of a single + * primary command buffer to the VkQueue. This value specifies how many vulkan secondary command + * buffers we will cache for reuse on a given primary command buffer. A single submit may use + * more than this many secondary command buffers, but after the primary command buffer is + * finished on the GPU it will only hold on to this many secondary command buffers for reuse. + * + * A value of -1 means we will pick a limit value internally. + */ + int fMaxCachedVulkanSecondaryCommandBuffers = -1; + + /** + * If true, the caps will never support mipmaps. + */ + bool fSuppressMipmapSupport = false; + + /** + * If true, the TessellationPathRenderer will not be used for path rendering. + * If false, will fallback to any driver workarounds, if set. + */ + bool fDisableTessellationPathRenderer = false; + + /** + * If true, and if supported, enables hardware tessellation in the caps. + * DEPRECATED: This value is ignored; experimental hardware tessellation is always disabled. + */ + bool fEnableExperimentalHardwareTessellation = false; + + /** + * If true, then add 1 pixel padding to all glyph masks in the atlas to support bi-lerp + * rendering of all glyphs. This must be set to true to use Slugs. + */ + bool fSupportBilerpFromGlyphAtlas = false; + + /** + * Uses a reduced variety of shaders. May perform less optimally in steady state but can reduce + * jank due to shader compilations. + */ + bool fReducedShaderVariations = false; + + /** + * If true, then allow to enable MSAA on new Intel GPUs. + */ + bool fAllowMSAAOnNewIntel = false; + + /** + * Currently on ARM Android we disable the use of GL TexStorage because of memory regressions. + * However, some clients may still want to use TexStorage. For example, TexStorage support is + * required for creating protected textures. + * + * This flag has no impact on non GL backends. + */ + bool fAlwaysUseTexStorageWhenAvailable = false; + + /** + * Optional callback that can be passed into the GrDirectContext which will be called when the + * GrDirectContext is about to be destroyed. When this call is made, it will be safe for the + * client to delete the GPU backend context that is backing the GrDirectContext. The + * GrDirectContextDestroyedContext will be passed back to the client in the callback. + */ + GrDirectContextDestroyedContext fContextDeleteContext = nullptr; + GrDirectContextDestroyedProc fContextDeleteProc = nullptr; + +#if GR_TEST_UTILS + /** + * Private options that are only meant for testing within Skia's tools. + */ + + /** + * Testing-only mode to exercise allocation failures in the flush-time callback objects. + * For now it only simulates allocation failure during the preFlush callback. + */ + bool fFailFlushTimeCallbacks = false; + + /** + * Prevents use of dual source blending, to test that all xfer modes work correctly without it. + */ + bool fSuppressDualSourceBlending = false; + + /** + * Prevents the use of non-coefficient-based blend equations, for testing dst reads, barriers, + * and in-shader blending. + */ + bool fSuppressAdvancedBlendEquations = false; + + /** + * Prevents the use of framebuffer fetches, for testing dst reads and texture barriers. + */ + bool fSuppressFramebufferFetch = false; + + /** + * If true, then all paths are processed as if "setIsVolatile" had been called. + */ + bool fAllPathsVolatile = false; + + /** + * Render everything in wireframe + */ + bool fWireframeMode = false; + + /** + * Enforces clearing of all textures when they're created. + */ + bool fClearAllTextures = false; + + /** + * Randomly generate a (false) GL_OUT_OF_MEMORY error + */ + bool fRandomGLOOM = false; + + /** + * Force off support for write/transfer pixels row bytes in caps. + */ + bool fDisallowWriteAndTransferPixelRowBytes = false; + + /** + * Include or exclude specific GPU path renderers. + */ + GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kDefault; + + /** + * Specify the GPU resource cache limit. Equivalent to calling `setResourceCacheLimit` on the + * context at construction time. + * + * A value of -1 means use the default limit value. + */ + int fResourceCacheLimitOverride = -1; + + /** + * Maximum width and height of internal texture atlases. + */ + int fMaxTextureAtlasSize = 2048; +#endif + + GrDriverBugWorkarounds fDriverBugWorkarounds; +}; +#else +struct GrContextOptions { + struct PersistentCache {}; +}; +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrContextThreadSafeProxy.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrContextThreadSafeProxy.h new file mode 100644 index 00000000000000..eb755553647b99 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrContextThreadSafeProxy.h @@ -0,0 +1,169 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContextThreadSafeProxy_DEFINED +#define GrContextThreadSafeProxy_DEFINED + +#include "include/core/SkRefCnt.h" + +#if defined(SK_GANESH) + +#include "include/core/SkImageInfo.h" +#include "include/gpu/GpuTypes.h" +#include "include/gpu/GrContextOptions.h" +#include "include/gpu/GrTypes.h" + +#include + +class GrBackendFormat; +class GrCaps; +class GrContextThreadSafeProxyPriv; +class GrThreadSafeCache; +class GrThreadSafePipelineBuilder; +class SkSurfaceCharacterization; +class SkSurfaceProps; +enum class SkTextureCompressionType; + +namespace sktext::gpu { class TextBlobRedrawCoordinator; } + +/** + * Can be used to perform actions related to the generating GrContext in a thread safe manner. The + * proxy does not access the 3D API (e.g. OpenGL) that backs the generating GrContext. + */ +class SK_API GrContextThreadSafeProxy final : public SkNVRefCnt { +public: + ~GrContextThreadSafeProxy(); + + /** + * Create a surface characterization for a DDL that will be replayed into the GrContext + * that created this proxy. On failure the resulting characterization will be invalid (i.e., + * "!c.isValid()"). + * + * @param cacheMaxResourceBytes The max resource bytes limit that will be in effect + * when the DDL created with this characterization is + * replayed. + * Note: the contract here is that the DDL will be + * created as if it had a full 'cacheMaxResourceBytes' + * to use. If replayed into a GrContext that already has + * locked GPU memory, the replay can exceed the budget. + * To rephrase, all resource allocation decisions are + * made at record time and at playback time the budget + * limits will be ignored. + * @param ii The image info specifying properties of the SkSurface + * that the DDL created with this characterization will + * be replayed into. + * Note: Ganesh doesn't make use of the SkImageInfo's + * alphaType + * @param backendFormat Information about the format of the GPU surface that + * will back the SkSurface upon replay + * @param sampleCount The sample count of the SkSurface that the DDL + * created with this characterization will be replayed + * into + * @param origin The origin of the SkSurface that the DDL created with + * this characterization will be replayed into + * @param surfaceProps The surface properties of the SkSurface that the DDL + * created with this characterization will be replayed + * into + * @param isMipMapped Will the surface the DDL will be replayed into have + * space allocated for mipmaps? + * @param willUseGLFBO0 Will the surface the DDL will be replayed into be + * backed by GL FBO 0. This flag is only valid if using + * an GL backend. + * @param isTextureable Will the surface be able to act as a texture? + * @param isProtected Will the (Vulkan) surface be DRM protected? + * @param vkRTSupportsInputAttachment Can the vulkan surface be used as in input + attachment? + * @param forVulkanSecondaryCommandBuffer Will the surface be wrapping a vulkan secondary + * command buffer via a GrVkSecondaryCBDrawContext? If + * this is true then the following is required: + * isTexureable = false + * isMipMapped = false + * willUseGLFBO0 = false + * vkRTSupportsInputAttachment = false + */ + SkSurfaceCharacterization createCharacterization( + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + const GrBackendFormat& backendFormat, + int sampleCount, + GrSurfaceOrigin origin, + const SkSurfaceProps& surfaceProps, + bool isMipMapped, + bool willUseGLFBO0 = false, + bool isTextureable = true, + GrProtected isProtected = GrProtected::kNo, + bool vkRTSupportsInputAttachment = false, + bool forVulkanSecondaryCommandBuffer = false); + + /* + * Retrieve the default GrBackendFormat for a given SkColorType and renderability. + * It is guaranteed that this backend format will be the one used by the following + * SkColorType and SkSurfaceCharacterization-based createBackendTexture methods. + * + * The caller should check that the returned format is valid. + */ + GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const; + + /** + * Retrieve the GrBackendFormat for a given SkTextureCompressionType. This is + * guaranteed to match the backend format used by the following + * createCompressedBackendTexture methods that take a CompressionType. + * + * The caller should check that the returned format is valid. + */ + GrBackendFormat compressedBackendFormat(SkTextureCompressionType c) const; + + /** + * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA + * rendering is supported for the color type. 0 is returned if rendering to this color type + * is not supported at all. + */ + int maxSurfaceSampleCountForColorType(SkColorType colorType) const; + + bool isValid() const { return nullptr != fCaps; } + + bool operator==(const GrContextThreadSafeProxy& that) const { + // Each GrContext should only ever have a single thread-safe proxy. + SkASSERT((this == &that) == (this->fContextID == that.fContextID)); + return this == &that; + } + + bool operator!=(const GrContextThreadSafeProxy& that) const { return !(*this == that); } + + // Provides access to functions that aren't part of the public API. + GrContextThreadSafeProxyPriv priv(); + const GrContextThreadSafeProxyPriv priv() const; // NOLINT(readability-const-return-type) + +private: + friend class GrContextThreadSafeProxyPriv; // for ctor and hidden methods + + // DDL TODO: need to add unit tests for backend & maybe options + GrContextThreadSafeProxy(GrBackendApi, const GrContextOptions&); + + void abandonContext(); + bool abandoned() const; + + // TODO: This should be part of the constructor but right now we have a chicken-and-egg problem + // with GrContext where we get the caps by creating a GPU which requires a context (see the + // `init` method on GrContext_Base). + void init(sk_sp, sk_sp); + + const GrBackendApi fBackend; + const GrContextOptions fOptions; + const uint32_t fContextID; + sk_sp fCaps; + std::unique_ptr fTextBlobRedrawCoordinator; + std::unique_ptr fThreadSafeCache; + sk_sp fPipelineBuilder; + std::atomic fAbandoned{false}; +}; + +#else // !defined(SK_GANESH) +class SK_API GrContextThreadSafeProxy final : public SkNVRefCnt {}; +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDirectContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDirectContext.h new file mode 100644 index 00000000000000..a22fc4fe5784cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDirectContext.h @@ -0,0 +1,926 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDirectContext_DEFINED +#define GrDirectContext_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/gpu/GpuTypes.h" +#include "include/gpu/GrContextOptions.h" +#include "include/gpu/GrRecordingContext.h" +#include "include/gpu/GrTypes.h" + +#include +#include +#include +#include +#include + +class GrAtlasManager; +class GrBackendSemaphore; +class GrBackendFormat; +class GrBackendTexture; +class GrBackendRenderTarget; +class GrClientMappedBufferManager; +class GrContextThreadSafeProxy; +class GrDirectContextPriv; +class GrGpu; +class GrResourceCache; +class GrResourceProvider; +class SkData; +class SkImage; +class SkPixmap; +class SkTaskGroup; +class SkTraceMemoryDump; +enum SkColorType : int; +enum class SkTextureCompressionType; +struct GrGLInterface; +struct GrMockOptions; +struct GrVkBackendContext; // IWYU pragma: keep +struct GrD3DBackendContext; // IWYU pragma: keep +struct GrMtlBackendContext; // IWYU pragma: keep + +namespace skgpu { + class MutableTextureState; +#if !defined(SK_ENABLE_OPTIMIZE_SIZE) + namespace ganesh { class SmallPathAtlasMgr; } +#endif +} +namespace sktext { namespace gpu { class StrikeCache; } } +namespace wgpu { class Device; } // IWYU pragma: keep + +class SK_API GrDirectContext : public GrRecordingContext { +public: +#ifdef SK_GL + /** + * Creates a GrDirectContext for a backend context. If no GrGLInterface is provided then the + * result of GrGLMakeNativeInterface() is used if it succeeds. + */ + static sk_sp MakeGL(sk_sp, const GrContextOptions&); + static sk_sp MakeGL(sk_sp); + static sk_sp MakeGL(const GrContextOptions&); + static sk_sp MakeGL(); +#endif + +#ifdef SK_VULKAN + /** + * The Vulkan context (VkQueue, VkDevice, VkInstance) must be kept alive until the returned + * GrDirectContext is destroyed. This also means that any objects created with this + * GrDirectContext (e.g. SkSurfaces, SkImages, etc.) must also be released as they may hold + * refs on the GrDirectContext. Once all these objects and the GrDirectContext are released, + * then it is safe to delete the vulkan objects. + */ + static sk_sp MakeVulkan(const GrVkBackendContext&, const GrContextOptions&); + static sk_sp MakeVulkan(const GrVkBackendContext&); +#endif + +#ifdef SK_METAL + /** + * Makes a GrDirectContext which uses Metal as the backend. The GrMtlBackendContext contains a + * MTLDevice and MTLCommandQueue which should be used by the backend. These objects must + * have their own ref which will be released when the GrMtlBackendContext is destroyed. + * Ganesh will take its own ref on the objects which will be released when the GrDirectContext + * is destroyed. + */ + static sk_sp MakeMetal(const GrMtlBackendContext&, const GrContextOptions&); + static sk_sp MakeMetal(const GrMtlBackendContext&); + /** + * Deprecated. + * + * Makes a GrDirectContext which uses Metal as the backend. The device parameter is an + * MTLDevice and queue is an MTLCommandQueue which should be used by the backend. These objects + * must have a ref on them that can be transferred to Ganesh, which will release the ref + * when the GrDirectContext is destroyed. + */ + static sk_sp MakeMetal(void* device, void* queue, const GrContextOptions&); + static sk_sp MakeMetal(void* device, void* queue); +#endif + +#ifdef SK_DIRECT3D + /** + * Makes a GrDirectContext which uses Direct3D as the backend. The Direct3D context + * must be kept alive until the returned GrDirectContext is first destroyed or abandoned. + */ + static sk_sp MakeDirect3D(const GrD3DBackendContext&, const GrContextOptions&); + static sk_sp MakeDirect3D(const GrD3DBackendContext&); +#endif + +#ifdef SK_DAWN + static sk_sp MakeDawn(const wgpu::Device&, + const GrContextOptions&); + static sk_sp MakeDawn(const wgpu::Device&); +#endif + + static sk_sp MakeMock(const GrMockOptions*, const GrContextOptions&); + static sk_sp MakeMock(const GrMockOptions*); + + ~GrDirectContext() override; + + /** + * The context normally assumes that no outsider is setting state + * within the underlying 3D API's context/device/whatever. This call informs + * the context that the state was modified and it should resend. Shouldn't + * be called frequently for good performance. + * The flag bits, state, is dependent on which backend is used by the + * context, either GL or D3D (possible in future). + */ + void resetContext(uint32_t state = kAll_GrBackendState); + + /** + * If the backend is GrBackendApi::kOpenGL, then all texture unit/target combinations for which + * the context has modified the bound texture will have texture id 0 bound. This does not + * flush the context. Calling resetContext() does not change the set that will be bound + * to texture id 0 on the next call to resetGLTextureBindings(). After this is called + * all unit/target combinations are considered to have unmodified bindings until the context + * subsequently modifies them (meaning if this is called twice in a row with no intervening + * context usage then the second call is a no-op.) + */ + void resetGLTextureBindings(); + + /** + * Abandons all GPU resources and assumes the underlying backend 3D API context is no longer + * usable. Call this if you have lost the associated GPU context, and thus internal texture, + * buffer, etc. references/IDs are now invalid. Calling this ensures that the destructors of the + * context and any of its created resource objects will not make backend 3D API calls. Content + * rendered but not previously flushed may be lost. After this function is called all subsequent + * calls on the context will fail or be no-ops. + * + * The typical use case for this function is that the underlying 3D context was lost and further + * API calls may crash. + * + * This call is not valid to be made inside ReleaseProcs passed into SkSurface or SkImages. The + * call will simply fail (and assert in debug) if it is called while inside a ReleaseProc. + * + * For Vulkan, even if the device becomes lost, the VkQueue, VkDevice, or VkInstance used to + * create the context must be kept alive even after abandoning the context. Those objects must + * live for the lifetime of the context object itself. The reason for this is so that + * we can continue to delete any outstanding GrBackendTextures/RenderTargets which must be + * cleaned up even in a device lost state. + */ + void abandonContext() override; + + /** + * Returns true if the context was abandoned or if the if the backend specific context has + * gotten into an unrecoverarble, lost state (e.g. in Vulkan backend if we've gotten a + * VK_ERROR_DEVICE_LOST). If the backend context is lost, this call will also abandon this + * context. + */ + bool abandoned() override; + + // TODO: Remove this from public after migrating Chrome. + sk_sp threadSafeProxy(); + + /** + * Checks if the underlying 3D API reported an out-of-memory error. If this returns true it is + * reset and will return false until another out-of-memory error is reported by the 3D API. If + * the context is abandoned then this will report false. + * + * Currently this is implemented for: + * + * OpenGL [ES] - Note that client calls to glGetError() may swallow GL_OUT_OF_MEMORY errors and + * therefore hide the error from Skia. Also, it is not advised to use this in combination with + * enabling GrContextOptions::fSkipGLErrorChecks. That option may prevent the context from ever + * checking the GL context for OOM. + * + * Vulkan - Reports true if VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY has + * occurred. + */ + bool oomed(); + + /** + * This is similar to abandonContext() however the underlying 3D context is not yet lost and + * the context will cleanup all allocated resources before returning. After returning it will + * assume that the underlying context may no longer be valid. + * + * The typical use case for this function is that the client is going to destroy the 3D context + * but can't guarantee that context will be destroyed first (perhaps because it may be ref'ed + * elsewhere by either the client or Skia objects). + * + * For Vulkan, even if the device becomes lost, the VkQueue, VkDevice, or VkInstance used to + * create the context must be alive before calling releaseResourcesAndAbandonContext. + */ + void releaseResourcesAndAbandonContext(); + + /////////////////////////////////////////////////////////////////////////// + // Resource Cache + + /** DEPRECATED + * Return the current GPU resource cache limits. + * + * @param maxResources If non-null, will be set to -1. + * @param maxResourceBytes If non-null, returns maximum number of bytes of + * video memory that can be held in the cache. + */ + void getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const; + + /** + * Return the current GPU resource cache limit in bytes. + */ + size_t getResourceCacheLimit() const; + + /** + * Gets the current GPU resource cache usage. + * + * @param resourceCount If non-null, returns the number of resources that are held in the + * cache. + * @param maxResourceBytes If non-null, returns the total number of bytes of video memory held + * in the cache. + */ + void getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const; + + /** + * Gets the number of bytes in the cache consumed by purgeable (e.g. unlocked) resources. + */ + size_t getResourceCachePurgeableBytes() const; + + /** DEPRECATED + * Specify the GPU resource cache limits. If the current cache exceeds the maxResourceBytes + * limit, it will be purged (LRU) to keep the cache within the limit. + * + * @param maxResources Unused. + * @param maxResourceBytes The maximum number of bytes of video memory + * that can be held in the cache. + */ + void setResourceCacheLimits(int maxResources, size_t maxResourceBytes); + + /** + * Specify the GPU resource cache limit. If the cache currently exceeds this limit, + * it will be purged (LRU) to keep the cache within the limit. + * + * @param maxResourceBytes The maximum number of bytes of video memory + * that can be held in the cache. + */ + void setResourceCacheLimit(size_t maxResourceBytes); + + /** + * Frees GPU created by the context. Can be called to reduce GPU memory + * pressure. + */ + void freeGpuResources(); + + /** + * Purge GPU resources that haven't been used in the past 'msNotUsed' milliseconds or are + * otherwise marked for deletion, regardless of whether the context is under budget. + * + * If 'scratchResourcesOnly' is true all unlocked scratch resources older than 'msNotUsed' will + * be purged but the unlocked resources with persistent data will remain. If + * 'scratchResourcesOnly' is false then all unlocked resources older than 'msNotUsed' will be + * purged. + * + * @param msNotUsed Only unlocked resources not used in these last milliseconds + * will be cleaned up. + * @param scratchResourcesOnly If true only unlocked scratch resources will be purged. + */ + void performDeferredCleanup(std::chrono::milliseconds msNotUsed, + bool scratchResourcesOnly=false); + + // Temporary compatibility API for Android. + void purgeResourcesNotUsedInMs(std::chrono::milliseconds msNotUsed) { + this->performDeferredCleanup(msNotUsed); + } + + /** + * Purge unlocked resources from the cache until the the provided byte count has been reached + * or we have purged all unlocked resources. The default policy is to purge in LRU order, but + * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other + * resource types. + * + * @param maxBytesToPurge the desired number of bytes to be purged. + * @param preferScratchResources If true scratch resources will be purged prior to other + * resource types. + */ + void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources); + + /** + * This entry point is intended for instances where an app has been backgrounded or + * suspended. + * If 'scratchResourcesOnly' is true all unlocked scratch resources will be purged but the + * unlocked resources with persistent data will remain. If 'scratchResourcesOnly' is false + * then all unlocked resources will be purged. + * In either case, after the unlocked resources are purged a separate pass will be made to + * ensure that resource usage is under budget (i.e., even if 'scratchResourcesOnly' is true + * some resources with persistent data may be purged to be under budget). + * + * @param scratchResourcesOnly If true only unlocked scratch resources will be purged prior + * enforcing the budget requirements. + */ + void purgeUnlockedResources(bool scratchResourcesOnly); + + /** + * Gets the maximum supported texture size. + */ + using GrRecordingContext::maxTextureSize; + + /** + * Gets the maximum supported render target size. + */ + using GrRecordingContext::maxRenderTargetSize; + + /** + * Can a SkImage be created with the given color type. + */ + using GrRecordingContext::colorTypeSupportedAsImage; + + /** + * Can a SkSurface be created with the given color type. To check whether MSAA is supported + * use maxSurfaceSampleCountForColorType(). + */ + using GrRecordingContext::colorTypeSupportedAsSurface; + + /** + * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA + * rendering is supported for the color type. 0 is returned if rendering to this color type + * is not supported at all. + */ + using GrRecordingContext::maxSurfaceSampleCountForColorType; + + /////////////////////////////////////////////////////////////////////////// + // Misc. + + /** + * Inserts a list of GPU semaphores that the current GPU-backed API must wait on before + * executing any more commands on the GPU. If this call returns false, then the GPU back-end + * will not wait on any passed in semaphores, and the client will still own the semaphores, + * regardless of the value of deleteSemaphoresAfterWait. + * + * If deleteSemaphoresAfterWait is false then Skia will not delete the semaphores. In this case + * it is the client's responsibility to not destroy or attempt to reuse the semaphores until it + * knows that Skia has finished waiting on them. This can be done by using finishedProcs on + * flush calls. + */ + bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores, + bool deleteSemaphoresAfterWait = true); + + /** + * Call to ensure all drawing to the context has been flushed and submitted to the underlying 3D + * API. This is equivalent to calling GrContext::flush with a default GrFlushInfo followed by + * GrContext::submit(syncCpu). + */ + void flushAndSubmit(bool syncCpu = false) { + this->flush(GrFlushInfo()); + this->submit(syncCpu); + } + + /** + * Call to ensure all drawing to the context has been flushed to underlying 3D API specific + * objects. A call to `submit` is always required to ensure work is actually sent to + * the gpu. Some specific API details: + * GL: Commands are actually sent to the driver, but glFlush is never called. Thus some + * sync objects from the flush will not be valid until a submission occurs. + * + * Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command + * buffer or encoder objects. However, these objects are not sent to the gpu until a + * submission occurs. + * + * If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be + * submitted to the gpu during the next submit call (it is possible Skia failed to create a + * subset of the semaphores). The client should not wait on these semaphores until after submit + * has been called, and must keep them alive until then. If this call returns + * GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on + * the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in with + * the GrFlushInfo. Regardless of whether semaphores were submitted to the GPU or not, the + * client is still responsible for deleting any initialized semaphores. + * Regardleess of semaphore submission the context will still be flushed. It should be + * emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not + * happen. It simply means there were no semaphores submitted to the GPU. A caller should only + * take this as a failure if they passed in semaphores to be submitted. + */ + GrSemaphoresSubmitted flush(const GrFlushInfo& info); + + void flush() { this->flush(GrFlushInfo()); } + + /** Flushes any pending uses of texture-backed images in the GPU backend. If the image is not + * texture-backed (including promise texture images) or if the GrDirectContext does not + * have the same context ID as the context backing the image then this is a no-op. + * If the image was not used in any non-culled draws in the current queue of work for the + * passed GrDirectContext then this is a no-op unless the GrFlushInfo contains semaphores or + * a finish proc. Those are respected even when the image has not been used. + * @param image the non-null image to flush. + * @param info flush options + */ + GrSemaphoresSubmitted flush(sk_sp image, const GrFlushInfo& info); + void flush(sk_sp image); + + /** Version of flush() that uses a default GrFlushInfo. Also submits the flushed work to the + GPU. + */ + void flushAndSubmit(sk_sp image); + + /** + * Submit outstanding work to the gpu from all previously un-submitted flushes. The return + * value of the submit will indicate whether or not the submission to the GPU was successful. + * + * If the call returns true, all previously passed in semaphores in flush calls will have been + * submitted to the GPU and they can safely be waited on. The caller should wait on those + * semaphores or perform some other global synchronization before deleting the semaphores. + * + * If it returns false, then those same semaphores will not have been submitted and we will not + * try to submit them again. The caller is free to delete the semaphores at any time. + * + * If the syncCpu flag is true this function will return once the gpu has finished with all + * submitted work. + */ + bool submit(bool syncCpu = false); + + /** + * Checks whether any asynchronous work is complete and if so calls related callbacks. + */ + void checkAsyncWorkCompletion(); + + /** Enumerates all cached GPU resources and dumps their memory to traceMemoryDump. */ + // Chrome is using this! + void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; + + bool supportsDistanceFieldText() const; + + void storeVkPipelineCacheData(); + + /** + * Retrieve the default GrBackendFormat for a given SkColorType and renderability. + * It is guaranteed that this backend format will be the one used by the following + * SkColorType and SkSurfaceCharacterization-based createBackendTexture methods. + * + * The caller should check that the returned format is valid. + */ + using GrRecordingContext::defaultBackendFormat; + + /** + * The explicitly allocated backend texture API allows clients to use Skia to create backend + * objects outside of Skia proper (i.e., Skia's caching system will not know about them.) + * + * It is the client's responsibility to delete all these objects (using deleteBackendTexture) + * before deleting the context used to create them. If the backend is Vulkan, the textures must + * be deleted before abandoning the context as well. Additionally, clients should only delete + * these objects on the thread for which that context is active. + * + * The client is responsible for ensuring synchronization between different uses + * of the backend object (i.e., wrapping it in a surface, rendering to it, deleting the + * surface, rewrapping it in a image and drawing the image will require explicit + * synchronization on the client's part). + */ + + /** + * If possible, create an uninitialized backend texture. The client should ensure that the + * returned backend texture is valid. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_UNDEFINED. + */ + GrBackendTexture createBackendTexture(int width, + int height, + const GrBackendFormat&, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo, + std::string_view label = {}); + + /** + * If possible, create an uninitialized backend texture. The client should ensure that the + * returned backend texture is valid. + * If successful, the created backend texture will be compatible with the provided + * SkColorType. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_UNDEFINED. + */ + GrBackendTexture createBackendTexture(int width, int height, + SkColorType, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo, + std::string_view label = {}); + + /** + * If possible, create a backend texture initialized to a particular color. The client should + * ensure that the returned backend texture is valid. The client can pass in a finishedProc + * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The + * client is required to call `submit` to send the upload work to the gpu. The + * finishedProc will always get called even if we failed to create the GrBackendTexture. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createBackendTexture(int width, int height, + const GrBackendFormat&, + const SkColor4f& color, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr, + std::string_view label = {}); + + /** + * If possible, create a backend texture initialized to a particular color. The client should + * ensure that the returned backend texture is valid. The client can pass in a finishedProc + * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The + * client is required to call `submit` to send the upload work to the gpu. The + * finishedProc will always get called even if we failed to create the GrBackendTexture. + * If successful, the created backend texture will be compatible with the provided + * SkColorType. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createBackendTexture(int width, int height, + SkColorType, + const SkColor4f& color, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr, + std::string_view label = {}); + + /** + * If possible, create a backend texture initialized with the provided pixmap data. The client + * should ensure that the returned backend texture is valid. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture. + * If successful, the created backend texture will be compatible with the provided + * pixmap(s). Compatible, in this case, means that the backend format will be the result + * of calling defaultBackendFormat on the base pixmap's colortype. The src data can be deleted + * when this call returns. + * If numLevels is 1 a non-mipmapped texture will result. If a mipmapped texture is desired + * the data for all the mipmap levels must be provided. In the mipmapped case all the + * colortypes of the provided pixmaps must be the same. Additionally, all the miplevels + * must be sized correctly (please see SkMipmap::ComputeLevelSize and ComputeLevelCount). The + * GrSurfaceOrigin controls whether the pixmap data is vertically flipped in the texture. + * Note: the pixmap's alphatypes and colorspaces are ignored. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createBackendTexture(const SkPixmap srcData[], + int numLevels, + GrSurfaceOrigin, + GrRenderable, + GrProtected, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr, + std::string_view label = {}); + + /** + * Convenience version createBackendTexture() that takes just a base level pixmap. + */ + GrBackendTexture createBackendTexture(const SkPixmap& srcData, + GrSurfaceOrigin textureOrigin, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr, + std::string_view label = {}); + + // Deprecated versions that do not take origin and assume top-left. + GrBackendTexture createBackendTexture(const SkPixmap srcData[], + int numLevels, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr, + std::string_view label = {}); + + GrBackendTexture createBackendTexture(const SkPixmap& srcData, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr, + std::string_view label = {}); + + /** + * If possible, updates a backend texture to be filled to a particular color. The client should + * check the return value to see if the update was successful. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to update the GrBackendTexture. + * For the Vulkan backend after a successful update the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + bool updateBackendTexture(const GrBackendTexture&, + const SkColor4f& color, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext); + + /** + * If possible, updates a backend texture to be filled to a particular color. The data in + * GrBackendTexture and passed in color is interpreted with respect to the passed in + * SkColorType. The client should check the return value to see if the update was successful. + * The client can pass in a finishedProc to be notified when the data has been uploaded by the + * gpu and the texture can be deleted. The client is required to call `submit` to send + * the upload work to the gpu. The finishedProc will always get called even if we failed to + * update the GrBackendTexture. + * For the Vulkan backend after a successful update the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + bool updateBackendTexture(const GrBackendTexture&, + SkColorType skColorType, + const SkColor4f& color, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext); + + /** + * If possible, updates a backend texture filled with the provided pixmap data. The client + * should check the return value to see if the update was successful. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture. + * The backend texture must be compatible with the provided pixmap(s). Compatible, in this case, + * means that the backend format is compatible with the base pixmap's colortype. The src data + * can be deleted when this call returns. + * If the backend texture is mip mapped, the data for all the mipmap levels must be provided. + * In the mipmapped case all the colortypes of the provided pixmaps must be the same. + * Additionally, all the miplevels must be sized correctly (please see + * SkMipmap::ComputeLevelSize and ComputeLevelCount). The GrSurfaceOrigin controls whether the + * pixmap data is vertically flipped in the texture. + * Note: the pixmap's alphatypes and colorspaces are ignored. + * For the Vulkan backend after a successful update the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + bool updateBackendTexture(const GrBackendTexture&, + const SkPixmap srcData[], + int numLevels, + GrSurfaceOrigin = kTopLeft_GrSurfaceOrigin, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + /** + * Convenience version of updateBackendTexture that takes just a base level pixmap. + */ + bool updateBackendTexture(const GrBackendTexture& texture, + const SkPixmap& srcData, + GrSurfaceOrigin textureOrigin = kTopLeft_GrSurfaceOrigin, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr) { + return this->updateBackendTexture(texture, + &srcData, + 1, + textureOrigin, + finishedProc, + finishedContext); + } + + // Deprecated version that does not take origin and assumes top-left. + bool updateBackendTexture(const GrBackendTexture& texture, + const SkPixmap srcData[], + int numLevels, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext); + + /** + * Retrieve the GrBackendFormat for a given SkTextureCompressionType. This is + * guaranteed to match the backend format used by the following + * createCompressedBackendTexture methods that take a CompressionType. + * + * The caller should check that the returned format is valid. + */ + using GrRecordingContext::compressedBackendFormat; + + /** + *If possible, create a compressed backend texture initialized to a particular color. The + * client should ensure that the returned backend texture is valid. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createCompressedBackendTexture(int width, int height, + const GrBackendFormat&, + const SkColor4f& color, + GrMipmapped, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + GrBackendTexture createCompressedBackendTexture(int width, int height, + SkTextureCompressionType, + const SkColor4f& color, + GrMipmapped, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + /** + * If possible, create a backend texture initialized with the provided raw data. The client + * should ensure that the returned backend texture is valid. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture + * If numLevels is 1 a non-mipmapped texture will result. If a mipmapped texture is desired + * the data for all the mipmap levels must be provided. Additionally, all the miplevels + * must be sized correctly (please see SkMipmap::ComputeLevelSize and ComputeLevelCount). + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createCompressedBackendTexture(int width, int height, + const GrBackendFormat&, + const void* data, size_t dataSize, + GrMipmapped, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + GrBackendTexture createCompressedBackendTexture(int width, int height, + SkTextureCompressionType, + const void* data, size_t dataSize, + GrMipmapped, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + /** + * If possible, updates a backend texture filled with the provided color. If the texture is + * mipmapped, all levels of the mip chain will be updated to have the supplied color. The client + * should check the return value to see if the update was successful. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture. + * For the Vulkan backend after a successful update the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + bool updateCompressedBackendTexture(const GrBackendTexture&, + const SkColor4f& color, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext); + + /** + * If possible, updates a backend texture filled with the provided raw data. The client + * should check the return value to see if the update was successful. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture. + * If a mipmapped texture is passed in, the data for all the mipmap levels must be provided. + * Additionally, all the miplevels must be sized correctly (please see + * SkMipMap::ComputeLevelSize and ComputeLevelCount). + * For the Vulkan backend after a successful update the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + bool updateCompressedBackendTexture(const GrBackendTexture&, + const void* data, + size_t dataSize, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext); + + /** + * Updates the state of the GrBackendTexture/RenderTarget to have the passed in + * skgpu::MutableTextureState. All objects that wrap the backend surface (i.e. SkSurfaces and + * SkImages) will also be aware of this state change. This call does not submit the state change + * to the gpu, but requires the client to call `submit` to send it to the GPU. The work + * for this call is ordered linearly with all other calls that require GrContext::submit to be + * called (e.g updateBackendTexture and flush). If finishedProc is not null then it will be + * called with finishedContext after the state transition is known to have occurred on the GPU. + * + * See skgpu::MutableTextureState to see what state can be set via this call. + * + * If the backend API is Vulkan, the caller can set the skgpu::MutableTextureState's + * VkImageLayout to VK_IMAGE_LAYOUT_UNDEFINED or queueFamilyIndex to VK_QUEUE_FAMILY_IGNORED to + * tell Skia to not change those respective states. + * + * If previousState is not null and this returns true, then Skia will have filled in + * previousState to have the values of the state before this call. + */ + bool setBackendTextureState(const GrBackendTexture&, + const skgpu::MutableTextureState&, + skgpu::MutableTextureState* previousState = nullptr, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + bool setBackendRenderTargetState(const GrBackendRenderTarget&, + const skgpu::MutableTextureState&, + skgpu::MutableTextureState* previousState = nullptr, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + void deleteBackendTexture(GrBackendTexture); + + // This interface allows clients to pre-compile shaders and populate the runtime program cache. + // The key and data blobs should be the ones passed to the PersistentCache, in SkSL format. + // + // Steps to use this API: + // + // 1) Create a GrDirectContext as normal, but set fPersistentCache on GrContextOptions to + // something that will save the cached shader blobs. Set fShaderCacheStrategy to kSkSL. This + // will ensure that the blobs are SkSL, and are suitable for pre-compilation. + // 2) Run your application, and save all of the key/data pairs that are fed to the cache. + // + // 3) Switch over to shipping your application. Include the key/data pairs from above. + // 4) At startup (or any convenient time), call precompileShader for each key/data pair. + // This will compile the SkSL to create a GL program, and populate the runtime cache. + // + // This is only guaranteed to work if the context/device used in step #2 are created in the + // same way as the one used in step #4, and the same GrContextOptions are specified. + // Using cached shader blobs on a different device or driver are undefined. + bool precompileShader(const SkData& key, const SkData& data); + +#ifdef SK_ENABLE_DUMP_GPU + /** Returns a string with detailed information about the context & GPU, in JSON format. */ + SkString dump() const; +#endif + + class DirectContextID { + public: + static GrDirectContext::DirectContextID Next(); + + DirectContextID() : fID(SK_InvalidUniqueID) {} + + bool operator==(const DirectContextID& that) const { return fID == that.fID; } + bool operator!=(const DirectContextID& that) const { return !(*this == that); } + + void makeInvalid() { fID = SK_InvalidUniqueID; } + bool isValid() const { return fID != SK_InvalidUniqueID; } + + private: + constexpr DirectContextID(uint32_t id) : fID(id) {} + uint32_t fID; + }; + + DirectContextID directContextID() const { return fDirectContextID; } + + // Provides access to functions that aren't part of the public API. + GrDirectContextPriv priv(); + const GrDirectContextPriv priv() const; // NOLINT(readability-const-return-type) + +protected: + GrDirectContext(GrBackendApi backend, const GrContextOptions& options); + + bool init() override; + + GrAtlasManager* onGetAtlasManager() { return fAtlasManager.get(); } +#if !defined(SK_ENABLE_OPTIMIZE_SIZE) + skgpu::ganesh::SmallPathAtlasMgr* onGetSmallPathAtlasMgr(); +#endif + + GrDirectContext* asDirectContext() override { return this; } + +private: + // This call will make sure out work on the GPU is finished and will execute any outstanding + // asynchronous work (e.g. calling finished procs, freeing resources, etc.) related to the + // outstanding work on the gpu. The main use currently for this function is when tearing down or + // abandoning the context. + // + // When we finish up work on the GPU it could trigger callbacks to the client. In the case we + // are abandoning the context we don't want the client to be able to use the GrDirectContext to + // issue more commands during the callback. Thus before calling this function we set the + // GrDirectContext's state to be abandoned. However, we need to be able to get by the abaonded + // check in the call to know that it is safe to execute this. The shouldExecuteWhileAbandoned + // bool is used for this signal. + void syncAllOutstandingGpuWork(bool shouldExecuteWhileAbandoned); + + // This delete callback needs to be the first thing on the GrDirectContext so that it is the + // last thing destroyed. The callback may signal the client to clean up things that may need + // to survive the lifetime of some of the other objects on the GrDirectCotnext. So make sure + // we don't call it until all else has been destroyed. + class DeleteCallbackHelper { + public: + DeleteCallbackHelper(GrDirectContextDestroyedContext context, + GrDirectContextDestroyedProc proc) + : fContext(context), fProc(proc) {} + + ~DeleteCallbackHelper() { + if (fProc) { + fProc(fContext); + } + } + + private: + GrDirectContextDestroyedContext fContext; + GrDirectContextDestroyedProc fProc; + }; + std::unique_ptr fDeleteCallbackHelper; + + const DirectContextID fDirectContextID; + // fTaskGroup must appear before anything that uses it (e.g. fGpu), so that it is destroyed + // after all of its users. Clients of fTaskGroup will generally want to ensure that they call + // wait() on it as they are being destroyed, to avoid the possibility of pending tasks being + // invoked after objects they depend upon have already been destroyed. + std::unique_ptr fTaskGroup; + std::unique_ptr fStrikeCache; + sk_sp fGpu; + std::unique_ptr fResourceCache; + std::unique_ptr fResourceProvider; + + // This is incremented before we start calling ReleaseProcs from GrSurfaces and decremented + // after. A ReleaseProc may trigger code causing another resource to get freed so we to track + // the count to know if we in a ReleaseProc at any level. When this is set to a value greated + // than zero we will not allow abandonContext calls to be made on the context. + int fInsideReleaseProcCnt = 0; + + bool fDidTestPMConversions; + // true if the PM/UPM conversion succeeded; false otherwise + bool fPMUPMConversionsRoundTrip; + + GrContextOptions::PersistentCache* fPersistentCache; + + std::unique_ptr fMappedBufferManager; + std::unique_ptr fAtlasManager; + +#if !defined(SK_ENABLE_OPTIMIZE_SIZE) + std::unique_ptr fSmallPathAtlasMgr; +#endif + + friend class GrDirectContextPriv; +}; + + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDriverBugWorkarounds.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDriverBugWorkarounds.h new file mode 100644 index 00000000000000..1aa995c79177a0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDriverBugWorkarounds.h @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDriverBugWorkarounds_DEFINED +#define GrDriverBugWorkarounds_DEFINED + +// External embedders of Skia can override this to use their own list +// of workaround names. +#ifdef SK_GPU_WORKAROUNDS_HEADER +#include SK_GPU_WORKAROUNDS_HEADER +#else +// To regenerate this file, set gn arg "skia_generate_workarounds = true" +// or invoke `bazel run //tools:generate_workarounds` +// This is not rebuilt by default to avoid embedders having to have extra +// build steps. +#include "include/gpu/GrDriverBugWorkaroundsAutogen.h" +#endif + +#include "include/core/SkTypes.h" + +#include +#include + +enum GrDriverBugWorkaroundType { +#define GPU_OP(type, name) type, + GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) +#undef GPU_OP + NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES +}; + +class SK_API GrDriverBugWorkarounds { + public: + GrDriverBugWorkarounds(); + GrDriverBugWorkarounds(const GrDriverBugWorkarounds&) = default; + explicit GrDriverBugWorkarounds(const std::vector& workarounds); + + GrDriverBugWorkarounds& operator=(const GrDriverBugWorkarounds&) = default; + + // Turn on any workarounds listed in |workarounds| (but don't turn any off). + void applyOverrides(const GrDriverBugWorkarounds& workarounds); + + ~GrDriverBugWorkarounds(); + +#define GPU_OP(type, name) bool name = false; + GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) +#undef GPU_OP +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDriverBugWorkaroundsAutogen.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDriverBugWorkaroundsAutogen.h new file mode 100644 index 00000000000000..d0b96ca80a428e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrDriverBugWorkaroundsAutogen.h @@ -0,0 +1,43 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is auto-generated from build_workaround_header.py +// DO NOT EDIT! + +#define GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) \ + GPU_OP(ADD_AND_TRUE_TO_LOOP_CONDITION, \ + add_and_true_to_loop_condition) \ + GPU_OP(DISABLE_BLEND_EQUATION_ADVANCED, \ + disable_blend_equation_advanced) \ + GPU_OP(DISABLE_DISCARD_FRAMEBUFFER, \ + disable_discard_framebuffer) \ + GPU_OP(DISABLE_DUAL_SOURCE_BLENDING_SUPPORT, \ + disable_dual_source_blending_support) \ + GPU_OP(DISABLE_TEXTURE_STORAGE, \ + disable_texture_storage) \ + GPU_OP(DISALLOW_LARGE_INSTANCED_DRAW, \ + disallow_large_instanced_draw) \ + GPU_OP(EMULATE_ABS_INT_FUNCTION, \ + emulate_abs_int_function) \ + GPU_OP(FLUSH_ON_FRAMEBUFFER_CHANGE, \ + flush_on_framebuffer_change) \ + GPU_OP(FORCE_UPDATE_SCISSOR_STATE_WHEN_BINDING_FBO0, \ + force_update_scissor_state_when_binding_fbo0) \ + GPU_OP(GL_CLEAR_BROKEN, \ + gl_clear_broken) \ + GPU_OP(MAX_FRAGMENT_UNIFORM_VECTORS_32, \ + max_fragment_uniform_vectors_32) \ + GPU_OP(MAX_MSAA_SAMPLE_COUNT_4, \ + max_msaa_sample_count_4) \ + GPU_OP(PACK_PARAMETERS_WORKAROUND_WITH_PACK_BUFFER, \ + pack_parameters_workaround_with_pack_buffer) \ + GPU_OP(REMOVE_POW_WITH_CONSTANT_EXPONENT, \ + remove_pow_with_constant_exponent) \ + GPU_OP(REWRITE_DO_WHILE_LOOPS, \ + rewrite_do_while_loops) \ + GPU_OP(UNBIND_ATTACHMENTS_ON_BOUND_RENDER_FBO_DELETE, \ + unbind_attachments_on_bound_render_fbo_delete) \ + GPU_OP(UNFOLD_SHORT_CIRCUIT_AS_TERNARY_OPERATION, \ + unfold_short_circuit_as_ternary_operation) \ +// The End diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrRecordingContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrRecordingContext.h new file mode 100644 index 00000000000000..85cc77c051c8f8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrRecordingContext.h @@ -0,0 +1,289 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRecordingContext_DEFINED +#define GrRecordingContext_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTArray.h" +#include "include/private/gpu/ganesh/GrImageContext.h" + +#if GR_GPU_STATS && GR_TEST_UTILS +#include +#include +#endif + +class GrAuditTrail; +class GrBackendFormat; +class GrDrawingManager; +class GrOnFlushCallbackObject; +class GrMemoryPool; +class GrProgramDesc; +class GrProgramInfo; +class GrProxyProvider; +class GrRecordingContextPriv; +class GrSurfaceProxy; +class GrThreadSafeCache; +class SkArenaAlloc; +class SkCapabilities; +class SkJSONWriter; + +namespace sktext::gpu { +class SubRunAllocator; +class TextBlobRedrawCoordinator; +} + +#if GR_TEST_UTILS +class SkString; +#endif + +class GrRecordingContext : public GrImageContext { +public: + ~GrRecordingContext() override; + + SK_API GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const { + return INHERITED::defaultBackendFormat(ct, renderable); + } + + /** + * Reports whether the GrDirectContext associated with this GrRecordingContext is abandoned. + * When called on a GrDirectContext it may actively check whether the underlying 3D API + * device/context has been disconnected before reporting the status. If so, calling this + * method will transition the GrDirectContext to the abandoned state. + */ + bool abandoned() override { return INHERITED::abandoned(); } + + /* + * Can a SkSurface be created with the given color type. To check whether MSAA is supported + * use maxSurfaceSampleCountForColorType(). + */ + SK_API bool colorTypeSupportedAsSurface(SkColorType colorType) const { + if (kR16G16_unorm_SkColorType == colorType || + kA16_unorm_SkColorType == colorType || + kA16_float_SkColorType == colorType || + kR16G16_float_SkColorType == colorType || + kR16G16B16A16_unorm_SkColorType == colorType || + kGray_8_SkColorType == colorType) { + return false; + } + + return this->maxSurfaceSampleCountForColorType(colorType) > 0; + } + + /** + * Gets the maximum supported texture size. + */ + SK_API int maxTextureSize() const; + + /** + * Gets the maximum supported render target size. + */ + SK_API int maxRenderTargetSize() const; + + /** + * Can a SkImage be created with the given color type. + */ + SK_API bool colorTypeSupportedAsImage(SkColorType) const; + + /** + * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA + * rendering is supported for the color type. 0 is returned if rendering to this color type + * is not supported at all. + */ + SK_API int maxSurfaceSampleCountForColorType(SkColorType colorType) const { + return INHERITED::maxSurfaceSampleCountForColorType(colorType); + } + + SK_API sk_sp skCapabilities() const; + + // Provides access to functions that aren't part of the public API. + GrRecordingContextPriv priv(); + const GrRecordingContextPriv priv() const; // NOLINT(readability-const-return-type) + + // The collection of specialized memory arenas for different types of data recorded by a + // GrRecordingContext. Arenas does not maintain ownership of the pools it groups together. + class Arenas { + public: + Arenas(SkArenaAlloc*, sktext::gpu::SubRunAllocator*); + + // For storing pipelines and other complex data as-needed by ops + SkArenaAlloc* recordTimeAllocator() { return fRecordTimeAllocator; } + + // For storing GrTextBlob SubRuns + sktext::gpu::SubRunAllocator* recordTimeSubRunAllocator() { + return fRecordTimeSubRunAllocator; + } + + private: + SkArenaAlloc* fRecordTimeAllocator; + sktext::gpu::SubRunAllocator* fRecordTimeSubRunAllocator; + }; + +protected: + friend class GrRecordingContextPriv; // for hidden functions + friend class SkDeferredDisplayList; // for OwnedArenas + friend class SkDeferredDisplayListPriv; // for ProgramData + + // Like Arenas, but preserves ownership of the underlying pools. + class OwnedArenas { + public: + OwnedArenas(bool ddlRecording); + ~OwnedArenas(); + + Arenas get(); + + OwnedArenas& operator=(OwnedArenas&&); + + private: + bool fDDLRecording; + std::unique_ptr fRecordTimeAllocator; + std::unique_ptr fRecordTimeSubRunAllocator; + }; + + GrRecordingContext(sk_sp, bool ddlRecording); + + bool init() override; + + void abandonContext() override; + + GrDrawingManager* drawingManager(); + + // There is no going back from this method. It should only be called to control the timing + // during abandon or destruction of the context. + void destroyDrawingManager(); + + Arenas arenas() { return fArenas.get(); } + // This entry point should only be used for DDL creation where we want the ops' lifetime to + // match that of the DDL. + OwnedArenas&& detachArenas(); + + GrProxyProvider* proxyProvider() { return fProxyProvider.get(); } + const GrProxyProvider* proxyProvider() const { return fProxyProvider.get(); } + + struct ProgramData { + ProgramData(std::unique_ptr, const GrProgramInfo*); + ProgramData(ProgramData&&); // for SkTArray + ProgramData(const ProgramData&) = delete; + ~ProgramData(); + + const GrProgramDesc& desc() const { return *fDesc; } + const GrProgramInfo& info() const { return *fInfo; } + + private: + // TODO: store the GrProgramDescs in the 'fRecordTimeData' arena + std::unique_ptr fDesc; + // The program infos should be stored in 'fRecordTimeData' so do not need to be ref + // counted or deleted in the destructor. + const GrProgramInfo* fInfo = nullptr; + }; + + // This entry point gives the recording context a chance to cache the provided + // programInfo. The DDL context takes this opportunity to store programInfos as a sidecar + // to the DDL. + virtual void recordProgramInfo(const GrProgramInfo*) {} + // This asks the recording context to return any programInfos it may have collected + // via the 'recordProgramInfo' call. It is up to the caller to ensure that the lifetime + // of the programInfos matches the intended use. For example, in DDL-record mode it + // is known that all the programInfos will have been allocated in an arena with the + // same lifetime at the DDL itself. + virtual void detachProgramData(skia_private::TArray*) {} + + sktext::gpu::TextBlobRedrawCoordinator* getTextBlobRedrawCoordinator(); + const sktext::gpu::TextBlobRedrawCoordinator* getTextBlobRedrawCoordinator() const; + + GrThreadSafeCache* threadSafeCache(); + const GrThreadSafeCache* threadSafeCache() const; + + /** + * Registers an object for flush-related callbacks. (See GrOnFlushCallbackObject.) + * + * NOTE: the drawing manager tracks this object as a raw pointer; it is up to the caller to + * ensure its lifetime is tied to that of the context. + */ + void addOnFlushCallbackObject(GrOnFlushCallbackObject*); + + GrRecordingContext* asRecordingContext() override { return this; } + + class Stats { + public: + Stats() = default; + +#if GR_GPU_STATS + void reset() { *this = {}; } + + int numPathMasksGenerated() const { return fNumPathMasksGenerated; } + void incNumPathMasksGenerated() { fNumPathMasksGenerated++; } + + int numPathMaskCacheHits() const { return fNumPathMaskCacheHits; } + void incNumPathMasksCacheHits() { fNumPathMaskCacheHits++; } + +#if GR_TEST_UTILS + void dump(SkString* out) const; + void dumpKeyValuePairs(skia_private::TArray* keys, + skia_private::TArray* values) const; +#endif + + private: + int fNumPathMasksGenerated{0}; + int fNumPathMaskCacheHits{0}; + +#else // GR_GPU_STATS + void incNumPathMasksGenerated() {} + void incNumPathMasksCacheHits() {} + +#if GR_TEST_UTILS + void dump(SkString*) const {} + void dumpKeyValuePairs(skia_private::TArray* keys, + skia_private::TArray* values) const {} +#endif +#endif // GR_GPU_STATS + } fStats; + +#if GR_GPU_STATS && GR_TEST_UTILS + struct DMSAAStats { + void dumpKeyValuePairs(skia_private::TArray* keys, + skia_private::TArray* values) const; + void dump() const; + void merge(const DMSAAStats&); + int fNumRenderPasses = 0; + int fNumMultisampleRenderPasses = 0; + std::map fTriggerCounts; + }; + + DMSAAStats fDMSAAStats; +#endif + + Stats* stats() { return &fStats; } + const Stats* stats() const { return &fStats; } + void dumpJSON(SkJSONWriter*) const; + +protected: + // Delete last in case other objects call it during destruction. + std::unique_ptr fAuditTrail; + +private: + OwnedArenas fArenas; + + std::unique_ptr fDrawingManager; + std::unique_ptr fProxyProvider; + +#if GR_TEST_UTILS + int fSuppressWarningMessages = 0; +#endif + + using INHERITED = GrImageContext; +}; + +/** + * Safely cast a possibly-null base context to direct context. + */ +static inline GrDirectContext* GrAsDirectContext(GrContext_Base* base) { + return base ? base->asDirectContext() : nullptr; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrSurfaceInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrSurfaceInfo.h new file mode 100644 index 00000000000000..e037fb495781ae --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrSurfaceInfo.h @@ -0,0 +1,166 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSurfaceInfo_DEFINED +#define GrSurfaceInfo_DEFINED + +#include "include/gpu/GrTypes.h" + +#ifdef SK_GL +#include "include/private/gpu/ganesh/GrGLTypesPriv.h" +#endif +#ifdef SK_VULKAN +#include "include/private/gpu/ganesh/GrVkTypesPriv.h" +#endif +#ifdef SK_DIRECT3D +#include "include/private/gpu/ganesh/GrD3DTypesMinimal.h" +struct GrD3DSurfaceInfo; +#endif +#ifdef SK_METAL +#include "include/private/gpu/ganesh/GrMtlTypesPriv.h" +#endif +#ifdef SK_DAWN +#include "include/private/gpu/ganesh/GrDawnTypesPriv.h" +#endif +#include "include/private/gpu/ganesh/GrMockTypesPriv.h" + +class GrSurfaceInfo { +public: + GrSurfaceInfo() {} +#ifdef SK_GL + GrSurfaceInfo(const GrGLSurfaceInfo& glInfo) + : fBackend(GrBackendApi::kOpenGL) + , fValid(true) + , fSampleCount(glInfo.fSampleCount) + , fLevelCount(glInfo.fLevelCount) + , fProtected(glInfo.fProtected) + , fGLSpec(glInfo) {} +#endif +#ifdef SK_VULKAN + GrSurfaceInfo(const GrVkSurfaceInfo& vkInfo) + : fBackend(GrBackendApi::kVulkan) + , fValid(true) + , fSampleCount(vkInfo.fSampleCount) + , fLevelCount(vkInfo.fLevelCount) + , fProtected(vkInfo.fProtected) + , fVkSpec(vkInfo) {} +#endif +#ifdef SK_DIRECT3D + GrSurfaceInfo(const GrD3DSurfaceInfo& d3dInfo); +#endif +#ifdef SK_METAL + GrSurfaceInfo(const GrMtlSurfaceInfo& mtlInfo) + : fBackend(GrBackendApi::kMetal) + , fValid(true) + , fSampleCount(mtlInfo.fSampleCount) + , fLevelCount(mtlInfo.fLevelCount) + , fProtected(mtlInfo.fProtected) + , fMtlSpec(mtlInfo) {} +#endif +#ifdef SK_DAWN + GrSurfaceInfo(const GrDawnSurfaceInfo& dawnInfo) + : fBackend(GrBackendApi::kDawn) + , fValid(true) + , fSampleCount(dawnInfo.fSampleCount) + , fLevelCount(dawnInfo.fLevelCount) + , fProtected(dawnInfo.fProtected) + , fDawnSpec(dawnInfo) {} +#endif + GrSurfaceInfo(const GrMockSurfaceInfo& mockInfo) + : fBackend(GrBackendApi::kMock) + , fValid(true) + , fSampleCount(mockInfo.fSampleCount) + , fLevelCount(mockInfo.fLevelCount) + , fProtected(mockInfo.fProtected) + , fMockSpec(mockInfo) {} + + ~GrSurfaceInfo(); + GrSurfaceInfo(const GrSurfaceInfo&) = default; + + bool isValid() const { return fValid; } + GrBackendApi backend() const { return fBackend; } + + uint32_t numSamples() const { return fSampleCount; } + uint32_t numMipLevels() const { return fLevelCount; } + GrProtected isProtected() const { return fProtected; } + +#ifdef SK_GL + bool getGLSurfaceInfo(GrGLSurfaceInfo* info) const { + if (!this->isValid() || fBackend != GrBackendApi::kOpenGL) { + return false; + } + *info = GrGLTextureSpecToSurfaceInfo(fGLSpec, fSampleCount, fLevelCount, fProtected); + return true; + } +#endif +#ifdef SK_VULKAN + bool getVkSurfaceInfo(GrVkSurfaceInfo* info) const { + if (!this->isValid() || fBackend != GrBackendApi::kVulkan) { + return false; + } + *info = GrVkImageSpecToSurfaceInfo(fVkSpec, fSampleCount, fLevelCount, fProtected); + return true; + } +#endif +#ifdef SK_DIRECT3D + bool getD3DSurfaceInfo(GrD3DSurfaceInfo*) const; +#endif +#ifdef SK_METAL + bool getMtlSurfaceInfo(GrMtlSurfaceInfo* info) const { + if (!this->isValid() || fBackend != GrBackendApi::kMetal) { + return false; + } + *info = GrMtlTextureSpecToSurfaceInfo(fMtlSpec, fSampleCount, fLevelCount, fProtected); + return true; + } +#endif +#ifdef SK_DAWN + bool getDawnSurfaceInfo(GrDawnSurfaceInfo* info) const { + if (!this->isValid() || fBackend != GrBackendApi::kDawn) { + return false; + } + *info = GrDawnTextureSpecToSurfaceInfo(fDawnSpec, fSampleCount, fLevelCount, fProtected); + return true; + } +#endif + bool getMockSurfaceInfo(GrMockSurfaceInfo* info) const { + if (!this->isValid() || fBackend != GrBackendApi::kMock) { + return false; + } + *info = GrMockTextureSpecToSurfaceInfo(fMockSpec, fSampleCount, fLevelCount, fProtected); + return true; + } + +private: + GrBackendApi fBackend = GrBackendApi::kMock; + bool fValid = false; + + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + GrProtected fProtected = GrProtected::kNo; + + union { +#ifdef SK_GL + GrGLTextureSpec fGLSpec; +#endif +#ifdef SK_VULKAN + GrVkImageSpec fVkSpec; +#endif +#ifdef SK_DIRECT3D + GrD3DTextureResourceSpecHolder fD3DSpec; +#endif +#ifdef SK_METAL + GrMtlTextureSpec fMtlSpec; +#endif +#ifdef SK_DAWN + GrDawnTextureSpec fDawnSpec; +#endif + GrMockTextureSpec fMockSpec; + }; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrTypes.h new file mode 100644 index 00000000000000..177a35a9437f93 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrTypes.h @@ -0,0 +1,244 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTypes_DEFINED +#define GrTypes_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/base/SkTo.h" // IWYU pragma: keep + +#include +#include +class GrBackendSemaphore; + +namespace skgpu { +enum class Mipmapped : bool; +enum class Protected : bool; +enum class Renderable : bool; +} + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Wraps a C++11 enum that we use as a bitfield, and enables a limited amount of + * masking with type safety. Instantiated with the ~ operator. + */ +template class GrTFlagsMask { +public: + constexpr explicit GrTFlagsMask(TFlags value) : GrTFlagsMask(static_cast(value)) {} + constexpr explicit GrTFlagsMask(int value) : fValue(value) {} + constexpr int value() const { return fValue; } +private: + const int fValue; +}; + +/** + * Defines bitwise operators that make it possible to use an enum class as a + * basic bitfield. + */ +#define GR_MAKE_BITFIELD_CLASS_OPS(X) \ + [[maybe_unused]] constexpr GrTFlagsMask operator~(X a) { \ + return GrTFlagsMask(~static_cast(a)); \ + } \ + [[maybe_unused]] constexpr X operator|(X a, X b) { \ + return static_cast(static_cast(a) | static_cast(b)); \ + } \ + [[maybe_unused]] inline X& operator|=(X& a, X b) { \ + return (a = a | b); \ + } \ + [[maybe_unused]] constexpr bool operator&(X a, X b) { \ + return SkToBool(static_cast(a) & static_cast(b)); \ + } \ + [[maybe_unused]] constexpr GrTFlagsMask operator|(GrTFlagsMask a, GrTFlagsMask b) { \ + return GrTFlagsMask(a.value() | b.value()); \ + } \ + [[maybe_unused]] constexpr GrTFlagsMask operator|(GrTFlagsMask a, X b) { \ + return GrTFlagsMask(a.value() | static_cast(b)); \ + } \ + [[maybe_unused]] constexpr GrTFlagsMask operator|(X a, GrTFlagsMask b) { \ + return GrTFlagsMask(static_cast(a) | b.value()); \ + } \ + [[maybe_unused]] constexpr X operator&(GrTFlagsMask a, GrTFlagsMask b) { \ + return static_cast(a.value() & b.value()); \ + } \ + [[maybe_unused]] constexpr X operator&(GrTFlagsMask a, X b) { \ + return static_cast(a.value() & static_cast(b)); \ + } \ + [[maybe_unused]] constexpr X operator&(X a, GrTFlagsMask b) { \ + return static_cast(static_cast(a) & b.value()); \ + } \ + [[maybe_unused]] inline X& operator&=(X& a, GrTFlagsMask b) { \ + return (a = a & b); \ + } \ + +#define GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(X) \ + friend constexpr GrTFlagsMask operator ~(X); \ + friend constexpr X operator |(X, X); \ + friend X& operator |=(X&, X); \ + friend constexpr bool operator &(X, X); \ + friend constexpr GrTFlagsMask operator|(GrTFlagsMask, GrTFlagsMask); \ + friend constexpr GrTFlagsMask operator|(GrTFlagsMask, X); \ + friend constexpr GrTFlagsMask operator|(X, GrTFlagsMask); \ + friend constexpr X operator&(GrTFlagsMask, GrTFlagsMask); \ + friend constexpr X operator&(GrTFlagsMask, X); \ + friend constexpr X operator&(X, GrTFlagsMask); \ + friend X& operator &=(X&, GrTFlagsMask) + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Possible 3D APIs that may be used by Ganesh. + */ +enum class GrBackendApi : unsigned { + kOpenGL, + kVulkan, + kMetal, + kDirect3D, + kDawn, + /** + * Mock is a backend that does not draw anything. It is used for unit tests + * and to measure CPU overhead. + */ + kMock, + + /** + * Added here to support the legacy GrBackend enum value and clients who referenced it using + * GrBackend::kOpenGL_GrBackend. + */ + kOpenGL_GrBackend = kOpenGL, +}; + +/** + * Previously the above enum was not an enum class but a normal enum. To support the legacy use of + * the enum values we define them below so that no clients break. + */ +typedef GrBackendApi GrBackend; + +static constexpr GrBackendApi kMetal_GrBackend = GrBackendApi::kMetal; +static constexpr GrBackendApi kVulkan_GrBackend = GrBackendApi::kVulkan; +static constexpr GrBackendApi kMock_GrBackend = GrBackendApi::kMock; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Used to say whether a texture has mip levels allocated or not. + */ +/** Deprecated legacy alias of skgpu::Mipmapped. */ +using GrMipmapped = skgpu::Mipmapped; +/** Deprecated legacy alias of skgpu::Mipmapped. */ +using GrMipMapped = skgpu::Mipmapped; + +/* + * Can a GrBackendObject be rendered to? + */ +using GrRenderable = skgpu::Renderable; + +/* + * Used to say whether texture is backed by protected memory. + */ +using GrProtected = skgpu::Protected; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * GPU SkImage and SkSurfaces can be stored such that (0, 0) in texture space may correspond to + * either the top-left or bottom-left content pixel. + */ +enum GrSurfaceOrigin : int { + kTopLeft_GrSurfaceOrigin, + kBottomLeft_GrSurfaceOrigin, +}; + +/** + * A GrContext's cache of backend context state can be partially invalidated. + * These enums are specific to the GL backend and we'd add a new set for an alternative backend. + */ +enum GrGLBackendState { + kRenderTarget_GrGLBackendState = 1 << 0, + // Also includes samplers bound to texture units. + kTextureBinding_GrGLBackendState = 1 << 1, + // View state stands for scissor and viewport + kView_GrGLBackendState = 1 << 2, + kBlend_GrGLBackendState = 1 << 3, + kMSAAEnable_GrGLBackendState = 1 << 4, + kVertex_GrGLBackendState = 1 << 5, + kStencil_GrGLBackendState = 1 << 6, + kPixelStore_GrGLBackendState = 1 << 7, + kProgram_GrGLBackendState = 1 << 8, + kFixedFunction_GrGLBackendState = 1 << 9, + kMisc_GrGLBackendState = 1 << 10, + kALL_GrGLBackendState = 0xffff +}; + +/** + * This value translates to reseting all the context state for any backend. + */ +static const uint32_t kAll_GrBackendState = 0xffffffff; + +typedef void* GrGpuFinishedContext; +typedef void (*GrGpuFinishedProc)(GrGpuFinishedContext finishedContext); + +typedef void* GrGpuSubmittedContext; +typedef void (*GrGpuSubmittedProc)(GrGpuSubmittedContext submittedContext, bool success); + +typedef void* GrDirectContextDestroyedContext; +typedef void (*GrDirectContextDestroyedProc)(GrDirectContextDestroyedContext destroyedContext); + +/** + * Struct to supply options to flush calls. + * + * After issuing all commands, fNumSemaphore semaphores will be signaled by the gpu. The client + * passes in an array of fNumSemaphores GrBackendSemaphores. In general these GrBackendSemaphore's + * can be either initialized or not. If they are initialized, the backend uses the passed in + * semaphore. If it is not initialized, a new semaphore is created and the GrBackendSemaphore + * object is initialized with that semaphore. The semaphores are not sent to the GPU until the next + * GrContext::submit call is made. See the GrContext::submit for more information. + * + * The client will own and be responsible for deleting the underlying semaphores that are stored + * and returned in initialized GrBackendSemaphore objects. The GrBackendSemaphore objects + * themselves can be deleted as soon as this function returns. + * + * If a finishedProc is provided, the finishedProc will be called when all work submitted to the gpu + * from this flush call and all previous flush calls has finished on the GPU. If the flush call + * fails due to an error and nothing ends up getting sent to the GPU, the finished proc is called + * immediately. + * + * If a submittedProc is provided, the submittedProc will be called when all work from this flush + * call is submitted to the GPU. If the flush call fails due to an error and nothing will get sent + * to the GPU, the submitted proc is called immediately. It is possibly that when work is finally + * submitted, that the submission actual fails. In this case we will not reattempt to do the + * submission. Skia notifies the client of these via the success bool passed into the submittedProc. + * The submittedProc is useful to the client to know when semaphores that were sent with the flush + * have actually been submitted to the GPU so that they can be waited on (or deleted if the submit + * fails). + * Note about GL: In GL work gets sent to the driver immediately during the flush call, but we don't + * really know when the driver sends the work to the GPU. Therefore, we treat the submitted proc as + * we do in other backends. It will be called when the next GrContext::submit is called after the + * flush (or possibly during the flush if there is no work to be done for the flush). The main use + * case for the submittedProc is to know when semaphores have been sent to the GPU and even in GL + * it is required to call GrContext::submit to flush them. So a client should be able to treat all + * backend APIs the same in terms of how the submitted procs are treated. + */ +struct GrFlushInfo { + size_t fNumSemaphores = 0; + GrBackendSemaphore* fSignalSemaphores = nullptr; + GrGpuFinishedProc fFinishedProc = nullptr; + GrGpuFinishedContext fFinishedContext = nullptr; + GrGpuSubmittedProc fSubmittedProc = nullptr; + GrGpuSubmittedContext fSubmittedContext = nullptr; +}; + +/** + * Enum used as return value when flush with semaphores so the client knows whether the valid + * semaphores will be submitted on the next GrContext::submit call. + */ +enum class GrSemaphoresSubmitted : bool { + kNo = false, + kYes = true +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrYUVABackendTextures.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrYUVABackendTextures.h new file mode 100644 index 00000000000000..edcde7e5335bc9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/GrYUVABackendTextures.h @@ -0,0 +1,124 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrYUVABackendTextures_DEFINED +#define GrYUVABackendTextures_DEFINED + +#include "include/core/SkYUVAInfo.h" +#include "include/gpu/GrBackendSurface.h" + +#include + +/** + * A description of a set GrBackendTextures that hold the planar data described by a SkYUVAInfo. + */ +class SK_API GrYUVABackendTextureInfo { +public: + static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; + + /** Default GrYUVABackendTextureInfo is invalid. */ + GrYUVABackendTextureInfo() = default; + + /** + * Initializes a GrYUVABackendTextureInfo to describe a set of textures that can store the + * planes indicated by the SkYUVAInfo. The texture dimensions are taken from the SkYUVAInfo's + * plane dimensions. All the described textures share a common origin. The planar image this + * describes will be mip mapped if all the textures are individually mip mapped as indicated + * by GrMipmapped. This will produce an invalid result (return false from isValid()) if the + * passed formats' channels don't agree with SkYUVAInfo. + */ + GrYUVABackendTextureInfo(const SkYUVAInfo&, + const GrBackendFormat[kMaxPlanes], + GrMipmapped, + GrSurfaceOrigin); + + GrYUVABackendTextureInfo(const GrYUVABackendTextureInfo&) = default; + + GrYUVABackendTextureInfo& operator=(const GrYUVABackendTextureInfo&) = default; + + bool operator==(const GrYUVABackendTextureInfo&) const; + bool operator!=(const GrYUVABackendTextureInfo& that) const { return !(*this == that); } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); } + + GrMipmapped mipmapped() const { return fMipmapped; } + + GrSurfaceOrigin textureOrigin() const { return fTextureOrigin; } + + /** The number of SkPixmap planes, 0 if this GrYUVABackendTextureInfo is invalid. */ + int numPlanes() const { return fYUVAInfo.numPlanes(); } + + /** Format of the ith plane, or invalid format if i >= numPlanes() */ + const GrBackendFormat& planeFormat(int i) const { return fPlaneFormats[i]; } + + /** + * Returns true if this has been configured with a valid SkYUVAInfo with compatible texture + * formats. + */ + bool isValid() const { return fYUVAInfo.isValid(); } + + /** + * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be + * valid if this->isValid(). + */ + SkYUVAInfo::YUVALocations toYUVALocations() const; + +private: + SkYUVAInfo fYUVAInfo; + GrBackendFormat fPlaneFormats[kMaxPlanes]; + GrMipmapped fMipmapped = GrMipmapped::kNo; + GrSurfaceOrigin fTextureOrigin = kTopLeft_GrSurfaceOrigin; +}; + +/** + * A set of GrBackendTextures that hold the planar data for an image described a SkYUVAInfo. + */ +class SK_API GrYUVABackendTextures { +public: + GrYUVABackendTextures() = default; + GrYUVABackendTextures(const GrYUVABackendTextures&) = delete; + GrYUVABackendTextures(GrYUVABackendTextures&&) = default; + + GrYUVABackendTextures& operator=(const GrYUVABackendTextures&) = delete; + GrYUVABackendTextures& operator=(GrYUVABackendTextures&&) = default; + + GrYUVABackendTextures(const SkYUVAInfo&, + const GrBackendTexture[SkYUVAInfo::kMaxPlanes], + GrSurfaceOrigin textureOrigin); + + const std::array& textures() const { + return fTextures; + } + + GrBackendTexture texture(int i) const { + SkASSERT(i >= 0 && i < SkYUVAInfo::kMaxPlanes); + return fTextures[static_cast(i)]; + } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + int numPlanes() const { return fYUVAInfo.numPlanes(); } + + GrSurfaceOrigin textureOrigin() const { return fTextureOrigin; } + + bool isValid() const { return fYUVAInfo.isValid(); } + + /** + * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be + * valid if this->isValid(). + */ + SkYUVAInfo::YUVALocations toYUVALocations() const; + +private: + SkYUVAInfo fYUVAInfo; + std::array fTextures; + GrSurfaceOrigin fTextureOrigin = kTopLeft_GrSurfaceOrigin; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/MutableTextureState.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/MutableTextureState.h new file mode 100644 index 00000000000000..19b7cd54c681a1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/MutableTextureState.h @@ -0,0 +1,122 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_MutableTextureState_DEFINED +#define skgpu_MutableTextureState_DEFINED + +#include "include/gpu/GpuTypes.h" + +#ifdef SK_VULKAN +#include "include/private/gpu/vk/VulkanTypesPriv.h" +#endif + +#include + +class GrVkGpu; + +namespace skgpu { + +/** + * Since Skia and clients can both modify gpu textures and their connected state, Skia needs a way + * for clients to inform us if they have modifiend any of this state. In order to not need setters + * for every single API and state, we use this class to be a generic wrapper around all the mutable + * state. This class is used for calls that inform Skia of these texture/image state changes by the + * client as well as for requesting state changes to be done by Skia. The backend specific state + * that is wrapped by this class are: + * + * Vulkan: VkImageLayout and QueueFamilyIndex + */ +class SK_API MutableTextureState { +public: + MutableTextureState() {} + +#ifdef SK_VULKAN + MutableTextureState(VkImageLayout layout, uint32_t queueFamilyIndex) + : fVkState(layout, queueFamilyIndex) + , fBackend(BackendApi::kVulkan) + , fIsValid(true) {} +#endif + + MutableTextureState(const MutableTextureState& that) + : fBackend(that.fBackend), fIsValid(that.fIsValid) { + if (!fIsValid) { + return; + } + switch (fBackend) { + case BackendApi::kVulkan: + #ifdef SK_VULKAN + SkASSERT(that.fBackend == BackendApi::kVulkan); + fVkState = that.fVkState; + #endif + break; + default: + (void)that; + SkUNREACHABLE; + } + } + + MutableTextureState& operator=(const MutableTextureState& that) { + if (this != &that) { + this->~MutableTextureState(); + new (this) MutableTextureState(that); + } + return *this; + } + +#ifdef SK_VULKAN + // If this class is not Vulkan backed it will return value of VK_IMAGE_LAYOUT_UNDEFINED. + // Otherwise it will return the VkImageLayout. + VkImageLayout getVkImageLayout() const { + if (this->isValid() && fBackend != BackendApi::kVulkan) { + return VK_IMAGE_LAYOUT_UNDEFINED; + } + return fVkState.getImageLayout(); + } + + // If this class is not Vulkan backed it will return value of VK_QUEUE_FAMILY_IGNORED. + // Otherwise it will return the VkImageLayout. + uint32_t getQueueFamilyIndex() const { + if (this->isValid() && fBackend != BackendApi::kVulkan) { + return VK_QUEUE_FAMILY_IGNORED; + } + return fVkState.getQueueFamilyIndex(); + } +#endif + + BackendApi backend() const { return fBackend; } + + // Returns true if the backend mutable state has been initialized. + bool isValid() const { return fIsValid; } + +private: + friend class MutableTextureStateRef; + friend class ::GrVkGpu; + +#ifdef SK_VULKAN + void setVulkanState(VkImageLayout layout, uint32_t queueFamilyIndex) { + SkASSERT(!this->isValid() || fBackend == BackendApi::kVulkan); + fVkState.setImageLayout(layout); + fVkState.setQueueFamilyIndex(queueFamilyIndex); + fBackend = BackendApi::kVulkan; + fIsValid = true; + } +#endif + + union { + char fPlaceholder; +#ifdef SK_VULKAN + VulkanMutableTextureState fVkState; +#endif + }; + + BackendApi fBackend = BackendApi::kMock; + bool fIsValid = false; +}; + +} // namespace skgpu + +#endif // skgpu_MutableTextureState_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ShaderErrorHandler.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ShaderErrorHandler.h new file mode 100644 index 00000000000000..8960da5c5a212b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ShaderErrorHandler.h @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_ShaderErrorHandler_DEFINED +#define skgpu_ShaderErrorHandler_DEFINED + +#include "include/core/SkTypes.h" + +namespace skgpu { +/** + * Abstract class to report errors when compiling shaders. + */ +class SK_API ShaderErrorHandler { +public: + virtual ~ShaderErrorHandler() = default; + + virtual void compileError(const char* shader, const char* errors) = 0; + +protected: + ShaderErrorHandler() = default; + ShaderErrorHandler(const ShaderErrorHandler&) = delete; + ShaderErrorHandler& operator=(const ShaderErrorHandler&) = delete; +}; + +/** + * Used when no error handler is set. Will report failures via SkDebugf and asserts. + */ +ShaderErrorHandler* DefaultShaderErrorHandler(); + +} // namespace skgpu + +#endif // skgpu_ShaderErrorHandler_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/d3d/GrD3DBackendContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/d3d/GrD3DBackendContext.h new file mode 100644 index 00000000000000..bb85e52e5c0fc3 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/d3d/GrD3DBackendContext.h @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DBackendContext_DEFINED +#define GrD3DBackendContext_DEFINED + +// GrD3DTypes.h includes d3d12.h, which in turn includes windows.h, which redefines many +// common identifiers such as: +// * interface +// * small +// * near +// * far +// * CreateSemaphore +// * MemoryBarrier +// +// You should only include GrD3DBackendContext.h if you are prepared to rename those identifiers. +#include "include/gpu/d3d/GrD3DTypes.h" + +#include "include/gpu/GrTypes.h" + +// The BackendContext contains all of the base D3D objects needed by the GrD3DGpu. The assumption +// is that the client will set these up and pass them to the GrD3DGpu constructor. +struct SK_API GrD3DBackendContext { + gr_cp fAdapter; + gr_cp fDevice; + gr_cp fQueue; + sk_sp fMemoryAllocator; + GrProtected fProtectedContext = GrProtected::kNo; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/d3d/GrD3DTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/d3d/GrD3DTypes.h new file mode 100644 index 00000000000000..b595422e8692ae --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/d3d/GrD3DTypes.h @@ -0,0 +1,248 @@ + +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DTypes_DEFINED +#define GrD3DTypes_DEFINED + +// This file includes d3d12.h, which in turn includes windows.h, which redefines many +// common identifiers such as: +// * interface +// * small +// * near +// * far +// * CreateSemaphore +// * MemoryBarrier +// +// You should only include this header if you need the Direct3D definitions and are +// prepared to rename those identifiers. + +#include "include/core/SkRefCnt.h" +#include "include/gpu/GpuTypes.h" +#include +#include + +class GrD3DGpu; + + /** Check if the argument is non-null, and if so, call obj->AddRef() and return obj. + */ +template static inline T* GrSafeComAddRef(T* obj) { + if (obj) { + obj->AddRef(); + } + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->Release() + */ +template static inline void GrSafeComRelease(T* obj) { + if (obj) { + obj->Release(); + } +} + +template class gr_cp { +public: + using element_type = T; + + constexpr gr_cp() : fObject(nullptr) {} + constexpr gr_cp(std::nullptr_t) : fObject(nullptr) {} + + /** + * Shares the underlying object by calling AddRef(), so that both the argument and the newly + * created gr_cp both have a reference to it. + */ + gr_cp(const gr_cp& that) : fObject(GrSafeComAddRef(that.get())) {} + + /** + * Move the underlying object from the argument to the newly created gr_cp. Afterwards only + * the new gr_cp will have a reference to the object, and the argument will point to null. + * No call to AddRef() or Release() will be made. + */ + gr_cp(gr_cp&& that) : fObject(that.release()) {} + + /** + * Adopt the bare object into the newly created gr_cp. + * No call to AddRef() or Release() will be made. + */ + explicit gr_cp(T* obj) { + fObject = obj; + } + + /** + * Calls Release() on the underlying object pointer. + */ + ~gr_cp() { + GrSafeComRelease(fObject); + SkDEBUGCODE(fObject = nullptr); + } + + /** + * Shares the underlying object referenced by the argument by calling AddRef() on it. If this + * gr_cp previously had a reference to an object (i.e. not null) it will call Release() + * on that object. + */ + gr_cp& operator=(const gr_cp& that) { + if (this != &that) { + this->reset(GrSafeComAddRef(that.get())); + } + return *this; + } + + /** + * Move the underlying object from the argument to the gr_cp. If the gr_cp + * previously held a reference to another object, Release() will be called on that object. + * No call to AddRef() will be made. + */ + gr_cp& operator=(gr_cp&& that) { + this->reset(that.release()); + return *this; + } + + explicit operator bool() const { return this->get() != nullptr; } + + T* get() const { return fObject; } + T* operator->() const { return fObject; } + T** operator&() { return &fObject; } + + /** + * Adopt the new object, and call Release() on any previously held object (if not null). + * No call to AddRef() will be made. + */ + void reset(T* object = nullptr) { + T* oldObject = fObject; + fObject = object; + GrSafeComRelease(oldObject); + } + + /** + * Shares the new object by calling AddRef() on it. If this gr_cp previously had a + * reference to an object (i.e. not null) it will call Release() on that object. + */ + void retain(T* object) { + if (this->fObject != object) { + this->reset(GrSafeComAddRef(object)); + } + } + + /** + * Return the original object, and set the internal object to nullptr. + * The caller must assume ownership of the object, and manage its reference count directly. + * No call to Release() will be made. + */ + T* SK_WARN_UNUSED_RESULT release() { + T* obj = fObject; + fObject = nullptr; + return obj; + } + +private: + T* fObject; +}; + +template inline bool operator==(const gr_cp& a, + const gr_cp& b) { + return a.get() == b.get(); +} + +template inline bool operator!=(const gr_cp& a, + const gr_cp& b) { + return a.get() != b.get(); +} + +// interface classes for the GPU memory allocator +class GrD3DAlloc : public SkRefCnt { +public: + ~GrD3DAlloc() override = default; +}; + +class GrD3DMemoryAllocator : public SkRefCnt { +public: + virtual gr_cp createResource(D3D12_HEAP_TYPE, const D3D12_RESOURCE_DESC*, + D3D12_RESOURCE_STATES initialResourceState, + sk_sp* allocation, + const D3D12_CLEAR_VALUE*) = 0; + virtual gr_cp createAliasingResource(sk_sp& allocation, + uint64_t localOffset, + const D3D12_RESOURCE_DESC*, + D3D12_RESOURCE_STATES initialResourceState, + const D3D12_CLEAR_VALUE*) = 0; +}; + +// Note: there is no notion of Borrowed or Adopted resources in the D3D backend, +// so Ganesh will ref fResource once it's asked to wrap it. +// Clients are responsible for releasing their own ref to avoid memory leaks. +struct GrD3DTextureResourceInfo { + gr_cp fResource = nullptr; + sk_sp fAlloc = nullptr; + D3D12_RESOURCE_STATES fResourceState = D3D12_RESOURCE_STATE_COMMON; + DXGI_FORMAT fFormat = DXGI_FORMAT_UNKNOWN; + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + unsigned int fSampleQualityPattern = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + GrD3DTextureResourceInfo() = default; + + GrD3DTextureResourceInfo(ID3D12Resource* resource, + const sk_sp alloc, + D3D12_RESOURCE_STATES resourceState, + DXGI_FORMAT format, + uint32_t sampleCount, + uint32_t levelCount, + unsigned int sampleQualityLevel, + skgpu::Protected isProtected = skgpu::Protected::kNo) + : fResource(resource) + , fAlloc(alloc) + , fResourceState(resourceState) + , fFormat(format) + , fSampleCount(sampleCount) + , fLevelCount(levelCount) + , fSampleQualityPattern(sampleQualityLevel) + , fProtected(isProtected) {} + + GrD3DTextureResourceInfo(const GrD3DTextureResourceInfo& info, + D3D12_RESOURCE_STATES resourceState) + : fResource(info.fResource) + , fAlloc(info.fAlloc) + , fResourceState(resourceState) + , fFormat(info.fFormat) + , fSampleCount(info.fSampleCount) + , fLevelCount(info.fLevelCount) + , fSampleQualityPattern(info.fSampleQualityPattern) + , fProtected(info.fProtected) {} + +#if GR_TEST_UTILS + bool operator==(const GrD3DTextureResourceInfo& that) const { + return fResource == that.fResource && fResourceState == that.fResourceState && + fFormat == that.fFormat && fSampleCount == that.fSampleCount && + fLevelCount == that.fLevelCount && + fSampleQualityPattern == that.fSampleQualityPattern && fProtected == that.fProtected; + } +#endif +}; + +struct GrD3DFenceInfo { + GrD3DFenceInfo() + : fFence(nullptr) + , fValue(0) { + } + + gr_cp fFence; + uint64_t fValue; // signal value for the fence +}; + +struct GrD3DSurfaceInfo { + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + DXGI_FORMAT fFormat = DXGI_FORMAT_UNKNOWN; + unsigned int fSampleQualityPattern = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/dawn/GrDawnTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/dawn/GrDawnTypes.h new file mode 100644 index 00000000000000..fbd3dbaf55cb1a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/dawn/GrDawnTypes.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDawnTypes_DEFINED +#define GrDawnTypes_DEFINED + +#include "include/gpu/GpuTypes.h" + +#ifdef Always +#undef Always +static constexpr int Always = 2; +#endif +#ifdef Success +#undef Success +static constexpr int Success = 0; +#endif +#ifdef None +#undef None +static constexpr int None = 0L; +#endif +#include "webgpu/webgpu_cpp.h" // IWYU pragma: export + +struct GrDawnTextureInfo { + wgpu::Texture fTexture; + wgpu::TextureFormat fFormat; + uint32_t fLevelCount; + GrDawnTextureInfo() : fTexture(nullptr), fFormat(), fLevelCount(0) { + } + GrDawnTextureInfo(const GrDawnTextureInfo& other) + : fTexture(other.fTexture) + , fFormat(other.fFormat) + , fLevelCount(other.fLevelCount) { + } + GrDawnTextureInfo& operator=(const GrDawnTextureInfo& other) { + fTexture = other.fTexture; + fFormat = other.fFormat; + fLevelCount = other.fLevelCount; + return *this; + } + bool operator==(const GrDawnTextureInfo& other) const { + return fTexture.Get() == other.fTexture.Get() && + fFormat == other.fFormat && + fLevelCount == other.fLevelCount; + } +}; + +// GrDawnRenderTargetInfo holds a reference to a (1-mip) TextureView. This means that, for now, +// GrDawnRenderTarget is suitable for rendering, but not readPixels() or writePixels(). Also, +// backdrop filters and certain blend modes requiring copying the destination framebuffer +// will not work. +struct GrDawnRenderTargetInfo { + wgpu::TextureView fTextureView; + wgpu::TextureFormat fFormat; + uint32_t fLevelCount; + GrDawnRenderTargetInfo() : fTextureView(nullptr), fFormat(), fLevelCount(0) { + } + GrDawnRenderTargetInfo(const GrDawnRenderTargetInfo& other) + : fTextureView(other.fTextureView) + , fFormat(other.fFormat) + , fLevelCount(other.fLevelCount) { + } + explicit GrDawnRenderTargetInfo(const GrDawnTextureInfo& texInfo) + : fFormat(texInfo.fFormat) + , fLevelCount(1) { + wgpu::TextureViewDescriptor desc; + desc.format = texInfo.fFormat; + desc.mipLevelCount = 1; + fTextureView = texInfo.fTexture.CreateView(&desc); + } + GrDawnRenderTargetInfo& operator=(const GrDawnRenderTargetInfo& other) { + fTextureView = other.fTextureView; + fFormat = other.fFormat; + fLevelCount = other.fLevelCount; + return *this; + } + bool operator==(const GrDawnRenderTargetInfo& other) const { + return fTextureView.Get() == other.fTextureView.Get() && + fFormat == other.fFormat && + fLevelCount == other.fLevelCount; + } +}; + +struct GrDawnSurfaceInfo { + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + wgpu::TextureFormat fFormat; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ganesh/GrTextureGenerator.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ganesh/GrTextureGenerator.h new file mode 100644 index 00000000000000..68f13ce4b5119d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ganesh/GrTextureGenerator.h @@ -0,0 +1,77 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureGenerator_DEFINED +#define GrTextureGenerator_DEFINED + +#include "include/core/SkImageGenerator.h" +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkAPI.h" + +#include +#include + +class GrRecordingContext; +class GrSurfaceProxyView; +class SkImage; +enum class GrImageTexGenPolicy : int; +namespace skgpu { enum class Mipmapped : bool; } +struct SkImageInfo; + +class SK_API GrTextureGenerator : public SkImageGenerator { +public: + bool isTextureGenerator() const final { return true; } + + /** + * If the generator can natively/efficiently return its pixels as a GPU image (backed by a + * texture) this will return that image. If not, this will return NULL. + * + * Regarding the GrRecordingContext parameter: + * + * It must be non-NULL. The generator should only succeed if: + * - its internal context is the same + * - it can somehow convert its texture into one that is valid for the provided context. + * + * If the mipmapped parameter is kYes, the generator should try to create a TextureProxy that + * at least has the mip levels allocated and the base layer filled in. If this is not possible, + * the generator is allowed to return a non mipped proxy, but this will have some additional + * overhead in later allocating mips and copying of the base layer. + * + * GrImageTexGenPolicy determines whether or not a new texture must be created (and its budget + * status) or whether this may (but is not required to) return a pre-existing texture that is + * retained by the generator (kDraw). + */ + GrSurfaceProxyView generateTexture(GrRecordingContext*, + const SkImageInfo& info, + skgpu::Mipmapped mipmapped, + GrImageTexGenPolicy); + + virtual GrSurfaceProxyView onGenerateTexture(GrRecordingContext*, const SkImageInfo&, + skgpu::Mipmapped, GrImageTexGenPolicy) = 0; + + // Most internal SkImageGenerators produce textures and views that use kTopLeft_GrSurfaceOrigin. + // If the generator may produce textures with different origins (e.g. + // GrAHardwareBufferImageGenerator) it should override this function to return the correct + // origin. Implementations should be thread-safe. + virtual GrSurfaceOrigin origin() const { return kTopLeft_GrSurfaceOrigin; } + +protected: + GrTextureGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID); +}; + +namespace SkImages { +/** + * Like SkImages::DeferredFromGenerator except allows for the use of SkGaneshTextureGenerator. + * + * @param gen producer of textures + * @return created SkImage, or nullptr + */ +SK_API sk_sp DeferredFromTextureGenerator(std::unique_ptr gen); +} + +#endif // GrTextureGenerator_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ganesh/SkImageGanesh.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ganesh/SkImageGanesh.h new file mode 100644 index 00000000000000..296d90d17e3f9f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/ganesh/SkImageGanesh.h @@ -0,0 +1,385 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageGanesh_DEFINED +#define SkImageGanesh_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkRefCnt.h" +#include "include/gpu/GpuTypes.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkAPI.h" + +#include +#include + +class GrBackendFormat; +class GrBackendTexture; +class GrContextThreadSafeProxy; +class GrDirectContext; +class GrRecordingContext; +class GrYUVABackendTextureInfo; +class GrYUVABackendTextures; +class SkColorSpace; +class SkData; +class SkPixmap; +class SkPromiseImageTexture; +class SkYUVAPixmaps; +enum SkAlphaType : int; +enum SkColorType : int; +enum class SkTextureCompressionType; +struct SkISize; + +/** + * All factories in this file refer to the Ganesh GPU backend when they say GPU. + */ + +namespace SkImages { +/** Defines a callback function, taking one parameter of type GrBackendTexture with + no return value. Function is called when backend texture is to be released. +*/ +using BackendTextureReleaseProc = std::function; +/** User function called when supplied texture may be deleted. */ +using TextureReleaseProc = void (*)(ReleaseContext); + +/** Creates GPU-backed SkImage from backendTexture associated with context. + Skia will assume ownership of the resource and will release it when no longer needed. + A non-null SkImage is returned if format of backendTexture is recognized and supported. + Recognized formats vary by GPU backend. + @param context GPU context + @param backendTexture texture residing on GPU + @param textureOrigin origin of backendTexture + @param colorType color type of the resulting image + @param alphaType alpha type of the resulting image + @param colorSpace range of colors; may be nullptr + @return created SkImage, or nullptr +*/ +SK_API sk_sp AdoptTextureFrom(GrRecordingContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin textureOrigin, + SkColorType colorType); +SK_API sk_sp AdoptTextureFrom(GrRecordingContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin textureOrigin, + SkColorType colorType, + SkAlphaType alphaType); +SK_API sk_sp AdoptTextureFrom(GrRecordingContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin textureOrigin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp colorSpace); + +/** Creates GPU-backed SkImage from the provided GPU texture associated with context. + GPU texture must stay valid and unchanged until textureReleaseProc is called by Skia. + Skia will call textureReleaseProc with the passed-in releaseContext when SkImage + is deleted or no longer refers to the texture. + A non-null SkImage is returned if format of backendTexture is recognized and supported. + Recognized formats vary by GPU backend. + @note When using a DDL recording context, textureReleaseProc will be called on the + GPU thread after the DDL is played back on the direct context. + @param context GPU context + @param backendTexture texture residing on GPU + @param colorSpace This describes the color space of this image's contents, as + seen after sampling. In general, if the format of the backend + texture is SRGB, some linear colorSpace should be supplied + (e.g., SkColorSpace::MakeSRGBLinear()). If the format of the + backend texture is linear, then the colorSpace should include + a description of the transfer function as + well (e.g., SkColorSpace::MakeSRGB()). + @param textureReleaseProc function called when texture can be released + @param releaseContext state passed to textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp BorrowTextureFrom(GrRecordingContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp colorSpace, + TextureReleaseProc textureReleaseProc = nullptr, + ReleaseContext releaseContext = nullptr); + +/** Creates a GPU-backed SkImage from pixmap. It is uploaded to GPU backend using context. + Created SkImage is available to other GPU contexts, and is available across thread + boundaries. All contexts must be in the same GPU share group, or otherwise + share resources. + When SkImage is no longer referenced, context releases texture memory + asynchronously. + SkColorSpace of SkImage is determined by pixmap.colorSpace(). + SkImage is returned referring to GPU backend if context is not nullptr, + format of data is recognized and supported, and if context supports moving + resources between contexts. Otherwise, pixmap pixel data is copied and SkImage + as returned in raster format if possible; nullptr may be returned. + Recognized GPU formats vary by platform and GPU backend. + @param context GPU context + @param pixmap SkImageInfo, pixel address, and row bytes + @param buildMips create SkImage as mip map if true + @param limitToMaxTextureSize downscale image to GPU maximum texture size, if necessary + @return created SkImage, or nullptr +*/ +SK_API sk_sp CrossContextTextureFromPixmap(GrDirectContext* context, + const SkPixmap& pixmap, + bool buildMips, + bool limitToMaxTextureSize = false); + +/** Creates a GPU-backed SkImage from a GPU backend texture. The backend texture must stay + valid and unchanged until textureReleaseProc is called. The textureReleaseProc is + called when the SkImage is deleted or no longer refers to the texture and will be + passed the releaseContext. + An SkImage is returned if the format of backendTexture is recognized and supported. + Recognized formats vary by GPU backend. + @note When using a DDL recording context, textureReleaseProc will be called on the + GPU thread after the DDL is played back on the direct context. + @param context the GPU context + @param backendTexture a texture already allocated by the GPU + @param alphaType This characterizes the nature of the alpha values in the + backend texture. For opaque compressed formats (e.g., ETC1) + this should usually be set to kOpaq + ue_SkAlphaType. + @param colorSpace This describes the color space of this image's contents, as + seen after sampling. In general, if the format of the backend + texture is SRGB, some linear colorSpace should be supplied + (e.g., SkColorSpace::MakeSRGBLinear()). If the format of the + backend texture is linear, then the colorSpace should include + a description of the transfer function as + well (e.g., SkColorSpace::MakeSRGB()). + @param textureReleaseProc function called when the backend texture can be released + @param releaseContext state passed to textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp TextureFromCompressedTexture(GrRecordingContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + SkAlphaType alphaType, + sk_sp colorSpace, + TextureReleaseProc textureReleaseProc = nullptr, + ReleaseContext releaseContext = nullptr); + +/** Creates a GPU-backed SkImage from compressed data. + This method will return an SkImage representing the compressed data. + If the GPU doesn't support the specified compression method, the data + will be decompressed and then wrapped in a GPU-backed image. + Note: one can query the supported compression formats via + GrRecordingContext::compressedBackendFormat. + @param context GPU context + @param data compressed data to store in SkImage + @param width width of full SkImage + @param height height of full SkImage + @param type type of compression used + @param mipmapped does 'data' contain data for all the mipmap levels? + @param isProtected do the contents of 'data' require DRM protection (on Vulkan)? + @return created SkImage, or nullptr +*/ +SK_API sk_sp TextureFromCompressedTextureData(GrDirectContext* direct, + sk_sp data, + int width, + int height, + SkTextureCompressionType type, + GrMipmapped mipmapped = GrMipmapped::kNo, + GrProtected isProtected = GrProtected::kNo); + +/** Returns SkImage backed by GPU texture associated with context. Returned SkImage is + compatible with SkSurface created with dstColorSpace. The returned SkImage respects + mipmapped setting; if mipmapped equals skgpu::Mipmapped::kYes, the backing texture + allocates mip map levels. + The mipmapped parameter is effectively treated as kNo if MIP maps are not supported by the + GPU. + Returns original SkImage if the image is already texture-backed, the context matches, and + mipmapped is compatible with the backing GPU texture. skgpu::Budgeted is ignored in this + case. + Returns nullptr if context is nullptr, or if SkImage was created with another + GrDirectContext. + @param GrDirectContext the GrDirectContext in play, if it exists + @param SkImage a non-null pointer to an SkImage. + @param skgpu::Mipmapped Whether created SkImage texture must allocate mip map levels. + Defaults to no. + @param skgpu::Budgeted Whether to count a newly created texture for the returned image + counts against the context's budget. Defaults to yes. + @return created SkImage, or nullptr +*/ +SK_API sk_sp TextureFromImage(GrDirectContext*, + const SkImage*, + skgpu::Mipmapped = skgpu::Mipmapped::kNo, + skgpu::Budgeted = skgpu::Budgeted::kYes); +inline sk_sp TextureFromImage(GrDirectContext* ctx, + sk_sp img, + skgpu::Mipmapped m = skgpu::Mipmapped::kNo, + skgpu::Budgeted b = skgpu::Budgeted::kYes) { + return TextureFromImage(ctx, img.get(), m, b); +} + +/** Creates a GPU-backed SkImage from SkYUVAPixmaps. + The image will remain planar with each plane converted to a texture using the passed + GrRecordingContext. + SkYUVAPixmaps has a SkYUVAInfo which specifies the transformation from YUV to RGB. + The SkColorSpace of the resulting RGB values is specified by imageColorSpace. This will + be the SkColorSpace reported by the image and when drawn the RGB values will be converted + from this space into the destination space (if the destination is tagged). + Currently, this is only supported using the GPU backend and will fail if context is nullptr. + SkYUVAPixmaps does not need to remain valid after this returns. + @param context GPU context + @param pixmaps The planes as pixmaps with supported SkYUVAInfo that + specifies conversion to RGB. + @param buildMips create internal YUVA textures as mip map if kYes. This is + silently ignored if the context does not support mip maps. + @param limitToMaxTextureSize downscale image to GPU maximum texture size, if necessary + @param imageColorSpace range of colors of the resulting image; may be nullptr + @return created SkImage, or nullptr +*/ +SK_API sk_sp TextureFromYUVAPixmaps(GrRecordingContext* context, + const SkYUVAPixmaps& pixmaps, + GrMipmapped buildMips, + bool limitToMaxTextureSize, + sk_sp imageColorSpace); +SK_API sk_sp TextureFromYUVAPixmaps(GrRecordingContext* context, + const SkYUVAPixmaps& pixmaps, + GrMipmapped buildMips = GrMipmapped::kNo, + bool limitToMaxTextureSize = false); + +/** Creates a GPU-backed SkImage from YUV[A] planar textures. This requires that the textures + * stay valid for the lifetime of the image. The ReleaseContext can be used to know when it is + * safe to either delete or overwrite the textures. If ReleaseProc is provided it is also called + * before return on failure. + @param context GPU context + @param yuvaTextures A set of textures containing YUVA data and a description of the + data and transformation to RGBA. + @param imageColorSpace range of colors of the resulting image after conversion to RGB; + may be nullptr + @param textureReleaseProc called when the backend textures can be released + @param releaseContext state passed to textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp TextureFromYUVATextures(GrRecordingContext* context, + const GrYUVABackendTextures& yuvaTextures, + sk_sp imageColorSpace, + TextureReleaseProc textureReleaseProc = nullptr, + ReleaseContext releaseContext = nullptr); +SK_API sk_sp TextureFromYUVATextures(GrRecordingContext* context, + const GrYUVABackendTextures& yuvaTextures); + +using PromiseImageTextureContext = void*; +using PromiseImageTextureFulfillProc = sk_sp (*)(PromiseImageTextureContext); +using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext); + +/** Create a new GPU-backed SkImage that is very similar to an SkImage created by BorrowTextureFrom. + The difference is that the caller need not have created the texture nor populated it with the + image pixel data. Moreover, the SkImage may be created on a thread as the creation of the + image does not require access to the backend API or GrDirectContext. Instead of passing a + GrBackendTexture the client supplies a description of the texture consisting of + GrBackendFormat, width, height, and GrMipmapped state. The resulting SkImage can be drawn + to a SkDeferredDisplayListRecorder or directly to a GPU-backed SkSurface. + When the actual texture is required to perform a backend API draw, textureFulfillProc will + be called to receive a GrBackendTexture. The properties of the GrBackendTexture must match + those set during the SkImage creation, and it must refer to a valid existing texture in the + backend API context/device, and be populated with the image pixel data. The texture cannot + be deleted until textureReleaseProc is called. + There is at most one call to each of textureFulfillProc and textureReleaseProc. + textureReleaseProc is always called even if image creation fails or if the + image is never fulfilled (e.g. it is never drawn or all draws are clipped out) + @param gpuContextProxy the thread-safe proxy of the gpu context. required. + @param backendFormat format of promised gpu texture + @param dimensions width & height of promised gpu texture + @param mipmapped mip mapped state of promised gpu texture + @param origin surface origin of promised gpu texture + @param colorType color type of promised gpu texture + @param alphaType alpha type of promised gpu texture + @param colorSpace range of colors; may be nullptr + @param textureFulfillProc function called to get actual gpu texture + @param textureReleaseProc function called when texture can be deleted + @param textureContext state passed to textureFulfillProc and textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp PromiseTextureFrom(sk_sp gpuContextProxy, + const GrBackendFormat& backendFormat, + SkISize dimensions, + GrMipmapped mipmapped, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp colorSpace, + PromiseImageTextureFulfillProc textureFulfillProc, + PromiseImageTextureReleaseProc textureReleaseProc, + PromiseImageTextureContext textureContext); + +/** This is similar to 'PromiseTextureFrom' but it creates a GPU-backed SkImage from YUV[A] data. + The source data may be planar (i.e. spread across multiple textures). In + the extreme Y, U, V, and A are all in different planes and thus the image is specified by + four textures. 'backendTextureInfo' describes the planar arrangement, texture formats, + conversion to RGB, and origin of the textures. Separate 'textureFulfillProc' and + 'textureReleaseProc' calls are made for each texture. Each texture has its own + PromiseImageTextureContext. If 'backendTextureInfo' is not valid then no release proc + calls are made. Otherwise, the calls will be made even on failure. 'textureContexts' has one + entry for each of the up to four textures, as indicated by 'backendTextureInfo'. + Currently the mip mapped property of 'backendTextureInfo' is ignored. However, in the + near future it will be required that if it is kYes then textureFulfillProc must return + a mip mapped texture for each plane in order to successfully draw the image. + @param gpuContextProxy the thread-safe proxy of the gpu context. required. + @param backendTextureInfo info about the promised yuva gpu texture + @param imageColorSpace range of colors; may be nullptr + @param textureFulfillProc function called to get actual gpu texture + @param textureReleaseProc function called when texture can be deleted + @param textureContexts state passed to textureFulfillProc and textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp PromiseTextureFromYUVA(sk_sp gpuContextProxy, + const GrYUVABackendTextureInfo& backendTextureInfo, + sk_sp imageColorSpace, + PromiseImageTextureFulfillProc textureFulfillProc, + PromiseImageTextureReleaseProc textureReleaseProc, + PromiseImageTextureContext textureContexts[]); + +/** Retrieves the existing backend texture. If SkImage is not a Ganesh-backend texture image + or otherwise does not have such a texture, false is returned. Otherwise, outTexture will + be set to the image's texture. + + If flushPendingGrContextIO is true, completes deferred I/O operations. + If origin in not nullptr, copies location of content drawn into SkImage. + @param outTexture Will be set to the underlying texture of the image if non-null. + @param flushPendingGrContextIO flag to flush outstanding requests + @param origin Will be set to the origin orientation of the image if non-null. + @return false if a Ganesh backend texture cannot be retrieved. +*/ +SK_API bool GetBackendTextureFromImage(const SkImage* img, + GrBackendTexture* outTexture, + bool flushPendingGrContextIO, + GrSurfaceOrigin* origin = nullptr); +inline bool GetBackendTextureFromImage(sk_sp img, + GrBackendTexture* outTexture, + bool flushPendingGrContextIO, + GrSurfaceOrigin* origin = nullptr) { + return GetBackendTextureFromImage(img.get(), outTexture, flushPendingGrContextIO, origin); +} + +/** Extracts the backendTexture from an existing SkImage. + If the image is not already GPU-backed, the raster data will be uploaded as a texture + and returned. + If this is the only reference to the image, the old image's texture will be + moved out of the passed in image. + If the image is shared (has a refcount > 1), the texture will be copied and then returned. + @param context GPU context + @param image image, either CPU-backed or GPU-backed + @param backendTexture Will be set to the underlying texture of the image. + @param backendTextureReleaseProc Called when the texture is released + @return false if image cannot be uploaded. +*/ +SK_API bool MakeBackendTextureFromImage(GrDirectContext* context, + sk_sp image, + GrBackendTexture* backendTexture, + BackendTextureReleaseProc* backendTextureReleaseProc); +// Legacy name +inline bool GetBackendTextureFromImage(GrDirectContext* context, + sk_sp image, + GrBackendTexture* backendTexture, + BackendTextureReleaseProc* backendTextureReleaseProc) { + return MakeBackendTextureFromImage(context, std::move(image), backendTexture, + backendTextureReleaseProc); +} + +} // namespace SkImages + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLAssembleHelpers.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLAssembleHelpers.h new file mode 100644 index 00000000000000..bfa2aea37670e5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLAssembleHelpers.h @@ -0,0 +1,11 @@ +/* + * Copyright 2019 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/gpu/gl/GrGLAssembleInterface.h" + +void GrGetEGLQueryAndDisplay(GrEGLQueryStringFn** queryString, GrEGLDisplay* display, + void* ctx, GrGLGetProc get); diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLAssembleInterface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLAssembleInterface.h new file mode 100644 index 00000000000000..4f9f9f9ee0f915 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLAssembleInterface.h @@ -0,0 +1,39 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/gpu/gl/GrGLInterface.h" + +typedef GrGLFuncPtr (*GrGLGetProc)(void* ctx, const char name[]); + +/** + * Generic function for creating a GrGLInterface for an either OpenGL or GLES. It calls + * get() to get each function address. ctx is a generic ptr passed to and interpreted by get(). + */ +SK_API sk_sp GrGLMakeAssembledInterface(void *ctx, GrGLGetProc get); + +/** + * Generic function for creating a GrGLInterface for an OpenGL (but not GLES) context. It calls + * get() to get each function address. ctx is a generic ptr passed to and interpreted by get(). + */ +SK_API sk_sp GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get); + +/** + * Generic function for creating a GrGLInterface for an OpenGL ES (but not Open GL) context. It + * calls get() to get each function address. ctx is a generic ptr passed to and interpreted by + * get(). + */ +SK_API sk_sp GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get); + +/** + * Generic function for creating a GrGLInterface for a WebGL (similar to OpenGL ES) context. It + * calls get() to get each function address. ctx is a generic ptr passed to and interpreted by + * get(). + */ +SK_API sk_sp GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get); + +/** Deprecated version of GrGLMakeAssembledInterface() that returns a bare pointer. */ +SK_API const GrGLInterface* GrGLAssembleInterface(void *ctx, GrGLGetProc get); diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLConfig.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLConfig.h new file mode 100644 index 00000000000000..e3573486ca7e40 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLConfig.h @@ -0,0 +1,79 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrGLConfig_DEFINED +#define GrGLConfig_DEFINED + +#include "include/gpu/GrTypes.h" + +/** + * Optional GL config file. + */ +#ifdef GR_GL_CUSTOM_SETUP_HEADER + #include GR_GL_CUSTOM_SETUP_HEADER +#endif + +#if !defined(GR_GL_FUNCTION_TYPE) + #if defined(SK_BUILD_FOR_WIN) + #define GR_GL_FUNCTION_TYPE __stdcall + #else + #define GR_GL_FUNCTION_TYPE + #endif +#endif + +/** + * The following are optional defines that can be enabled at the compiler + * command line, in a IDE project, in a GrUserConfig.h file, or in a GL custom + * file (if one is in use). If a GR_GL_CUSTOM_SETUP_HEADER is used they can + * also be placed there. + * + * GR_GL_LOG_CALLS: if 1 Gr can print every GL call using SkDebugf. Defaults to + * 0. Logging can be enabled and disabled at runtime using a debugger via to + * global gLogCallsGL. The initial value of gLogCallsGL is controlled by + * GR_GL_LOG_CALLS_START. + * + * GR_GL_LOG_CALLS_START: controls the initial value of gLogCallsGL when + * GR_GL_LOG_CALLS is 1. Defaults to 0. + * + * GR_GL_CHECK_ERROR: if enabled Gr can do a glGetError() after every GL call. + * Defaults to 1 if SK_DEBUG is set, otherwise 0. When GR_GL_CHECK_ERROR is 1 + * this can be toggled in a debugger using the gCheckErrorGL global. The initial + * value of gCheckErrorGL is controlled by by GR_GL_CHECK_ERROR_START. + * + * GR_GL_CHECK_ERROR_START: controls the initial value of gCheckErrorGL + * when GR_GL_CHECK_ERROR is 1. Defaults to 1. + * + */ + +#if !defined(GR_GL_LOG_CALLS) + #ifdef SK_DEBUG + #define GR_GL_LOG_CALLS 1 + #else + #define GR_GL_LOG_CALLS 0 + #endif +#endif + +#if !defined(GR_GL_LOG_CALLS_START) + #define GR_GL_LOG_CALLS_START 0 +#endif + +#if !defined(GR_GL_CHECK_ERROR) + #ifdef SK_DEBUG + #define GR_GL_CHECK_ERROR 1 + #else + #define GR_GL_CHECK_ERROR 0 + #endif +#endif + +#if !defined(GR_GL_CHECK_ERROR_START) + #define GR_GL_CHECK_ERROR_START 1 +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLConfig_chrome.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLConfig_chrome.h new file mode 100644 index 00000000000000..40127d17048c82 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLConfig_chrome.h @@ -0,0 +1,14 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef GrGLConfig_chrome_DEFINED +#define GrGLConfig_chrome_DEFINED + +// glGetError() forces a sync with gpu process on chrome +#define GR_GL_CHECK_ERROR_START 0 + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLExtensions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLExtensions.h new file mode 100644 index 00000000000000..0ae85f07a0349d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLExtensions.h @@ -0,0 +1,78 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLExtensions_DEFINED +#define GrGLExtensions_DEFINED + +#include "include/core/SkString.h" +#include "include/gpu/gl/GrGLFunctions.h" +#include "include/private/base/SkTArray.h" + +#include + +struct GrGLInterface; +class SkJSONWriter; + +/** + * This helper queries the current GL context for its extensions, remembers them, and can be + * queried. It supports both glGetString- and glGetStringi-style extension string APIs and will + * use the latter if it is available. It also will query for EGL extensions if a eglQueryString + * implementation is provided. + */ +class SK_API GrGLExtensions { +public: + GrGLExtensions() {} + + GrGLExtensions(const GrGLExtensions&); + + GrGLExtensions& operator=(const GrGLExtensions&); + + void swap(GrGLExtensions* that) { + using std::swap; + swap(fStrings, that->fStrings); + swap(fInitialized, that->fInitialized); + } + + /** + * We sometimes need to use this class without having yet created a GrGLInterface. This version + * of init expects that getString is always non-NULL while getIntegerv and getStringi are non- + * NULL if on desktop GL with version 3.0 or higher. Otherwise it will fail. + */ + bool init(GrGLStandard standard, + GrGLFunction getString, + GrGLFunction getStringi, + GrGLFunction getIntegerv, + GrGLFunction queryString = nullptr, + GrEGLDisplay eglDisplay = nullptr); + + bool isInitialized() const { return fInitialized; } + + /** + * Queries whether an extension is present. This will fail if init() has not been called. + */ + bool has(const char[]) const; + + /** + * Removes an extension if present. Returns true if the extension was present before the call. + */ + bool remove(const char[]); + + /** + * Adds an extension to list + */ + void add(const char[]); + + void reset() { fStrings.clear(); } + + void dumpJSON(SkJSONWriter*) const; + +private: + bool fInitialized = false; + skia_private::TArray fStrings; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLFunctions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLFunctions.h new file mode 100644 index 00000000000000..4e488abcad4320 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLFunctions.h @@ -0,0 +1,307 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLFunctions_DEFINED +#define GrGLFunctions_DEFINED + +#include +#include "include/gpu/gl/GrGLTypes.h" +#include "include/private/base/SkTLogic.h" + + +extern "C" { + +/////////////////////////////////////////////////////////////////////////////// + +using GrGLActiveTextureFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum texture); +using GrGLAttachShaderFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint shader); +using GrGLBeginQueryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint id); +using GrGLBindAttribLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint index, const char* name); +using GrGLBindBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint buffer); +using GrGLBindFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint framebuffer); +using GrGLBindRenderbufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint renderbuffer); +using GrGLBindTextureFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint texture); +using GrGLBindFragDataLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint colorNumber, const GrGLchar* name); +using GrGLBindFragDataLocationIndexedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar* name); +using GrGLBindSamplerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint unit, GrGLuint sampler); +using GrGLBindVertexArrayFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint array); +using GrGLBlendBarrierFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLBlendColorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha); +using GrGLBlendEquationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLBlendFuncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum sfactor, GrGLenum dfactor); +using GrGLBlitFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint srcX0, GrGLint srcY0, GrGLint srcX1, GrGLint srcY1, GrGLint dstX0, GrGLint dstY0, GrGLint dstX1, GrGLint dstY1, GrGLbitfield mask, GrGLenum filter); +using GrGLBufferDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage); +using GrGLBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr size, const GrGLvoid* data); +using GrGLCheckFramebufferStatusFn = GrGLenum GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLClearFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLbitfield mask); +using GrGLClearColorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha); +using GrGLClearStencilFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint s); +using GrGLClearTexImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level, GrGLenum format, GrGLenum type, const GrGLvoid* data); +using GrGLClearTexSubImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint zoffset, GrGLsizei width, GrGLsizei height, GrGLsizei depth, GrGLenum format, GrGLenum type, const GrGLvoid* data); +using GrGLColorMaskFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha); +using GrGLCompileShaderFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader); +using GrGLCompressedTexImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLenum internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLsizei imageSize, const GrGLvoid* data); +using GrGLCompressedTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLsizei imageSize, const GrGLvoid* data); +using GrGLCopyBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum readTargt, GrGLenum writeTarget, GrGLintptr readOffset, GrGLintptr writeOffset, GrGLsizeiptr size); +using GrGLCopyTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +using GrGLCreateProgramFn = GrGLuint GR_GL_FUNCTION_TYPE(); +using GrGLCreateShaderFn = GrGLuint GR_GL_FUNCTION_TYPE(GrGLenum type); +using GrGLCullFaceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLDeleteBuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* buffers); +using GrGLDeleteFencesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* fences); +using GrGLDeleteFramebuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* framebuffers); +using GrGLDeleteProgramFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program); +using GrGLDeleteQueriesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* ids); +using GrGLDeleteRenderbuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* renderbuffers); +using GrGLDeleteSamplersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei count, const GrGLuint* samplers); +using GrGLDeleteShaderFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader); +using GrGLDeleteTexturesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* textures); +using GrGLDeleteVertexArraysFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* arrays); +using GrGLDepthMaskFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLboolean flag); +using GrGLDisableFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum cap); +using GrGLDisableVertexAttribArrayFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint index); +using GrGLDrawArraysFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLint first, GrGLsizei count); +using GrGLDrawArraysInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLint first, GrGLsizei count, GrGLsizei primcount); +using GrGLDrawArraysIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, const GrGLvoid* indirect); +using GrGLDrawBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLDrawBuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLenum* bufs); +using GrGLDrawElementsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); +using GrGLDrawElementsInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices, GrGLsizei primcount); +using GrGLDrawElementsIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLenum type, const GrGLvoid* indirect); +using GrGLDrawRangeElementsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLuint start, GrGLuint end, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); +using GrGLEnableFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum cap); +using GrGLEnableVertexAttribArrayFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint index); +using GrGLEndQueryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLFinishFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLFinishFenceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint fence); +using GrGLFlushFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLFlushMappedBufferRangeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length); +using GrGLFramebufferRenderbufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer); +using GrGLFramebufferTexture2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level); +using GrGLFramebufferTexture2DMultisampleFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level, GrGLsizei samples); +using GrGLFrontFaceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLGenBuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* buffers); +using GrGLGenFencesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* fences); +using GrGLGenFramebuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* framebuffers); +using GrGLGenerateMipmapFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLGenQueriesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* ids); +using GrGLGenRenderbuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* renderbuffers); +using GrGLGenSamplersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei count, GrGLuint* samplers); +using GrGLGenTexturesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* textures); +using GrGLGenVertexArraysFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* arrays); +using GrGLGetBufferParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLint* params); +using GrGLGetErrorFn = GrGLenum GR_GL_FUNCTION_TYPE(); +using GrGLGetFramebufferAttachmentParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params); +using GrGLGetFloatvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLfloat* params); +using GrGLGetIntegervFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint* params); +using GrGLGetMultisamplefvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLuint index, GrGLfloat* val); +using GrGLGetProgramBinaryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, GrGLenum* binaryFormat, void* binary); +using GrGLGetProgramInfoLogFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog); +using GrGLGetProgramivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum pname, GrGLint* params); +using GrGLGetQueryivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum GLtarget, GrGLenum pname, GrGLint* params); +using GrGLGetQueryObjecti64vFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLint64* params); +using GrGLGetQueryObjectivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLint* params); +using GrGLGetQueryObjectui64vFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLuint64* params); +using GrGLGetQueryObjectuivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLuint* params); +using GrGLGetRenderbufferParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLint* params); +using GrGLGetShaderInfoLogFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length, char* infolog); +using GrGLGetShaderivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLenum pname, GrGLint* params); +using GrGLGetShaderPrecisionFormatFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum shadertype, GrGLenum precisiontype, GrGLint* range, GrGLint* precision); +using GrGLGetStringFn = const GrGLubyte* GR_GL_FUNCTION_TYPE(GrGLenum name); +using GrGLGetStringiFn = const GrGLubyte* GR_GL_FUNCTION_TYPE(GrGLenum name, GrGLuint index); +using GrGLGetTexLevelParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLenum pname, GrGLint* params); +using GrGLGetUniformLocationFn = GrGLint GR_GL_FUNCTION_TYPE(GrGLuint program, const char* name); +using GrGLInsertEventMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei length, const char* marker); +using GrGLInvalidateBufferDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint buffer); +using GrGLInvalidateBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length); +using GrGLInvalidateFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments); +using GrGLInvalidateSubFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments, GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +using GrGLInvalidateTexImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level); +using GrGLInvalidateTexSubImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint zoffset, GrGLsizei width, GrGLsizei height, GrGLsizei depth); +using GrGLIsTextureFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLuint texture); +using GrGLLineWidthFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLfloat width); +using GrGLLinkProgramFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program); +using GrGLMapBufferFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum access); +using GrGLMapBufferRangeFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access); +using GrGLMapBufferSubDataFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLuint target, GrGLintptr offset, GrGLsizeiptr size, GrGLenum access); +using GrGLMapTexSubImage2DFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLenum access); +using GrGLMemoryBarrierFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLbitfield barriers); +using GrGLPatchParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint value); +using GrGLPixelStoreiFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint param); +using GrGLPolygonModeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum mode); +using GrGLPopGroupMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLProgramBinaryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum binaryFormat, void* binary, GrGLsizei length); +using GrGLProgramParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum pname, GrGLint value); +using GrGLPushGroupMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei length, const char* marker); +using GrGLQueryCounterFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum target); +using GrGLReadBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum src); +using GrGLReadPixelsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels); +using GrGLRenderbufferStorageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); +using GrGLRenderbufferStorageMultisampleFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); +using GrGLResolveMultisampleFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLSamplerParameterfFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint sampler, GrGLenum pname, GrGLfloat param); +using GrGLSamplerParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint sampler, GrGLenum pname, GrGLint param); +using GrGLSamplerParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint sampler, GrGLenum pname, const GrGLint* params); +using GrGLScissorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +// GL_CHROMIUM_bind_uniform_location +using GrGLBindUniformLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLint location, const char* name); +using GrGLSetFenceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint fence, GrGLenum condition); +using GrGLShaderSourceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLsizei count, const char* const* str, const GrGLint* length); +using GrGLStencilFuncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum func, GrGLint ref, GrGLuint mask); +using GrGLStencilFuncSeparateFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum func, GrGLint ref, GrGLuint mask); +using GrGLStencilMaskFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint mask); +using GrGLStencilMaskSeparateFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLuint mask); +using GrGLStencilOpFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum fail, GrGLenum zfail, GrGLenum zpass); +using GrGLStencilOpSeparateFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass); +using GrGLTexBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLuint buffer); +using GrGLTexBufferRangeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr size); +using GrGLTexImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); +using GrGLTexParameterfFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLfloat param); +using GrGLTexParameterfvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, const GrGLfloat* params); +using GrGLTexParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLint param); +using GrGLTexParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, const GrGLint* params); +using GrGLTexStorage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); +using GrGLDiscardFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments); +using GrGLTestFenceFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLuint fence); +using GrGLTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); +using GrGLTextureBarrierFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLUniform1fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0); +using GrGLUniform1iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0); +using GrGLUniform1fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform1ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniform2fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0, GrGLfloat v1); +using GrGLUniform2iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0, GrGLint v1); +using GrGLUniform2fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform2ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniform3fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2); +using GrGLUniform3iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2); +using GrGLUniform3fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform3ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniform4fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2, GrGLfloat v3); +using GrGLUniform4iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2, GrGLint v3); +using GrGLUniform4fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform4ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniformMatrix2fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); +using GrGLUniformMatrix3fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); +using GrGLUniformMatrix4fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); +using GrGLUnmapBufferFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLUnmapBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(const GrGLvoid* mem); +using GrGLUnmapTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(const GrGLvoid* mem); +using GrGLUseProgramFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program); +using GrGLVertexAttrib1fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat value); +using GrGLVertexAttrib2fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat* values); +using GrGLVertexAttrib3fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat* values); +using GrGLVertexAttrib4fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat* values); +using GrGLVertexAttribDivisorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint index, GrGLuint divisor); +using GrGLVertexAttribIPointerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* ptr); +using GrGLVertexAttribPointerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr); +using GrGLViewportFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); + +/* GL_NV_framebuffer_mixed_samples */ +using GrGLCoverageModulationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum components); + +/* EXT_base_instance */ +using GrGLDrawArraysInstancedBaseInstanceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLint first, GrGLsizei count, GrGLsizei instancecount, GrGLuint baseinstance); +using GrGLDrawElementsInstancedBaseVertexBaseInstanceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, GrGLenum type, const void *indices, GrGLsizei instancecount, GrGLint basevertex, GrGLuint baseinstance); + +/* EXT_multi_draw_indirect */ +using GrGLMultiDrawArraysIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, const GrGLvoid* indirect, GrGLsizei drawcount, GrGLsizei stride); +using GrGLMultiDrawElementsIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLenum type, const GrGLvoid* indirect, GrGLsizei drawcount, GrGLsizei stride); + +/* ANGLE_base_vertex_base_instance */ +using GrGLMultiDrawArraysInstancedBaseInstanceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, const GrGLint* firsts, const GrGLsizei* counts, const GrGLsizei* instanceCounts, const GrGLuint* baseInstances, const GrGLsizei drawcount); +using GrGLMultiDrawElementsInstancedBaseVertexBaseInstanceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, const GrGLint* counts, GrGLenum type, const GrGLvoid* const* indices, const GrGLsizei* instanceCounts, const GrGLint* baseVertices, const GrGLuint* baseInstances, const GrGLsizei drawcount); + +/* ARB_sync */ +using GrGLFenceSyncFn = GrGLsync GR_GL_FUNCTION_TYPE(GrGLenum condition, GrGLbitfield flags); +using GrGLIsSyncFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLsync sync); +using GrGLClientWaitSyncFn = GrGLenum GR_GL_FUNCTION_TYPE(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +using GrGLWaitSyncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +using GrGLDeleteSyncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsync sync); + +/* ARB_internalformat_query */ +using GrGLGetInternalformativFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLenum pname, GrGLsizei bufSize, GrGLint* params); + +/* KHR_debug */ +using GrGLDebugMessageControlFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled); +using GrGLDebugMessageInsertFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum source, GrGLenum type, GrGLuint id, GrGLenum severity, GrGLsizei length, const GrGLchar* buf); +using GrGLDebugMessageCallbackFn = GrGLvoid GR_GL_FUNCTION_TYPE(GRGLDEBUGPROC callback, const GrGLvoid* userParam); +using GrGLGetDebugMessageLogFn = GrGLuint GR_GL_FUNCTION_TYPE(GrGLuint count, GrGLsizei bufSize, GrGLenum* sources, GrGLenum* types, GrGLuint* ids, GrGLenum* severities, GrGLsizei* lengths, GrGLchar* messageLog); +using GrGLPushDebugGroupFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum source, GrGLuint id, GrGLsizei length, const GrGLchar* message); +using GrGLPopDebugGroupFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLObjectLabelFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum identifier, GrGLuint name, GrGLsizei length, const GrGLchar* label); + +/** EXT_window_rectangles */ +using GrGLWindowRectanglesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, const GrGLint box[]); + +/** GL_QCOM_tiled_rendering */ +using GrGLStartTilingFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint x, GrGLuint y, GrGLuint width, GrGLuint height, GrGLbitfield preserveMask); +using GrGLEndTilingFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLbitfield preserveMask); + +/** EGL functions */ +using GrEGLQueryStringFn = const char* GR_GL_FUNCTION_TYPE(GrEGLDisplay dpy, GrEGLint name); +using GrEGLGetCurrentDisplayFn = GrEGLDisplay GR_GL_FUNCTION_TYPE(); +using GrEGLCreateImageFn = GrEGLImage GR_GL_FUNCTION_TYPE(GrEGLDisplay dpy, GrEGLContext ctx, GrEGLenum target, GrEGLClientBuffer buffer, const GrEGLint* attrib_list); +using GrEGLDestroyImageFn = GrEGLBoolean GR_GL_FUNCTION_TYPE(GrEGLDisplay dpy, GrEGLImage image); +} // extern "C" + +// This is a lighter-weight std::function, trying to reduce code size and compile time +// by only supporting the exact use cases we require. +template class GrGLFunction; + +template +class GrGLFunction { +public: + using Fn = R GR_GL_FUNCTION_TYPE(Args...); + // Construct empty. + GrGLFunction() = default; + GrGLFunction(std::nullptr_t) {} + + // Construct from a simple function pointer. + GrGLFunction(Fn* fn_ptr) { + static_assert(sizeof(fn_ptr) <= sizeof(fBuf), "fBuf is too small"); + if (fn_ptr) { + memcpy(fBuf, &fn_ptr, sizeof(fn_ptr)); + fCall = [](const void* buf, Args... args) { + return (*(Fn**)buf)(std::forward(args)...); + }; + } + } + + // Construct from a small closure. + template + GrGLFunction(Closure closure) : GrGLFunction() { + static_assert(sizeof(Closure) <= sizeof(fBuf), "fBuf is too small"); +#if defined(__APPLE__) // I am having serious trouble getting these to work with all STLs... + static_assert(std::is_trivially_copyable::value, ""); + static_assert(std::is_trivially_destructible::value, ""); +#endif + + memcpy(fBuf, &closure, sizeof(closure)); + fCall = [](const void* buf, Args... args) { + auto closure = (const Closure*)buf; + return (*closure)(args...); + }; + } + + R operator()(Args... args) const { + SkASSERT(fCall); + return fCall(fBuf, std::forward(args)...); + } + + explicit operator bool() const { return fCall != nullptr; } + + void reset() { fCall = nullptr; } + +private: + using Call = R(const void* buf, Args...); + Call* fCall = nullptr; + size_t fBuf[4]; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLInterface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLInterface.h new file mode 100644 index 00000000000000..64ca419b9b16a4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLInterface.h @@ -0,0 +1,340 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLInterface_DEFINED +#define GrGLInterface_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/gl/GrGLExtensions.h" +#include "include/gpu/gl/GrGLFunctions.h" + +//////////////////////////////////////////////////////////////////////////////// + +typedef void(*GrGLFuncPtr)(); +struct GrGLInterface; + + +/** + * Rather than depend on platform-specific GL headers and libraries, we require + * the client to provide a struct of GL function pointers. This struct can be + * specified per-GrContext as a parameter to GrContext::MakeGL. If no interface is + * passed to MakeGL then a default GL interface is created using GrGLMakeNativeInterface(). + * If this returns nullptr then GrContext::MakeGL() will fail. + * + * The implementation of GrGLMakeNativeInterface is platform-specific. Several + * implementations have been provided (for GLX, WGL, EGL, etc), along with an + * implementation that simply returns nullptr. Clients should select the most + * appropriate one to build. + */ +SK_API sk_sp GrGLMakeNativeInterface(); + +/** + * GrContext uses the following interface to make all calls into OpenGL. When a + * GrContext is created it is given a GrGLInterface. The interface's function + * pointers must be valid for the OpenGL context associated with the GrContext. + * On some platforms, such as Windows, function pointers for OpenGL extensions + * may vary between OpenGL contexts. So the caller must be careful to use a + * GrGLInterface initialized for the correct context. All functions that should + * be available based on the OpenGL's version and extension string must be + * non-NULL or GrContext creation will fail. This can be tested with the + * validate() method when the OpenGL context has been made current. + */ +struct SK_API GrGLInterface : public SkRefCnt { +private: + using INHERITED = SkRefCnt; + +#if GR_GL_CHECK_ERROR + // This is here to avoid having our debug code that checks for a GL error after most GL calls + // accidentally swallow an OOM that should be reported. + mutable bool fOOMed = false; + bool fSuppressErrorLogging = false; +#endif + +public: + GrGLInterface(); + + // Validates that the GrGLInterface supports its advertised standard. This means the necessary + // function pointers have been initialized for both the GL version and any advertised + // extensions. + bool validate() const; + +#if GR_GL_CHECK_ERROR + GrGLenum checkError(const char* location, const char* call) const; + bool checkAndResetOOMed() const; + void suppressErrorLogging(); +#endif + +#if GR_TEST_UTILS + GrGLInterface(const GrGLInterface& that) + : fStandard(that.fStandard) + , fExtensions(that.fExtensions) + , fFunctions(that.fFunctions) {} +#endif + + // Indicates the type of GL implementation + union { + GrGLStandard fStandard; + GrGLStandard fBindingsExported; // Legacy name, will be remove when Chromium is updated. + }; + + GrGLExtensions fExtensions; + + bool hasExtension(const char ext[]) const { return fExtensions.has(ext); } + + /** + * The function pointers are in a struct so that we can have a compiler generated assignment + * operator. + */ + struct Functions { + GrGLFunction fActiveTexture; + GrGLFunction fAttachShader; + GrGLFunction fBeginQuery; + GrGLFunction fBindAttribLocation; + GrGLFunction fBindBuffer; + GrGLFunction fBindFragDataLocation; + GrGLFunction fBindFragDataLocationIndexed; + GrGLFunction fBindFramebuffer; + GrGLFunction fBindRenderbuffer; + GrGLFunction fBindSampler; + GrGLFunction fBindTexture; + GrGLFunction fBindVertexArray; + GrGLFunction fBlendBarrier; + GrGLFunction fBlendColor; + GrGLFunction fBlendEquation; + GrGLFunction fBlendFunc; + GrGLFunction fBlitFramebuffer; + GrGLFunction fBufferData; + GrGLFunction fBufferSubData; + GrGLFunction fCheckFramebufferStatus; + GrGLFunction fClear; + GrGLFunction fClearColor; + GrGLFunction fClearStencil; + GrGLFunction fClearTexImage; + GrGLFunction fClearTexSubImage; + GrGLFunction fColorMask; + GrGLFunction fCompileShader; + GrGLFunction fCompressedTexImage2D; + GrGLFunction fCompressedTexSubImage2D; + GrGLFunction fCopyBufferSubData; + GrGLFunction fCopyTexSubImage2D; + GrGLFunction fCreateProgram; + GrGLFunction fCreateShader; + GrGLFunction fCullFace; + GrGLFunction fDeleteBuffers; + GrGLFunction fDeleteFences; + GrGLFunction fDeleteFramebuffers; + GrGLFunction fDeleteProgram; + GrGLFunction fDeleteQueries; + GrGLFunction fDeleteRenderbuffers; + GrGLFunction fDeleteSamplers; + GrGLFunction fDeleteShader; + GrGLFunction fDeleteTextures; + GrGLFunction fDeleteVertexArrays; + GrGLFunction fDepthMask; + GrGLFunction fDisable; + GrGLFunction fDisableVertexAttribArray; + GrGLFunction fDrawArrays; + GrGLFunction fDrawArraysIndirect; + GrGLFunction fDrawArraysInstanced; + GrGLFunction fDrawBuffer; + GrGLFunction fDrawBuffers; + GrGLFunction fDrawElements; + GrGLFunction fDrawElementsIndirect; + GrGLFunction fDrawElementsInstanced; + GrGLFunction fDrawRangeElements; + GrGLFunction fEnable; + GrGLFunction fEnableVertexAttribArray; + GrGLFunction fEndQuery; + GrGLFunction fFinish; + GrGLFunction fFinishFence; + GrGLFunction fFlush; + GrGLFunction fFlushMappedBufferRange; + GrGLFunction fFramebufferRenderbuffer; + GrGLFunction fFramebufferTexture2D; + GrGLFunction fFramebufferTexture2DMultisample; + GrGLFunction fFrontFace; + GrGLFunction fGenBuffers; + GrGLFunction fGenFences; + GrGLFunction fGenFramebuffers; + GrGLFunction fGenerateMipmap; + GrGLFunction fGenQueries; + GrGLFunction fGenRenderbuffers; + GrGLFunction fGenSamplers; + GrGLFunction fGenTextures; + GrGLFunction fGenVertexArrays; + GrGLFunction fGetBufferParameteriv; + GrGLFunction fGetError; + GrGLFunction fGetFramebufferAttachmentParameteriv; + GrGLFunction fGetFloatv; + GrGLFunction fGetIntegerv; + GrGLFunction fGetMultisamplefv; + GrGLFunction fGetProgramBinary; + GrGLFunction fGetProgramInfoLog; + GrGLFunction fGetProgramiv; + GrGLFunction fGetQueryObjecti64v; + GrGLFunction fGetQueryObjectiv; + GrGLFunction fGetQueryObjectui64v; + GrGLFunction fGetQueryObjectuiv; + GrGLFunction fGetQueryiv; + GrGLFunction fGetRenderbufferParameteriv; + GrGLFunction fGetShaderInfoLog; + GrGLFunction fGetShaderiv; + GrGLFunction fGetShaderPrecisionFormat; + GrGLFunction fGetString; + GrGLFunction fGetStringi; + GrGLFunction fGetTexLevelParameteriv; + GrGLFunction fGetUniformLocation; + GrGLFunction fInsertEventMarker; + GrGLFunction fInvalidateBufferData; + GrGLFunction fInvalidateBufferSubData; + GrGLFunction fInvalidateFramebuffer; + GrGLFunction fInvalidateSubFramebuffer; + GrGLFunction fInvalidateTexImage; + GrGLFunction fInvalidateTexSubImage; + GrGLFunction fIsTexture; + GrGLFunction fLineWidth; + GrGLFunction fLinkProgram; + GrGLFunction fProgramBinary; + GrGLFunction fProgramParameteri; + GrGLFunction fMapBuffer; + GrGLFunction fMapBufferRange; + GrGLFunction fMapBufferSubData; + GrGLFunction fMapTexSubImage2D; + GrGLFunction fMemoryBarrier; + GrGLFunction fDrawArraysInstancedBaseInstance; + GrGLFunction fDrawElementsInstancedBaseVertexBaseInstance; + GrGLFunction fMultiDrawArraysIndirect; + GrGLFunction fMultiDrawElementsIndirect; + GrGLFunction fMultiDrawArraysInstancedBaseInstance; + GrGLFunction fMultiDrawElementsInstancedBaseVertexBaseInstance; + GrGLFunction fPatchParameteri; + GrGLFunction fPixelStorei; + GrGLFunction fPolygonMode; + GrGLFunction fPopGroupMarker; + GrGLFunction fPushGroupMarker; + GrGLFunction fQueryCounter; + GrGLFunction fReadBuffer; + GrGLFunction fReadPixels; + GrGLFunction fRenderbufferStorage; + + // On OpenGL ES there are multiple incompatible extensions that add support for MSAA + // and ES3 adds MSAA support to the standard. On an ES3 driver we may still use the + // older extensions for performance reasons or due to ES3 driver bugs. We want the function + // that creates the GrGLInterface to provide all available functions and internally + // we will select among them. They all have a method called glRenderbufferStorageMultisample*. + // So we have separate function pointers for GL_IMG/EXT_multisampled_to_texture, + // GL_CHROMIUM/ANGLE_framebuffer_multisample/ES3, and GL_APPLE_framebuffer_multisample + // variations. + // + // If a driver supports multiple GL_ARB_framebuffer_multisample-style extensions then we will + // assume the function pointers for the standard (or equivalent GL_ARB) version have + // been preferred over GL_EXT, GL_CHROMIUM, or GL_ANGLE variations that have reduced + // functionality. + + // GL_EXT_multisampled_render_to_texture (preferred) or GL_IMG_multisampled_render_to_texture + GrGLFunction fRenderbufferStorageMultisampleES2EXT; + // GL_APPLE_framebuffer_multisample + GrGLFunction fRenderbufferStorageMultisampleES2APPLE; + + // This is used to store the pointer for GL_ARB/EXT/ANGLE/CHROMIUM_framebuffer_multisample or + // the standard function in ES3+ or GL 3.0+. + GrGLFunction fRenderbufferStorageMultisample; + + // Pointer to BindUniformLocationCHROMIUM from the GL_CHROMIUM_bind_uniform_location extension. + GrGLFunction fBindUniformLocation; + + GrGLFunction fResolveMultisampleFramebuffer; + GrGLFunction fSamplerParameterf; + GrGLFunction fSamplerParameteri; + GrGLFunction fSamplerParameteriv; + GrGLFunction fScissor; + GrGLFunction fSetFence; + GrGLFunction fShaderSource; + GrGLFunction fStencilFunc; + GrGLFunction fStencilFuncSeparate; + GrGLFunction fStencilMask; + GrGLFunction fStencilMaskSeparate; + GrGLFunction fStencilOp; + GrGLFunction fStencilOpSeparate; + GrGLFunction fTestFence; + GrGLFunction fTexBuffer; + GrGLFunction fTexBufferRange; + GrGLFunction fTexImage2D; + GrGLFunction fTexParameterf; + GrGLFunction fTexParameterfv; + GrGLFunction fTexParameteri; + GrGLFunction fTexParameteriv; + GrGLFunction fTexSubImage2D; + GrGLFunction fTexStorage2D; + GrGLFunction fTextureBarrier; + GrGLFunction fDiscardFramebuffer; + GrGLFunction fUniform1f; + GrGLFunction fUniform1i; + GrGLFunction fUniform1fv; + GrGLFunction fUniform1iv; + GrGLFunction fUniform2f; + GrGLFunction fUniform2i; + GrGLFunction fUniform2fv; + GrGLFunction fUniform2iv; + GrGLFunction fUniform3f; + GrGLFunction fUniform3i; + GrGLFunction fUniform3fv; + GrGLFunction fUniform3iv; + GrGLFunction fUniform4f; + GrGLFunction fUniform4i; + GrGLFunction fUniform4fv; + GrGLFunction fUniform4iv; + GrGLFunction fUniformMatrix2fv; + GrGLFunction fUniformMatrix3fv; + GrGLFunction fUniformMatrix4fv; + GrGLFunction fUnmapBuffer; + GrGLFunction fUnmapBufferSubData; + GrGLFunction fUnmapTexSubImage2D; + GrGLFunction fUseProgram; + GrGLFunction fVertexAttrib1f; + GrGLFunction fVertexAttrib2fv; + GrGLFunction fVertexAttrib3fv; + GrGLFunction fVertexAttrib4fv; + GrGLFunction fVertexAttribDivisor; + GrGLFunction fVertexAttribIPointer; + GrGLFunction fVertexAttribPointer; + GrGLFunction fViewport; + + /* ARB_sync */ + GrGLFunction fFenceSync; + GrGLFunction fIsSync; + GrGLFunction fClientWaitSync; + GrGLFunction fWaitSync; + GrGLFunction fDeleteSync; + + /* ARB_internalforamt_query */ + GrGLFunction fGetInternalformativ; + + /* KHR_debug */ + GrGLFunction fDebugMessageControl; + GrGLFunction fDebugMessageInsert; + GrGLFunction fDebugMessageCallback; + GrGLFunction fGetDebugMessageLog; + GrGLFunction fPushDebugGroup; + GrGLFunction fPopDebugGroup; + GrGLFunction fObjectLabel; + + /* EXT_window_rectangles */ + GrGLFunction fWindowRectangles; + + /* GL_QCOM_tiled_rendering */ + GrGLFunction fStartTiling; + GrGLFunction fEndTiling; + } fFunctions; + +#if GR_TEST_UTILS + // This exists for internal testing. + virtual void abandon() const; +#endif +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLTypes.h new file mode 100644 index 00000000000000..3af4802eaacc26 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/GrGLTypes.h @@ -0,0 +1,208 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLTypes_DEFINED +#define GrGLTypes_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/GpuTypes.h" +#include "include/gpu/gl/GrGLConfig.h" + +/** + * Classifies GL contexts by which standard they implement (currently as OpenGL vs. OpenGL ES). + */ +enum GrGLStandard { + kNone_GrGLStandard, + kGL_GrGLStandard, + kGLES_GrGLStandard, + kWebGL_GrGLStandard, +}; +static const int kGrGLStandardCnt = 4; + +// The following allow certain interfaces to be turned off at compile time +// (for example, to lower code size). +#if SK_ASSUME_GL_ES + #define GR_IS_GR_GL(standard) false + #define GR_IS_GR_GL_ES(standard) true + #define GR_IS_GR_WEBGL(standard) false + #define SK_DISABLE_GL_INTERFACE 1 + #define SK_DISABLE_WEBGL_INTERFACE 1 +#elif SK_ASSUME_GL + #define GR_IS_GR_GL(standard) true + #define GR_IS_GR_GL_ES(standard) false + #define GR_IS_GR_WEBGL(standard) false + #define SK_DISABLE_GL_ES_INTERFACE 1 + #define SK_DISABLE_WEBGL_INTERFACE 1 +#elif SK_ASSUME_WEBGL + #define GR_IS_GR_GL(standard) false + #define GR_IS_GR_GL_ES(standard) false + #define GR_IS_GR_WEBGL(standard) true + #define SK_DISABLE_GL_ES_INTERFACE 1 + #define SK_DISABLE_GL_INTERFACE 1 +#else + #define GR_IS_GR_GL(standard) (kGL_GrGLStandard == standard) + #define GR_IS_GR_GL_ES(standard) (kGLES_GrGLStandard == standard) + #define GR_IS_GR_WEBGL(standard) (kWebGL_GrGLStandard == standard) +#endif + +/////////////////////////////////////////////////////////////////////////////// + +/** + * The supported GL formats represented as an enum. Actual support by GrContext depends on GL + * context version and extensions. + */ +enum class GrGLFormat { + kUnknown, + + kRGBA8, + kR8, + kALPHA8, + kLUMINANCE8, + kLUMINANCE8_ALPHA8, + kBGRA8, + kRGB565, + kRGBA16F, + kR16F, + kRGB8, + kRGBX8, + kRG8, + kRGB10_A2, + kRGBA4, + kSRGB8_ALPHA8, + kCOMPRESSED_ETC1_RGB8, + kCOMPRESSED_RGB8_ETC2, + kCOMPRESSED_RGB8_BC1, + kCOMPRESSED_RGBA8_BC1, + kR16, + kRG16, + kRGBA16, + kRG16F, + kLUMINANCE16F, + + kLastColorFormat = kLUMINANCE16F, + + // Depth/Stencil formats + kSTENCIL_INDEX8, + kSTENCIL_INDEX16, + kDEPTH24_STENCIL8, + + kLast = kDEPTH24_STENCIL8 +}; + +/////////////////////////////////////////////////////////////////////////////// +/** + * Declares typedefs for all the GL functions used in GrGLInterface + */ + +typedef unsigned int GrGLenum; +typedef unsigned char GrGLboolean; +typedef unsigned int GrGLbitfield; +typedef signed char GrGLbyte; +typedef char GrGLchar; +typedef short GrGLshort; +typedef int GrGLint; +typedef int GrGLsizei; +typedef int64_t GrGLint64; +typedef unsigned char GrGLubyte; +typedef unsigned short GrGLushort; +typedef unsigned int GrGLuint; +typedef uint64_t GrGLuint64; +typedef unsigned short int GrGLhalf; +typedef float GrGLfloat; +typedef float GrGLclampf; +typedef double GrGLdouble; +typedef double GrGLclampd; +typedef void GrGLvoid; +#ifdef _WIN64 +typedef signed long long int GrGLintptr; +typedef signed long long int GrGLsizeiptr; +#else +typedef signed long int GrGLintptr; +typedef signed long int GrGLsizeiptr; +#endif +typedef void* GrGLeglImage; +typedef struct __GLsync* GrGLsync; + +struct GrGLDrawArraysIndirectCommand { + GrGLuint fCount; + GrGLuint fInstanceCount; + GrGLuint fFirst; + GrGLuint fBaseInstance; // Requires EXT_base_instance on ES. +}; + +// static_asserts must have messages in this file because its included in C++14 client code. +static_assert(16 == sizeof(GrGLDrawArraysIndirectCommand), ""); + +struct GrGLDrawElementsIndirectCommand { + GrGLuint fCount; + GrGLuint fInstanceCount; + GrGLuint fFirstIndex; + GrGLuint fBaseVertex; + GrGLuint fBaseInstance; // Requires EXT_base_instance on ES. +}; + +static_assert(20 == sizeof(GrGLDrawElementsIndirectCommand), ""); + +/** + * KHR_debug + */ +typedef void (GR_GL_FUNCTION_TYPE* GRGLDEBUGPROC)(GrGLenum source, + GrGLenum type, + GrGLuint id, + GrGLenum severity, + GrGLsizei length, + const GrGLchar* message, + const void* userParam); + +/** + * EGL types. + */ +typedef void* GrEGLImage; +typedef void* GrEGLDisplay; +typedef void* GrEGLContext; +typedef void* GrEGLClientBuffer; +typedef unsigned int GrEGLenum; +typedef int32_t GrEGLint; +typedef unsigned int GrEGLBoolean; + +/////////////////////////////////////////////////////////////////////////////// +/** + * Types for interacting with GL resources created externally to Skia. GrBackendObjects for GL + * textures are really const GrGLTexture*. The fFormat here should be a sized, internal format + * for the texture. We will try to use the sized format if the GL Context supports it, otherwise + * we will internally fall back to using the base internal formats. + */ +struct GrGLTextureInfo { + GrGLenum fTarget; + GrGLuint fID; + GrGLenum fFormat = 0; + + bool operator==(const GrGLTextureInfo& that) const { + return fTarget == that.fTarget && fID == that.fID && fFormat == that.fFormat; + } +}; + +struct GrGLFramebufferInfo { + GrGLuint fFBOID; + GrGLenum fFormat = 0; + + bool operator==(const GrGLFramebufferInfo& that) const { + return fFBOID == that.fFBOID && fFormat == that.fFormat; + } +}; + +struct GrGLSurfaceInfo { + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + GrGLenum fTarget = 0; + GrGLenum fFormat = 0; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/egl/GrGLMakeEGLInterface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/egl/GrGLMakeEGLInterface.h new file mode 100644 index 00000000000000..a3eb420b040a86 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/egl/GrGLMakeEGLInterface.h @@ -0,0 +1,14 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/gpu/GrTypes.h" + +#include "include/core/SkRefCnt.h" + +struct GrGLInterface; + +sk_sp GrGLMakeEGLInterface(); diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/glx/GrGLMakeGLXInterface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/glx/GrGLMakeGLXInterface.h new file mode 100644 index 00000000000000..b49cde4589aead --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/gl/glx/GrGLMakeGLXInterface.h @@ -0,0 +1,14 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/gpu/GrTypes.h" + +#include "include/core/SkRefCnt.h" + +struct GrGLInterface; + +sk_sp GrGLMakeGLXInterface(); diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/BackendTexture.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/BackendTexture.h new file mode 100644 index 00000000000000..82a662ab13fdfe --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/BackendTexture.h @@ -0,0 +1,140 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_BackendTexture_DEFINED +#define skgpu_graphite_BackendTexture_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/gpu/graphite/TextureInfo.h" + +#ifdef SK_DAWN +#include "include/gpu/graphite/dawn/DawnTypes.h" +#endif + +#ifdef SK_METAL +#include "include/gpu/graphite/mtl/MtlGraphiteTypes.h" +#endif + +#ifdef SK_VULKAN +#include "include/private/gpu/vk/SkiaVulkan.h" +#endif + +namespace skgpu { +class MutableTextureState; +class MutableTextureStateRef; +} + +namespace skgpu::graphite { + +class SK_API BackendTexture { +public: + BackendTexture(); +#ifdef SK_DAWN + // Create a BackendTexture from a WGPUTexture. Texture info will be + // queried from the texture. Comparing to WGPUTextureView, + // SkImage::readPixels(), SkSurface::readPixels() and + // SkSurface::writePixels() are implemented by direct buffer copy. They + // should be more efficient. For WGPUTextureView, those methods will use + // create an intermediate WGPUTexture, and use it to transfer pixels. + // Note: + // - for better performance, using WGPUTexture IS RECOMMENDED. + // - The BackendTexture will not call retain or release on the passed in + // WGPUTexture. Thus the client must keep the WGPUTexture valid until + // they are no longer using the BackendTexture. + BackendTexture(WGPUTexture texture); + // Create a BackendTexture from a WGPUTextureView. Texture dimensions and + // info have to be provided. + // Note: + // - this method is for importing WGPUTextureView from wgpu::SwapChain only. + // - The BackendTexture will not call retain or release on the passed in + // WGPUTextureView. Thus the client must keep the WGPUTextureView valid + // until they are no longer using the BackendTexture. + BackendTexture(SkISize dimensions, + const DawnTextureInfo& info, + WGPUTextureView textureView); +#endif +#ifdef SK_METAL + // The BackendTexture will not call retain or release on the passed in MtlHandle. Thus the + // client must keep the MtlHandle valid until they are no longer using the BackendTexture. + BackendTexture(SkISize dimensions, MtlHandle mtlTexture); +#endif + +#ifdef SK_VULKAN + BackendTexture(SkISize dimensions, + const VulkanTextureInfo&, + VkImageLayout, + uint32_t queueFamilyIndex, + VkImage); +#endif + + BackendTexture(const BackendTexture&); + + ~BackendTexture(); + + BackendTexture& operator=(const BackendTexture&); + + bool operator==(const BackendTexture&) const; + bool operator!=(const BackendTexture& that) const { return !(*this == that); } + + bool isValid() const { return fInfo.isValid(); } + BackendApi backend() const { return fInfo.backend(); } + + SkISize dimensions() const { return fDimensions; } + + const TextureInfo& info() const { return fInfo; } + + // If the client changes any of the mutable backend of the GrBackendTexture they should call + // this function to inform Skia that those values have changed. The backend API specific state + // that can be set from this function are: + // + // Vulkan: VkImageLayout and QueueFamilyIndex + void setMutableState(const skgpu::MutableTextureState&); + +#ifdef SK_DAWN + WGPUTexture getDawnTexturePtr() const; + WGPUTextureView getDawnTextureViewPtr() const; +#endif +#ifdef SK_METAL + MtlHandle getMtlTexture() const; +#endif + +#ifdef SK_VULKAN + VkImage getVkImage() const; + VkImageLayout getVkImageLayout() const; + uint32_t getVkQueueFamilyIndex() const; +#endif + +private: + sk_sp mutableState() const; + + SkISize fDimensions; + TextureInfo fInfo; + + sk_sp fMutableState; + + union { +#ifdef SK_DAWN + struct { + WGPUTexture fDawnTexture; + WGPUTextureView fDawnTextureView; + }; +#endif +#ifdef SK_METAL + MtlHandle fMtlTexture; +#endif +#ifdef SK_VULKAN + VkImage fVkImage; +#endif + }; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_BackendTexture_DEFINED + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Context.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Context.h new file mode 100644 index 00000000000000..0fb6eee418687e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Context.h @@ -0,0 +1,169 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_Context_DEFINED +#define skgpu_graphite_Context_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkShader.h" +#include "include/gpu/graphite/ContextOptions.h" +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/gpu/graphite/Recorder.h" +#include "include/private/base/SingleOwner.h" + +#include +#include + +class SkRuntimeEffect; + +namespace skgpu::graphite { + +class BackendTexture; +class Buffer; +class ClientMappedBufferManager; +class Context; +class ContextPriv; +class GlobalCache; +class PaintOptions; +class PlotUploadTracker; +class QueueManager; +class Recording; +class ResourceProvider; +class SharedContext; +class TextureProxy; + +class SK_API Context final { +public: + Context(const Context&) = delete; + Context(Context&&) = delete; + Context& operator=(const Context&) = delete; + Context& operator=(Context&&) = delete; + + ~Context(); + + BackendApi backend() const; + + std::unique_ptr makeRecorder(const RecorderOptions& = {}); + + bool insertRecording(const InsertRecordingInfo&); + bool submit(SyncToCpu = SyncToCpu::kNo); + + void asyncReadPixels(const SkImage* image, + const SkColorInfo& dstColorInfo, + const SkIRect& srcRect, + SkImage::ReadPixelsCallback callback, + SkImage::ReadPixelsContext context); + + void asyncReadPixels(const SkSurface* surface, + const SkColorInfo& dstColorInfo, + const SkIRect& srcRect, + SkImage::ReadPixelsCallback callback, + SkImage::ReadPixelsContext context); + + /** + * Checks whether any asynchronous work is complete and if so calls related callbacks. + */ + void checkAsyncWorkCompletion(); + + /** + * Called to delete the passed in BackendTexture. This should only be called if the + * BackendTexture was created by calling Recorder::createBackendTexture on a Recorder created + * from this Context. If the BackendTexture is not valid or does not match the BackendApi of the + * Context then nothing happens. + * + * Otherwise this will delete/release the backend object that is wrapped in the BackendTexture. + * The BackendTexture will be reset to an invalid state and should not be used again. + */ + void deleteBackendTexture(BackendTexture&); + + // Provides access to functions that aren't part of the public API. + ContextPriv priv(); + const ContextPriv priv() const; // NOLINT(readability-const-return-type) + + class ContextID { + public: + static Context::ContextID Next(); + + ContextID() : fID(SK_InvalidUniqueID) {} + + bool operator==(const ContextID& that) const { return fID == that.fID; } + bool operator!=(const ContextID& that) const { return !(*this == that); } + + void makeInvalid() { fID = SK_InvalidUniqueID; } + bool isValid() const { return fID != SK_InvalidUniqueID; } + + private: + constexpr ContextID(uint32_t id) : fID(id) {} + uint32_t fID; + }; + + ContextID contextID() const { return fContextID; } + +protected: + Context(sk_sp, std::unique_ptr, const ContextOptions&); + +private: + friend class ContextPriv; + friend class ContextCtorAccessor; + + SingleOwner* singleOwner() const { return &fSingleOwner; } + + // Must be called in Make() to handle one-time GPU setup operations that can possibly fail and + // require Context::Make() to return a nullptr. + bool finishInitialization(); + + void asyncReadPixels(const TextureProxy* textureProxy, + const SkImageInfo& srcImageInfo, + const SkColorInfo& dstColorInfo, + const SkIRect& srcRect, + SkImage::ReadPixelsCallback callback, + SkImage::ReadPixelsContext context); + + // Inserts a texture to buffer transfer task, used by asyncReadPixels methods + struct PixelTransferResult { + using ConversionFn = void(void* dst, const void* mappedBuffer); + // If null then the transfer could not be performed. Otherwise this buffer will contain + // the pixel data when the transfer is complete. + sk_sp fTransferBuffer; + // RowBytes for transfer buffer data + size_t fRowBytes; + // If this is null then the transfer buffer will contain the data in the requested + // color type. Otherwise, when the transfer is done this must be called to convert + // from the transfer buffer's color type to the requested color type. + std::function fPixelConverter; + }; + PixelTransferResult transferPixels(const TextureProxy*, + const SkImageInfo& srcImageInfo, + const SkColorInfo& dstColorInfo, + const SkIRect& srcRect); + + sk_sp fSharedContext; + std::unique_ptr fResourceProvider; + std::unique_ptr fQueueManager; + std::unique_ptr fMappedBufferManager; + std::unique_ptr fPlotUploadTracker; + + // In debug builds we guard against improper thread handling. This guard is passed to the + // ResourceCache for the Context. + mutable SingleOwner fSingleOwner; + +#if GRAPHITE_TEST_UTILS + // In test builds a Recorder may track the Context that was used to create it. + bool fStoreContextRefInRecorder = false; + // If this tracking is on, to allow the client to safely delete this Context or its Recorders + // in any order we must also track the Recorders created here. + std::vector fTrackedRecorders; +#endif + + // Needed for MessageBox handling + const ContextID fContextID; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_Context_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/ContextOptions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/ContextOptions.h new file mode 100644 index 00000000000000..b9ac1b09d16198 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/ContextOptions.h @@ -0,0 +1,89 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_ContextOptions_DEFINED +#define skgpu_graphite_ContextOptions_DEFINED + +#include "include/private/base/SkAPI.h" + +namespace skgpu { class ShaderErrorHandler; } + +namespace skgpu::graphite { + +struct SK_API ContextOptions { + ContextOptions() {} + + /** + * Disables correctness workarounds that are enabled for particular GPUs, OSes, or drivers. + * This does not affect code path choices that are made for perfomance reasons nor does it + * override other ContextOption settings. + */ + bool fDisableDriverCorrectnessWorkarounds = false; + + /** + * If present, use this object to report shader compilation failures. If not, report failures + * via SkDebugf and assert. + */ + skgpu::ShaderErrorHandler* fShaderErrorHandler = nullptr; + + /** + * Will the client make sure to only ever be executing one thread that uses the Context and all + * derived classes (e.g. Recorders, Recordings, etc.) at a time. If so we can possibly make some + * objects (e.g. VulkanMemoryAllocator) not thread safe to improve single thread performance. + */ + bool fClientWillExternallySynchronizeAllThreads = false; + + /** + * The maximum size of cache textures used for Skia's Glyph cache. + */ + size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4; + + /** + * Below this threshold size in device space distance field fonts won't be used. Distance field + * fonts don't support hinting which is more important at smaller sizes. + */ + float fMinDistanceFieldFontSize = 18; + + /** + * Above this threshold size in device space glyphs are drawn as individual paths. + */ +#if defined(SK_BUILD_FOR_ANDROID) + float fGlyphsAsPathsFontSize = 384; +#elif defined(SK_BUILD_FOR_MAC) + float fGlyphsAsPathsFontSize = 256; +#else + float fGlyphsAsPathsFontSize = 324; +#endif + + /** + * Can the glyph atlas use multiple textures. If allowed, the each texture's size is bound by + * fGlypheCacheTextureMaximumBytes. + */ + bool fAllowMultipleGlyphCacheTextures = true; + bool fSupportBilerpFromGlyphAtlas = false; + +#if GRAPHITE_TEST_UTILS + /** + * Private options that are only meant for testing within Skia's tools. + */ + + /** + * Maximum width and height of internal texture atlases. + */ + int fMaxTextureAtlasSize = 2048; + + /** + * If true, will store a pointer in Recorder that points back to the Context + * that created it. Used by readPixels() and other methods that normally require a Context. + */ + bool fStoreContextRefInRecorder = false; +#endif +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_ContextOptions diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/GraphiteTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/GraphiteTypes.h new file mode 100644 index 00000000000000..231f2a5e1454dd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/GraphiteTypes.h @@ -0,0 +1,105 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_GraphiteTypes_DEFINED +#define skgpu_graphite_GraphiteTypes_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkTypes.h" +#include "include/gpu/GpuTypes.h" + +#include + +class SkSurface; + +namespace skgpu::graphite { + +class Recording; +class Task; + +using GpuFinishedContext = void*; +using GpuFinishedProc = void (*)(GpuFinishedContext finishedContext, CallbackResult); + +/** + * The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or + * when there is a failure that caused it not to be submitted. The callback will always be called + * and the caller can use the callback to know it is safe to free any resources associated with + * the Recording that they may be holding onto. If the Recording is successfully submitted to the + * GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All + * other cases where some failure occured it will be called with CallbackResult::kFailed. + * + * The fTargetSurface, if provided, is used as a target for any draws recorded onto a deferred + * canvas returned from Recorder::makeDeferredCanvas. This target surface must be provided iff + * the Recording contains any such draws. It must be Graphite-backed and its backing texture's + * TextureInfo must match the info provided to the Recorder when making the deferred canvas. + * + * fTargetTranslation is an additional translation applied to draws targeting fTargetSurface. + */ +struct InsertRecordingInfo { + Recording* fRecording = nullptr; + + SkSurface* fTargetSurface = nullptr; + SkIVector fTargetTranslation = {0, 0}; + + GpuFinishedContext fFinishedContext = nullptr; + GpuFinishedProc fFinishedProc = nullptr; +}; + +/** + * The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or + * when there is a failure that caused it not to be submitted. The callback will always be called + * and the caller can use the callback to know it is safe to free any resources associated with + * the Recording that they may be holding onto. If the Recording is successfully submitted to the + * GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All + * other cases where some failure occured it will be called with CallbackResult::kFailed. + */ +struct InsertFinishInfo { + GpuFinishedContext fFinishedContext = nullptr; + GpuFinishedProc fFinishedProc = nullptr; +}; + +/** + * Actually submit work to the GPU and track its completion + */ +enum class SyncToCpu : bool { + kYes = true, + kNo = false +}; + +/* + * For Promise Images - should the Promise Image be fulfilled every time a Recording that references + * it is inserted into the Context. + */ +enum class Volatile : bool { + kNo = false, // only fulfilled once + kYes = true // fulfilled on every insertion call +}; + +/* + * Graphite's different rendering methods each only apply to certain types of draws. This + * enum supports decision-making regarding the different renderers and what is being drawn. + */ +enum DrawTypeFlags : uint8_t { + + kNone = 0b000, + + // SkCanvas:: drawSimpleText, drawString, drawGlyphs, drawTextBlob, drawSlug + kText = 0b001, + + // SkCanvas::drawVertices + kDrawVertices = 0b010, + + // All other canvas draw calls + kShape = 0b100, + + kMostCommon = kText | kShape, + kAll = kText | kDrawVertices | kShape +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_GraphiteTypes_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/ImageProvider.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/ImageProvider.h new file mode 100644 index 00000000000000..3c071fe9ea3e74 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/ImageProvider.h @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_ImageProvider_DEFINED +#define skgpu_graphite_ImageProvider_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkRefCnt.h" + +namespace skgpu::graphite { + +class Recorder; + +/* + * This class provides a centralized location for clients to perform any caching of images + * they desire. Whenever Graphite encounters an SkImage which is not Graphite-backed + * it will call ImageProvider::findOrCreate. The client's derived version of this class should + * return a Graphite-backed version of the provided SkImage that meets the specified + * requirements. + * + * Skia requires that 'findOrCreate' return a Graphite-backed image that preserves the + * dimensions and alpha type of the original image. The bit depth of the + * individual channels can change (e.g., 4444 -> 8888 is allowed) as well as the channels - as + * long as the returned image has a superset of the original image's channels + * (e.g., 565 -> 8888 opaque is allowed). + * + * Wrt mipmapping, the returned image can have different mipmap settings than requested. If + * mipmapping was requested but not returned, the sampling level will be reduced to linear. + * If the requirements are not met by the returned image (modulo the flexibility wrt mipmapping) + * Graphite will drop the draw. + * + * Note: by default, Graphite will not perform any caching of images + * + * Threading concerns: + * If the same ImageProvider is given to multiple Recorders it is up to the + * client to handle any required thread synchronization. This is not limited to just + * restricting access to whatever map a derived class may have but extends to ensuring + * that an image created on one Recorder has had its creation work submitted before it + * is used by any work submitted by another Recording. Please note, this requirement + * (re the submission of creation work and image usage on different threads) is common to all + * graphite SkImages and isn't unique to SkImages returned by the ImageProvider. + * + * TODO(b/240996632): add documentation re shutdown order. + * TODO(b/240997067): add unit tests + */ +class SK_API ImageProvider : public SkRefCnt { +public: + // If the client's derived class already has a Graphite-backed image that has the same + // contents as 'image' and meets the requirements, then it can be returned. + // makeTextureImage can always be called to create an acceptable Graphite-backed image + // which could then be cached. + virtual sk_sp findOrCreate(Recorder* recorder, + const SkImage* image, + SkImage::RequiredImageProperties) = 0; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_ImageProvider_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Recorder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Recorder.h new file mode 100644 index 00000000000000..6e911a4e72c725 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Recorder.h @@ -0,0 +1,213 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_Recorder_DEFINED +#define skgpu_graphite_Recorder_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/gpu/graphite/Recording.h" +#include "include/private/base/SingleOwner.h" +#include "include/private/base/SkTArray.h" + +#include + +class SkCanvas; +struct SkImageInfo; +class SkPixmap; + +namespace skgpu { +class RefCntedCallback; +class TokenTracker; +} + +namespace sktext::gpu { +class StrikeCache; +class TextBlobRedrawCoordinator; +} + +namespace skgpu::graphite { + +class AtlasManager; +class BackendTexture; +class Caps; +class Context; +class Device; +class DrawBufferManager; +class GlobalCache; +class ImageProvider; +class ProxyCache; +class RecorderPriv; +class ResourceProvider; +class RuntimeEffectDictionary; +class SharedContext; +class Task; +class TaskGraph; +class TextureDataBlock; +class TextureInfo; +class UniformDataBlock; +class UploadBufferManager; + +template class PipelineDataCache; +using UniformDataCache = PipelineDataCache; +using TextureDataCache = PipelineDataCache; + +struct SK_API RecorderOptions final { + RecorderOptions(); + RecorderOptions(const RecorderOptions&); + ~RecorderOptions(); + + sk_sp fImageProvider; +}; + +class SK_API Recorder final { +public: + Recorder(const Recorder&) = delete; + Recorder(Recorder&&) = delete; + Recorder& operator=(const Recorder&) = delete; + Recorder& operator=(Recorder&&) = delete; + + ~Recorder(); + + std::unique_ptr snap(); + + ImageProvider* clientImageProvider() { return fClientImageProvider.get(); } + const ImageProvider* clientImageProvider() const { return fClientImageProvider.get(); } + + /** + * Creates a new backend gpu texture matching the dimensions and TextureInfo. If an invalid + * TextureInfo or a TextureInfo Skia can't support is passed in, this will return an invalid + * BackendTexture. Thus the client should check isValid on the returned BackendTexture to know + * if it succeeded or not. + * + * If this does return a valid BackendTexture, the caller is required to use + * Recorder::deleteBackendTexture or Context::deleteBackendTexture to delete the texture. It is + * safe to use the Context that created this Recorder or any other Recorder created from the + * same Context to call deleteBackendTexture. + */ + BackendTexture createBackendTexture(SkISize dimensions, const TextureInfo&); + + /** + * If possible, updates a backend texture with the provided pixmap data. The client + * should check the return value to see if the update was successful. The client is required + * to insert a Recording into the Context and call `submit` to send the upload work to the gpu. + * The backend texture must be compatible with the provided pixmap(s). Compatible, in this case, + * means that the backend format is compatible with the base pixmap's colortype. The src data + * can be deleted when this call returns. + * If the backend texture is mip mapped, the data for all the mipmap levels must be provided. + * In the mipmapped case all the colortypes of the provided pixmaps must be the same. + * Additionally, all the miplevels must be sized correctly (please see + * SkMipmap::ComputeLevelSize and ComputeLevelCount). + * Note: the pixmap's alphatypes and colorspaces are ignored. + * For the Vulkan backend after a successful update the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + bool updateBackendTexture(const BackendTexture&, + const SkPixmap srcData[], + int numLevels); + + /** + * Called to delete the passed in BackendTexture. This should only be called if the + * BackendTexture was created by calling Recorder::createBackendTexture on a Recorder that is + * associated with the same Context. If the BackendTexture is not valid or does not match the + * BackendApi of the Recorder then nothing happens. + * + * Otherwise this will delete/release the backend object that is wrapped in the BackendTexture. + * The BackendTexture will be reset to an invalid state and should not be used again. + */ + void deleteBackendTexture(BackendTexture&); + + // Adds a proc that will be moved to the Recording upon snap, subsequently attached to the + // CommandBuffer when the Recording is added, and called when that CommandBuffer is submitted + // and finishes. If the Recorder or Recording is deleted before the proc is added to the + // CommandBuffer, it will be called with result Failure. + void addFinishInfo(const InsertFinishInfo&); + + // Returns a canvas that will record to a proxy surface, which must be instantiated on replay. + // This can only be called once per Recording; subsequent calls will return null until a + // Recording is snapped. Additionally, the returned SkCanvas is only valid until the next + // Recording snap, at which point it is deleted. + SkCanvas* makeDeferredCanvas(const SkImageInfo&, const TextureInfo&); + + // Provides access to functions that aren't part of the public API. + RecorderPriv priv(); + const RecorderPriv priv() const; // NOLINT(readability-const-return-type) + +#if GRAPHITE_TEST_UTILS + bool deviceIsRegistered(Device*); +#endif + +private: + friend class Context; // For ctor + friend class Device; // For registering and deregistering Devices; + friend class RecorderPriv; // for ctor and hidden methods + + Recorder(sk_sp, const RecorderOptions&); + + SingleOwner* singleOwner() const { return &fSingleOwner; } + + BackendApi backend() const; + + // We keep track of all Devices that are connected to a Recorder. This allows the client to + // safely delete an SkSurface or a Recorder in any order. If the client deletes the Recorder + // we need to notify all Devices that the Recorder is no longer valid. If we delete the + // SkSurface/Device first we will flush all the Device's into the Recorder before deregistering + // it from the Recorder. + // + // We do not need to take a ref on the Device since the Device will flush and deregister itself + // in its dtor. There is no other need for the Recorder to know about the Device after this + // point. + // + // Note: We could probably get by with only registering Devices directly connected to + // SkSurfaces. All other one off Devices will be created in a controlled scope where the + // Recorder should still be valid by the time they need to flush their work when the Device is + // deleted. We would have to make sure we safely handle cases where a client calls saveLayer + // then either deletes the SkSurface or Recorder before calling restore. For simplicity we just + // register every device for now, but if we see extra overhead in pushing back the extra + // pointers, we can look into only registering SkSurface Devices. + void registerDevice(Device*); + void deregisterDevice(const Device*); + + sk_sp fSharedContext; + std::unique_ptr fResourceProvider; + std::unique_ptr fRuntimeEffectDict; + + std::unique_ptr fGraph; + std::unique_ptr fUniformDataCache; + std::unique_ptr fTextureDataCache; + std::unique_ptr fDrawBufferManager; + std::unique_ptr fUploadBufferManager; + std::vector fTrackedDevices; + + uint32_t fRecorderID; // Needed for MessageBox handling for text + std::unique_ptr fAtlasManager; + std::unique_ptr fTokenTracker; + std::unique_ptr fStrikeCache; + std::unique_ptr fTextBlobCache; + sk_sp fClientImageProvider; + + // In debug builds we guard against improper thread handling + // This guard is passed to the ResourceCache. + // TODO: Should we also pass this to Device, DrawContext, and similar classes? + mutable SingleOwner fSingleOwner; + + sk_sp fTargetProxyDevice; + std::unique_ptr fTargetProxyCanvas; + std::unique_ptr fTargetProxyData; + + skia_private::TArray> fFinishedProcs; + +#if GRAPHITE_TEST_UTILS + // For testing use only -- the Context used to create this Recorder + Context* fContext = nullptr; +#endif +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_Recorder_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Recording.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Recording.h new file mode 100644 index 00000000000000..4a60e5b936626e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/Recording.h @@ -0,0 +1,96 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_Recording_DEFINED +#define skgpu_graphite_Recording_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/SkChecksum.h" +#include "include/private/base/SkTArray.h" + +#include +#include +#include + +namespace skgpu { +class RefCntedCallback; +} + +namespace skgpu::graphite { + +class CommandBuffer; +class RecordingPriv; +class Resource; +class ResourceProvider; +class TaskGraph; +class Texture; +class TextureInfo; +class TextureProxy; + +class SK_API Recording final { +public: + ~Recording(); + + RecordingPriv priv(); + +#if GRAPHITE_TEST_UTILS + bool isTargetProxyInstantiated() const; +#endif + +private: + friend class Recorder; // for ctor and LazyProxyData + friend class RecordingPriv; + + // LazyProxyData is used if this recording should be replayed to a target that is provided on + // replay, and it handles the target proxy's instantiation with the provided target. + class LazyProxyData { + public: + LazyProxyData(const TextureInfo&); + + TextureProxy* lazyProxy(); + sk_sp refLazyProxy(); + + bool lazyInstantiate(ResourceProvider*, sk_sp); + + private: + sk_sp fTarget; + sk_sp fTargetProxy; + }; + + struct ProxyHash { + std::size_t operator()(const sk_sp& proxy) const { + return SkGoodHash()(proxy.get()); + } + }; + + Recording(std::unique_ptr, + std::unordered_set, ProxyHash>&& nonVolatileLazyProxies, + std::unordered_set, ProxyHash>&& volatileLazyProxies, + std::unique_ptr targetProxyData, + skia_private::TArray>&& finishedProcs); + + bool addCommands(CommandBuffer*, ResourceProvider*); + void addResourceRef(sk_sp); + + std::unique_ptr fGraph; + // We don't always take refs to all resources used by specific Tasks (e.g. a common buffer used + // for uploads). Instead we'll just hold onto one ref for those Resources outside the Tasks. + // Those refs are stored in the array here and will eventually be passed onto a CommandBuffer + // when the Recording adds its commands. + std::vector> fExtraResourceRefs; + + std::unordered_set, ProxyHash> fNonVolatileLazyProxies; + std::unordered_set, ProxyHash> fVolatileLazyProxies; + + std::unique_ptr fTargetProxyData; + + skia_private::TArray> fFinishedProcs; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_Recording_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/TextureInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/TextureInfo.h new file mode 100644 index 00000000000000..9a30839ab43e8e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/TextureInfo.h @@ -0,0 +1,162 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_TextureInfo_DEFINED +#define skgpu_graphite_TextureInfo_DEFINED + +#include "include/gpu/graphite/GraphiteTypes.h" + +#ifdef SK_DAWN +#include "include/private/gpu/graphite/DawnTypesPriv.h" +#endif + +#ifdef SK_METAL +#include "include/private/gpu/graphite/MtlGraphiteTypesPriv.h" +#endif + +#ifdef SK_VULKAN +#include "include/private/gpu/graphite/VulkanGraphiteTypesPriv.h" +#endif + +namespace skgpu::graphite { + +class SK_API TextureInfo { +public: + TextureInfo() {} +#ifdef SK_DAWN + TextureInfo(const DawnTextureInfo& dawnInfo) + : fBackend(BackendApi::kDawn) + , fValid(true) + , fSampleCount(dawnInfo.fSampleCount) + , fMipmapped(dawnInfo.fMipmapped) + , fProtected(Protected::kNo) + , fDawnSpec(dawnInfo) {} +#endif + +#ifdef SK_METAL + TextureInfo(const MtlTextureInfo& mtlInfo) + : fBackend(BackendApi::kMetal) + , fValid(true) + , fSampleCount(mtlInfo.fSampleCount) + , fMipmapped(mtlInfo.fMipmapped) + , fProtected(Protected::kNo) + , fMtlSpec(mtlInfo) {} +#endif + +#ifdef SK_VULKAN + TextureInfo(const VulkanTextureInfo& vkInfo) + : fBackend(BackendApi::kVulkan) + , fValid(true) + , fSampleCount(vkInfo.fSampleCount) + , fMipmapped(vkInfo.fMipmapped) + , fProtected(Protected::kNo) + , fVkSpec(vkInfo) { + if (vkInfo.fFlags & VK_IMAGE_CREATE_PROTECTED_BIT) { + fProtected = Protected::kYes; + } + } +#endif + + ~TextureInfo() {} + TextureInfo(const TextureInfo&) = default; + TextureInfo& operator=(const TextureInfo&); + + bool operator==(const TextureInfo&) const; + bool operator!=(const TextureInfo& that) const { return !(*this == that); } + + bool isValid() const { return fValid; } + BackendApi backend() const { return fBackend; } + + uint32_t numSamples() const { return fSampleCount; } + Mipmapped mipmapped() const { return fMipmapped; } + Protected isProtected() const { return fProtected; } + +#ifdef SK_DAWN + bool getDawnTextureInfo(DawnTextureInfo* info) const { + if (!this->isValid() || fBackend != BackendApi::kDawn) { + return false; + } + *info = DawnTextureSpecToTextureInfo(fDawnSpec, fSampleCount, fMipmapped); + return true; + } +#endif + +#ifdef SK_METAL + bool getMtlTextureInfo(MtlTextureInfo* info) const { + if (!this->isValid() || fBackend != BackendApi::kMetal) { + return false; + } + *info = MtlTextureSpecToTextureInfo(fMtlSpec, fSampleCount, fMipmapped); + return true; + } +#endif + +#ifdef SK_VULKAN + bool getVulkanTextureInfo(VulkanTextureInfo* info) const { + if (!this->isValid() || fBackend != BackendApi::kVulkan) { + return false; + } + *info = VulkanTextureSpecToTextureInfo(fVkSpec, fSampleCount, fMipmapped); + return true; + } +#endif + +private: +#ifdef SK_DAWN + friend class DawnCaps; + friend class DawnCommandBuffer; + friend class DawnGraphicsPipeline; + friend class DawnResourceProvider; + friend class DawnTexture; + const DawnTextureSpec& dawnTextureSpec() const { + SkASSERT(fValid && fBackend == BackendApi::kDawn); + return fDawnSpec; + } +#endif + +#ifdef SK_METAL + friend class MtlCaps; + friend class MtlGraphicsPipeline; + friend class MtlTexture; + const MtlTextureSpec& mtlTextureSpec() const { + SkASSERT(fValid && fBackend == BackendApi::kMetal); + return fMtlSpec; + } +#endif + +#ifdef SK_VULKAN + friend class VulkanCaps; + friend class VulkanTexture; + const VulkanTextureSpec& vulkanTextureSpec() const { + SkASSERT(fValid && fBackend == BackendApi::kVulkan); + return fVkSpec; + } +#endif + + BackendApi fBackend = BackendApi::kMock; + bool fValid = false; + + uint32_t fSampleCount = 1; + Mipmapped fMipmapped = Mipmapped::kNo; + Protected fProtected = Protected::kNo; + + union { +#ifdef SK_DAWN + DawnTextureSpec fDawnSpec; +#endif +#ifdef SK_METAL + MtlTextureSpec fMtlSpec; +#endif +#ifdef SK_VULKAN + VulkanTextureSpec fVkSpec; +#endif + }; +}; + +} // namespace skgpu::graphite + +#endif //skgpu_graphite_TextureInfo_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/YUVABackendTextures.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/YUVABackendTextures.h new file mode 100644 index 00000000000000..c3b80ae196e321 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/YUVABackendTextures.h @@ -0,0 +1,139 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_YUVABackendTextures_DEFINED +#define skgpu_graphite_YUVABackendTextures_DEFINED + +#include "include/core/SkSpan.h" +#include "include/core/SkYUVAInfo.h" +#include "include/gpu/graphite/BackendTexture.h" + +#include + +namespace skgpu::graphite { +class Recorder; + +/** + * A description of a set of BackendTextures that hold the planar data described by a SkYUVAInfo. + */ +class SK_API YUVABackendTextureInfo { +public: + static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; + + /** Default YUVABackendTextureInfo is invalid. */ + YUVABackendTextureInfo() = default; + YUVABackendTextureInfo(const YUVABackendTextureInfo&) = default; + YUVABackendTextureInfo& operator=(const YUVABackendTextureInfo&) = default; + + /** + * Initializes a YUVABackendTextureInfo to describe a set of textures that can store the + * planes indicated by the SkYUVAInfo. The texture dimensions are taken from the SkYUVAInfo's + * plane dimensions. All the described textures share a common origin. The planar image this + * describes will be mip mapped if all the textures are individually mip mapped as indicated + * by Mipmapped. This will produce an invalid result (return false from isValid()) if the + * passed formats' channels don't agree with SkYUVAInfo. + */ + YUVABackendTextureInfo(const Recorder*, + const SkYUVAInfo&, + const TextureInfo[kMaxPlanes], + Mipmapped); + + bool operator==(const YUVABackendTextureInfo&) const; + bool operator!=(const YUVABackendTextureInfo& that) const { return !(*this == that); } + + /** TextureInfo for the ith plane, or invalid if i >= numPlanes() */ + const TextureInfo& planeTextureInfo(int i) const { + SkASSERT(i >= 0); + return fPlaneTextureInfos[static_cast(i)]; + } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); } + + Mipmapped mipmapped() const { return fMipmapped; } + + /** The number of planes, 0 if this YUVABackendTextureInfo is invalid. */ + int numPlanes() const { return fYUVAInfo.numPlanes(); } + + /** + * Returns true if this has been configured with a valid SkYUVAInfo with compatible texture + * formats. + */ + bool isValid() const { return fYUVAInfo.isValid(); } + + /** + * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be + * valid if this->isValid(). + */ + SkYUVAInfo::YUVALocations toYUVALocations() const; + +private: + SkYUVAInfo fYUVAInfo; + std::array fPlaneTextureInfos; + std::array fPlaneChannelMasks; + Mipmapped fMipmapped = Mipmapped::kNo; +}; + +/** + * A set of BackendTextures that hold the planar data for an image described a SkYUVAInfo. + */ +class SK_API YUVABackendTextures { +public: + static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; + + YUVABackendTextures() = default; + YUVABackendTextures(const YUVABackendTextures&) = delete; + YUVABackendTextures& operator=(const YUVABackendTextures&) = delete; + + /** + * Initializes a YUVABackendTextures object from a set of textures that store the planes + * indicated by the SkYUVAInfo. This will produce an invalid result (return false from + * isValid()) if the passed texture formats' channels don't agree with SkYUVAInfo. + */ + YUVABackendTextures(const Recorder*, + const SkYUVAInfo&, + const BackendTexture[kMaxPlanes]); + + SkSpan planeTextures() const { + return SkSpan(fPlaneTextures); + } + + /** BackendTexture for the ith plane, or invalid if i >= numPlanes() */ + BackendTexture planeTexture(int i) const { + SkASSERT(i >= 0); + return fPlaneTextures[static_cast(i)]; + } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); } + + /** The number of planes, 0 if this YUVABackendTextureInfo is invalid. */ + int numPlanes() const { return fYUVAInfo.numPlanes(); } + + /** + * Returns true if this has been configured with a valid SkYUVAInfo with compatible texture + * formats. + */ + bool isValid() const { return fYUVAInfo.isValid(); } + + /** + * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be + * valid if this->isValid(). + */ + SkYUVAInfo::YUVALocations toYUVALocations() const; + +private: + SkYUVAInfo fYUVAInfo; + std::array fPlaneTextures; + std::array fPlaneChannelMasks; +}; + +} // End of namespace skgpu::graphite + +#endif // skgpu_graphite_YUVABackendTextures_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnBackendContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnBackendContext.h new file mode 100644 index 00000000000000..99282c4d76094a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnBackendContext.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_DawnBackendContext_DEFINED +#define skgpu_graphite_DawnBackendContext_DEFINED + +#include "webgpu/webgpu_cpp.h" + +namespace skgpu::graphite { + +// The DawnBackendContext contains all of the base Dawn objects needed by the graphite Dawn +// backend. The client will create this object and pass it into the Context::MakeDawn factory call +// when setting up Skia. +struct SK_API DawnBackendContext { + wgpu::Device fDevice; + wgpu::Queue fQueue; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_DawnBackendContext_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnTypes.h new file mode 100644 index 00000000000000..291be756306e7e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnTypes.h @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_DawnTypes_DEFINED +#define skgpu_graphite_DawnTypes_DEFINED + +#include "include/gpu/graphite/GraphiteTypes.h" +#include "webgpu/webgpu_cpp.h" + +namespace skgpu::graphite { + +struct DawnTextureInfo { + uint32_t fSampleCount = 1; + Mipmapped fMipmapped = Mipmapped::kNo; + + // wgpu::TextureDescriptor properties + wgpu::TextureFormat fFormat = wgpu::TextureFormat::Undefined; + wgpu::TextureUsage fUsage = wgpu::TextureUsage::None; + + DawnTextureInfo() = default; + DawnTextureInfo(const wgpu::Texture& texture); + DawnTextureInfo(uint32_t sampleCount, + Mipmapped mipmapped, + wgpu::TextureFormat format, + wgpu::TextureUsage usage) + : fSampleCount(sampleCount) + , fMipmapped(mipmapped) + , fFormat(format) + , fUsage(usage) {} +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_DawnTypes_DEFINED + + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnUtils.h new file mode 100644 index 00000000000000..059d128ef59d61 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/dawn/DawnUtils.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_DawnUtils_DEFINED +#define skgpu_graphite_DawnUtils_DEFINED + +#include + +#include "include/private/base/SkAPI.h" + +namespace skgpu::graphite { + +class Context; +struct ContextOptions; +struct DawnBackendContext; + +namespace ContextFactory { +SK_API std::unique_ptr MakeDawn(const DawnBackendContext&, const ContextOptions&); +} // namespace ContextFactory + +} // namespace skgpu::graphite + + +#endif // skgpu_graphite_DawnUtils_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlBackendContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlBackendContext.h new file mode 100644 index 00000000000000..9d6d0192d170d8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlBackendContext.h @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_MtlBackendContext_DEFINED +#define skgpu_graphite_MtlBackendContext_DEFINED + +#include "include/gpu/graphite/mtl/MtlGraphiteTypes.h" + +namespace skgpu::graphite { + +// The MtlBackendContext contains all of the base Metal objects needed by the graphite Metal +// backend. The client will create this object and pass it into the Context::MakeMetal factory call +// when setting up Skia. +struct SK_API MtlBackendContext { + sk_cfp fDevice; + sk_cfp fQueue; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_MtlBackendContext_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteTypes.h new file mode 100644 index 00000000000000..bc04421643db2d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteTypes.h @@ -0,0 +1,69 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_MtlGraphiteTypes_DEFINED +#define skgpu_graphite_MtlGraphiteTypes_DEFINED + +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/ports/SkCFObject.h" + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ + +#include +#include + +#if TARGET_OS_SIMULATOR +#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(13.0)) +#else // TARGET_OS_SIMULATOR +#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(8.0)) +#endif // TARGET_OS_SIMULATOR + +#endif // __APPLE__ + + +namespace skgpu::graphite { + +/** + * Declares typedefs for Metal types used in Graphite cpp code + */ +using MtlPixelFormat = unsigned int; +using MtlTextureUsage = unsigned int; +using MtlStorageMode = unsigned int; +using MtlHandle = const void*; + +struct MtlTextureInfo { + uint32_t fSampleCount = 1; + skgpu::Mipmapped fMipmapped = skgpu::Mipmapped::kNo; + + // Since we aren't in an Obj-C header we can't directly use Mtl types here. Each of these can + // cast to their mapped Mtl types list below. + MtlPixelFormat fFormat = 0; // MTLPixelFormat fFormat = MTLPixelFormatInvalid; + MtlTextureUsage fUsage = 0; // MTLTextureUsage fUsage = MTLTextureUsageUnknown; + MtlStorageMode fStorageMode = 0; // MTLStorageMode fStorageMode = MTLStorageModeShared; + bool fFramebufferOnly = false; + + MtlTextureInfo() = default; + MtlTextureInfo(MtlHandle mtlTexture); + MtlTextureInfo(uint32_t sampleCount, + skgpu::Mipmapped mipmapped, + MtlPixelFormat format, + MtlTextureUsage usage, + MtlStorageMode storageMode, + bool framebufferOnly) + : fSampleCount(sampleCount) + , fMipmapped(mipmapped) + , fFormat(format) + , fUsage(usage) + , fStorageMode(storageMode) + , fFramebufferOnly(framebufferOnly) {} +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_MtlGraphiteTypes_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteUtils.h new file mode 100644 index 00000000000000..cd7837f86c2386 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteUtils.h @@ -0,0 +1,27 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_MtlGraphiteUtils_DEFINED +#define skgpu_graphite_MtlGraphiteUtils_DEFINED + +#include + +#include "include/private/base/SkAPI.h" + +namespace skgpu::graphite { + +class Context; +struct ContextOptions; +struct MtlBackendContext; + +namespace ContextFactory { +SK_API std::unique_ptr MakeMetal(const MtlBackendContext&, const ContextOptions&); +} // namespace ContextFactory + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_MtlGraphiteUtils_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteTypes.h new file mode 100644 index 00000000000000..bd448d2ca6c1ef --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteTypes.h @@ -0,0 +1,64 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_VulkanGraphiteTypes_DEFINED +#define skgpu_graphite_VulkanGraphiteTypes_DEFINED + +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/gpu/vk/VulkanTypes.h" + +namespace skgpu::graphite { + +struct VulkanTextureInfo { + uint32_t fSampleCount = 1; + Mipmapped fMipmapped = Mipmapped::kNo; + + // VkImageCreateInfo properties + // Currently the only supported flag is VK_IMAGE_CREATE_PROTECTED_BIT. Any other flag will not + // be accepted + VkImageCreateFlags fFlags = 0; + VkFormat fFormat = VK_FORMAT_UNDEFINED; + VkImageTiling fImageTiling = VK_IMAGE_TILING_OPTIMAL; + VkImageUsageFlags fImageUsageFlags = 0; + VkSharingMode fSharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // Properties related to the image view and sampling. These are less inherent properties of the + // VkImage but describe how the VkImage should be used within Skia. + + // What aspect to use for the VkImageView. The normal, default is VK_IMAGE_ASPECT_COLOR_BIT. + // However, if the VkImage is a Ycbcr format, the client can pass a specific plan here to have + // Skia directly sample a plane. In that case the client should also pass in a VkFormat that is + // compatible with the plane as described by the Vulkan spec. + VkImageAspectFlags fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // TODO: Either Make the ycbcr conversion info shareable with Ganesh or add a version for + // Graphite. + // GrVkYcbcrConversionInfo fYcbcrConversionInfo; + + VulkanTextureInfo() = default; + VulkanTextureInfo(uint32_t sampleCount, + Mipmapped mipmapped, + VkImageCreateFlags flags, + VkFormat format, + VkImageTiling imageTiling, + VkImageUsageFlags imageUsageFlags, + VkSharingMode sharingMode, + VkImageAspectFlags aspectMask) + : fSampleCount(sampleCount) + , fMipmapped(mipmapped) + , fFlags(flags) + , fFormat(format) + , fImageTiling(imageTiling) + , fImageUsageFlags(imageUsageFlags) + , fSharingMode(sharingMode) + , fAspectMask(aspectMask) {} +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_VulkanGraphiteTypes_DEFINED + + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteUtils.h new file mode 100644 index 00000000000000..0cfa0e9bf0a40c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteUtils.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_VulkanGraphiteUtils_DEFINED +#define skgpu_graphite_VulkanGraphiteUtils_DEFINED + +#include + +#include "include/private/base/SkAPI.h" + +namespace skgpu { struct VulkanBackendContext; } + +namespace skgpu::graphite { + +class Context; +struct ContextOptions; + +namespace ContextFactory { +SK_API std::unique_ptr MakeVulkan(const VulkanBackendContext&, const ContextOptions&); +} // namespace ContextFactory + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_VulkanGraphiteUtils_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mock/GrMockTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mock/GrMockTypes.h new file mode 100644 index 00000000000000..b3e4b7b84268d7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mock/GrMockTypes.h @@ -0,0 +1,147 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrMockOptions_DEFINED +#define GrMockOptions_DEFINED + +#include "include/core/SkTextureCompressionType.h" +#include "include/gpu/GpuTypes.h" +#include "include/private/gpu/ganesh/GrTypesPriv.h" + +class GrBackendFormat; + +struct GrMockTextureInfo { + GrMockTextureInfo() + : fColorType(GrColorType::kUnknown) + , fCompressionType(SkTextureCompressionType::kNone) + , fID(0) {} + + GrMockTextureInfo(GrColorType colorType, + SkTextureCompressionType compressionType, + int id) + : fColorType(colorType) + , fCompressionType(compressionType) + , fID(id) { + SkASSERT(fID); + if (fCompressionType != SkTextureCompressionType::kNone) { + SkASSERT(colorType == GrColorType::kUnknown); + } + } + + bool operator==(const GrMockTextureInfo& that) const { + return fColorType == that.fColorType && + fCompressionType == that.fCompressionType && + fID == that.fID; + } + + GrBackendFormat getBackendFormat() const; + + SkTextureCompressionType compressionType() const { return fCompressionType; } + + GrColorType colorType() const { + SkASSERT(fCompressionType == SkTextureCompressionType::kNone); + return fColorType; + } + + int id() const { return fID; } + +private: + GrColorType fColorType; + SkTextureCompressionType fCompressionType; + int fID; +}; + +struct GrMockRenderTargetInfo { + GrMockRenderTargetInfo() + : fColorType(GrColorType::kUnknown) + , fID(0) {} + + GrMockRenderTargetInfo(GrColorType colorType, int id) + : fColorType(colorType) + , fID(id) { + SkASSERT(fID); + } + + bool operator==(const GrMockRenderTargetInfo& that) const { + return fColorType == that.fColorType && + fID == that.fID; + } + + GrBackendFormat getBackendFormat() const; + + GrColorType colorType() const { return fColorType; } + +private: + GrColorType fColorType; + int fID; +}; + +struct GrMockSurfaceInfo { + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + GrColorType fColorType = GrColorType::kUnknown; + SkTextureCompressionType fCompressionType = SkTextureCompressionType::kNone; +}; + +static constexpr int kSkTextureCompressionTypeCount = + static_cast(SkTextureCompressionType::kLast) + 1; + +/** + * A pointer to this type is used as the GrBackendContext when creating a Mock GrContext. It can be + * used to specify capability options for the mock context. If nullptr is used a default constructed + * GrMockOptions is used. + */ +struct GrMockOptions { + GrMockOptions() { + using Renderability = ConfigOptions::Renderability; + // By default RGBA_8888 and BGRA_8888 are textureable and renderable and + // A8 and RGB565 are texturable. + fConfigOptions[(int)GrColorType::kRGBA_8888].fRenderability = Renderability::kNonMSAA; + fConfigOptions[(int)GrColorType::kRGBA_8888].fTexturable = true; + fConfigOptions[(int)GrColorType::kAlpha_8].fTexturable = true; + fConfigOptions[(int)GrColorType::kBGR_565].fTexturable = true; + + fConfigOptions[(int)GrColorType::kBGRA_8888] = fConfigOptions[(int)GrColorType::kRGBA_8888]; + + fCompressedOptions[(int)SkTextureCompressionType::kETC2_RGB8_UNORM].fTexturable = true; + fCompressedOptions[(int)SkTextureCompressionType::kBC1_RGB8_UNORM].fTexturable = true; + fCompressedOptions[(int)SkTextureCompressionType::kBC1_RGBA8_UNORM].fTexturable = true; + } + + struct ConfigOptions { + enum Renderability { kNo, kNonMSAA, kMSAA }; + Renderability fRenderability = kNo; + bool fTexturable = false; + }; + + // GrCaps options. + bool fMipmapSupport = false; + bool fDrawInstancedSupport = false; + bool fHalfFloatVertexAttributeSupport = false; + uint32_t fMapBufferFlags = 0; + int fMaxTextureSize = 2048; + int fMaxRenderTargetSize = 2048; + int fMaxWindowRectangles = 0; + int fMaxVertexAttributes = 16; + ConfigOptions fConfigOptions[kGrColorTypeCnt]; + ConfigOptions fCompressedOptions[kSkTextureCompressionTypeCount]; + + // GrShaderCaps options. + bool fIntegerSupport = false; + bool fFlatInterpolationSupport = false; + int fMaxVertexSamplers = 0; + int fMaxFragmentSamplers = 8; + bool fShaderDerivativeSupport = true; + bool fDualSourceBlendingSupport = false; + + // GrMockGpu options. + bool fFailTextureAllocations = false; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/GrMtlBackendContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/GrMtlBackendContext.h new file mode 100644 index 00000000000000..0d88f479acc8dc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/GrMtlBackendContext.h @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrMtlBackendContext_DEFINED +#define GrMtlBackendContext_DEFINED + +#include "include/gpu/mtl/GrMtlTypes.h" + +// The BackendContext contains all of the base Metal objects needed by the GrMtlGpu. The assumption +// is that the client will set these up and pass them to the GrMtlGpu constructor. +struct SK_API GrMtlBackendContext { + sk_cfp fDevice; + sk_cfp fQueue; + sk_cfp fBinaryArchive; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/GrMtlTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/GrMtlTypes.h new file mode 100644 index 00000000000000..7c0d620e06412b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/GrMtlTypes.h @@ -0,0 +1,63 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrMtlTypes_DEFINED +#define GrMtlTypes_DEFINED + +#include "include/gpu/GpuTypes.h" +#include "include/ports/SkCFObject.h" + +/** + * Declares typedefs for Metal types used in Ganesh cpp code + */ +using GrMTLPixelFormat = unsigned int; +using GrMTLTextureUsage = unsigned int; +using GrMTLStorageMode = unsigned int; +using GrMTLHandle = const void*; + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ + +#include + +#if TARGET_OS_SIMULATOR +#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(13.0)) +#else // TARGET_OS_SIMULATOR +#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(8.0)) +#endif // TARGET_OS_SIMULATOR + +/** + * Types for interacting with Metal resources created externally to Skia. + * This is used by GrBackendObjects. + */ +struct GrMtlTextureInfo { +public: + GrMtlTextureInfo() {} + + sk_cfp fTexture; + + bool operator==(const GrMtlTextureInfo& that) const { + return fTexture == that.fTexture; + } +}; + +struct GrMtlSurfaceInfo { + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + // Since we aren't in an Obj-C header we can't directly use Mtl types here. Each of these can + // cast to their mapped Mtl types list below. + GrMTLPixelFormat fFormat = 0; // MTLPixelFormat fFormat = MTLPixelFormatInvalid; + GrMTLTextureUsage fUsage = 0; // MTLTextureUsage fUsage = MTLTextureUsageUnknown; + GrMTLStorageMode fStorageMode = 0; // MTLStorageMode fStorageMode = MTLStorageModeShared; +}; + +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/MtlMemoryAllocator.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/MtlMemoryAllocator.h new file mode 100644 index 00000000000000..425c4617914b8d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/mtl/MtlMemoryAllocator.h @@ -0,0 +1,39 @@ +/* + * Copyright 2022 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_MtlMemoryAllocator_DEFINED +#define skgpu_MtlMemoryAllocator_DEFINED + +#ifdef __APPLE__ + +#ifdef __OBJC__ +#import +#endif + +namespace skgpu { + +// interface classes for the GPU memory allocator +class MtlAlloc : public SkRefCnt { +public: + ~MtlAlloc() override = default; +}; + +#ifdef __OBJC__ +class MtlMemoryAllocator : public SkRefCnt { +public: + virtual id newBufferWithLength(NSUInteger length, MTLResourceOptions options, + sk_sp* allocation) = 0; + virtual id newTextureWithDescriptor(MTLTextureDescriptor* texDesc, + sk_sp* allocation) = 0; +}; +#endif + +} // namespace skgpu + +#endif // __APPLE__ + +#endif // skgpu_MtlMemoryAllocator_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkBackendContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkBackendContext.h new file mode 100644 index 00000000000000..23c1b0deaf4a5c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkBackendContext.h @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkBackendContext_DEFINED +#define GrVkBackendContext_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/vk/GrVkTypes.h" +#include "include/gpu/vk/VulkanMemoryAllocator.h" + +namespace skgpu { class VulkanExtensions; } + +enum GrVkExtensionFlags { + kEXT_debug_report_GrVkExtensionFlag = 0x0001, + kNV_glsl_shader_GrVkExtensionFlag = 0x0002, + kKHR_surface_GrVkExtensionFlag = 0x0004, + kKHR_swapchain_GrVkExtensionFlag = 0x0008, + kKHR_win32_surface_GrVkExtensionFlag = 0x0010, + kKHR_android_surface_GrVkExtensionFlag = 0x0020, + kKHR_xcb_surface_GrVkExtensionFlag = 0x0040, +}; + +enum GrVkFeatureFlags { + kGeometryShader_GrVkFeatureFlag = 0x0001, + kDualSrcBlend_GrVkFeatureFlag = 0x0002, + kSampleRateShading_GrVkFeatureFlag = 0x0004, +}; + +// It is not guarenteed VkPhysicalDeviceProperties2 will be in the client's header so we forward +// declare it here to be safe. +struct VkPhysicalDeviceFeatures2; + +// The BackendContext contains all of the base Vulkan objects needed by the GrVkGpu. The assumption +// is that the client will set these up and pass them to the GrVkGpu constructor. The VkDevice +// created must support at least one graphics queue, which is passed in as well. +// The QueueFamilyIndex must match the family of the given queue. It is needed for CommandPool +// creation, and any GrBackendObjects handed to us (e.g., for wrapped textures) needs to be created +// in or transitioned to that family. The refs held by members of this struct must be released +// (either by deleting the struct or manually releasing the refs) before the underlying vulkan +// device and instance are destroyed. +struct SK_API GrVkBackendContext { + VkInstance fInstance = VK_NULL_HANDLE; + VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE; + VkDevice fDevice = VK_NULL_HANDLE; + VkQueue fQueue = VK_NULL_HANDLE; + uint32_t fGraphicsQueueIndex = 0; + uint32_t fMinAPIVersion = 0; // Deprecated. Use fInstanceVersion + // instead. + uint32_t fInstanceVersion = 0; // Deprecated. Use fMaxApiVersion + // The max api version set here should match the value set in VkApplicationInfo::apiVersion when + // then VkInstance was created. + uint32_t fMaxAPIVersion = 0; + uint32_t fExtensions = 0; // Deprecated. Use fVkExtensions instead. + const skgpu::VulkanExtensions* fVkExtensions = nullptr; + uint32_t fFeatures = 0; // Deprecated. Use fDeviceFeatures[2] + // instead. + // The client can create their VkDevice with either a VkPhysicalDeviceFeatures or + // VkPhysicalDeviceFeatures2 struct, thus we have to support taking both. The + // VkPhysicalDeviceFeatures2 struct is needed so we know if the client enabled any extension + // specific features. If fDeviceFeatures2 is not null then we ignore fDeviceFeatures. If both + // fDeviceFeatures and fDeviceFeatures2 are null we will assume no features are enabled. + const VkPhysicalDeviceFeatures* fDeviceFeatures = nullptr; + const VkPhysicalDeviceFeatures2* fDeviceFeatures2 = nullptr; + sk_sp fMemoryAllocator; + skgpu::VulkanGetProc fGetProc = nullptr; + // This is deprecated and should be set to false. The client is responsible for managing the + // lifetime of the VkInstance and VkDevice objects. + bool fOwnsInstanceAndDevice = false; + // Indicates that we are working with protected content and all CommandPool and Queue operations + // should be done in a protected context. + skgpu::Protected fProtectedContext = skgpu::Protected::kNo; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkExtensions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkExtensions.h new file mode 100644 index 00000000000000..b32cc16eb5373d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkExtensions.h @@ -0,0 +1,15 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkExtensions_DEFINED +#define GrVkExtensions_DEFINED + +#include "include/gpu/vk/VulkanExtensions.h" + +using GrVkExtensions = skgpu::VulkanExtensions; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkMemoryAllocator.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkMemoryAllocator.h new file mode 100644 index 00000000000000..034e1f506c6769 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkMemoryAllocator.h @@ -0,0 +1,15 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkMemoryAllocator_DEFINED +#define GrVkMemoryAllocator_DEFINED + +#include "include/gpu/vk/VulkanMemoryAllocator.h" + +using GrVkMemoryAllocator = skgpu::VulkanMemoryAllocator; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkTypes.h new file mode 100644 index 00000000000000..ae680a8af55219 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/GrVkTypes.h @@ -0,0 +1,149 @@ + +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkTypes_DEFINED +#define GrVkTypes_DEFINED + +#include "include/gpu/GpuTypes.h" +#include "include/gpu/vk/VulkanTypes.h" + +using GrVkBackendMemory = skgpu::VulkanBackendMemory; +using GrVkAlloc = skgpu::VulkanAlloc; + +// This struct is used to pass in the necessary information to create a VkSamplerYcbcrConversion +// object for an VkExternalFormatANDROID. +struct GrVkYcbcrConversionInfo { + bool operator==(const GrVkYcbcrConversionInfo& that) const { + // Invalid objects are not required to have all other fields initialized or matching. + if (!this->isValid() && !that.isValid()) { + return true; + } + return this->fFormat == that.fFormat && + this->fExternalFormat == that.fExternalFormat && + this->fYcbcrModel == that.fYcbcrModel && + this->fYcbcrRange == that.fYcbcrRange && + this->fXChromaOffset == that.fXChromaOffset && + this->fYChromaOffset == that.fYChromaOffset && + this->fChromaFilter == that.fChromaFilter && + this->fForceExplicitReconstruction == that.fForceExplicitReconstruction; + } + bool operator!=(const GrVkYcbcrConversionInfo& that) const { return !(*this == that); } + + bool isValid() const { return fYcbcrModel != VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; } + + // Format of the source image. Must be set to VK_FORMAT_UNDEFINED for external images or + // a valid image format otherwise. + VkFormat fFormat = VK_FORMAT_UNDEFINED; + + // The external format. Must be non-zero for external images, zero otherwise. + // Should be compatible to be used in a VkExternalFormatANDROID struct. + uint64_t fExternalFormat = 0; + + VkSamplerYcbcrModelConversion fYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; + VkSamplerYcbcrRange fYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; + VkChromaLocation fXChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; + VkChromaLocation fYChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; + VkFilter fChromaFilter = VK_FILTER_NEAREST; + VkBool32 fForceExplicitReconstruction = false; + + // For external images format features here should be those returned by a call to + // vkAndroidHardwareBufferFormatPropertiesANDROID + VkFormatFeatureFlags fFormatFeatures = 0; +}; + +/* + * When wrapping a GrBackendTexture or GrBackendRendenderTarget, the fCurrentQueueFamily should + * either be VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_EXTERNAL, or VK_QUEUE_FAMILY_FOREIGN_EXT. If + * fSharingMode is VK_SHARING_MODE_EXCLUSIVE then fCurrentQueueFamily can also be the graphics + * queue index passed into Skia. + */ +struct GrVkImageInfo { + VkImage fImage = VK_NULL_HANDLE; + skgpu::VulkanAlloc fAlloc; + VkImageTiling fImageTiling = VK_IMAGE_TILING_OPTIMAL; + VkImageLayout fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkFormat fFormat = VK_FORMAT_UNDEFINED; + VkImageUsageFlags fImageUsageFlags = 0; + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + uint32_t fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED; + skgpu::Protected fProtected = skgpu::Protected::kNo; + GrVkYcbcrConversionInfo fYcbcrConversionInfo; + VkSharingMode fSharingMode = VK_SHARING_MODE_EXCLUSIVE; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + bool fPartOfSwapchainOrAndroidWindow = false; +#endif + +#if GR_TEST_UTILS + bool operator==(const GrVkImageInfo& that) const { + bool equal = fImage == that.fImage && fAlloc == that.fAlloc && + fImageTiling == that.fImageTiling && + fImageLayout == that.fImageLayout && + fFormat == that.fFormat && + fImageUsageFlags == that.fImageUsageFlags && + fSampleCount == that.fSampleCount && + fLevelCount == that.fLevelCount && + fCurrentQueueFamily == that.fCurrentQueueFamily && + fProtected == that.fProtected && + fYcbcrConversionInfo == that.fYcbcrConversionInfo && + fSharingMode == that.fSharingMode; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + equal = equal && (fPartOfSwapchainOrAndroidWindow == that.fPartOfSwapchainOrAndroidWindow); +#endif + return equal; + } +#endif +}; + +using GrVkGetProc = skgpu::VulkanGetProc; + +/** + * This object is wrapped in a GrBackendDrawableInfo and passed in as an argument to + * drawBackendGpu() calls on an SkDrawable. The drawable will use this info to inject direct + * Vulkan calls into our stream of GPU draws. + * + * The SkDrawable is given a secondary VkCommandBuffer in which to record draws. The GPU backend + * will then execute that command buffer within a render pass it is using for its own draws. The + * drawable is also given the attachment of the color index, a compatible VkRenderPass, and the + * VkFormat of the color attachment so that it can make VkPipeline objects for the draws. The + * SkDrawable must not alter the state of the VkRenderpass or sub pass. + * + * Additionally, the SkDrawable may fill in the passed in fDrawBounds with the bounds of the draws + * that it submits to the command buffer. This will be used by the GPU backend for setting the + * bounds in vkCmdBeginRenderPass. If fDrawBounds is not updated, we will assume that the entire + * attachment may have been written to. + * + * The SkDrawable is always allowed to create its own command buffers and submit them to the queue + * to render offscreen textures which will be sampled in draws added to the passed in + * VkCommandBuffer. If this is done the SkDrawable is in charge of adding the required memory + * barriers to the queue for the sampled images since the Skia backend will not do this. + */ +struct GrVkDrawableInfo { + VkCommandBuffer fSecondaryCommandBuffer; + uint32_t fColorAttachmentIndex; + VkRenderPass fCompatibleRenderPass; + VkFormat fFormat; + VkRect2D* fDrawBounds; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + bool fFromSwapchainOrAndroidWindow; +#endif +}; + +struct GrVkSurfaceInfo { + uint32_t fSampleCount = 1; + uint32_t fLevelCount = 0; + skgpu::Protected fProtected = skgpu::Protected::kNo; + + VkImageTiling fImageTiling = VK_IMAGE_TILING_OPTIMAL; + VkFormat fFormat = VK_FORMAT_UNDEFINED; + VkImageUsageFlags fImageUsageFlags = 0; + GrVkYcbcrConversionInfo fYcbcrConversionInfo; + VkSharingMode fSharingMode = VK_SHARING_MODE_EXCLUSIVE; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanBackendContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanBackendContext.h new file mode 100644 index 00000000000000..c78e2de0c92f26 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanBackendContext.h @@ -0,0 +1,46 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_VulkanBackendContext_DEFINED +#define skgpu_VulkanBackendContext_DEFINED + +#include "include/gpu/GpuTypes.h" +#include "include/gpu/vk/VulkanMemoryAllocator.h" +#include "include/gpu/vk/VulkanTypes.h" + +namespace skgpu { + +class VulkanExtensions; + +// The VkBackendContext contains all of the base Vk objects needed by the skia Vulkan context. +struct SK_API VulkanBackendContext { + VkInstance fInstance; + VkPhysicalDevice fPhysicalDevice; + VkDevice fDevice; + VkQueue fQueue; + uint32_t fGraphicsQueueIndex; + // The max api version set here should match the value set in VkApplicationInfo::apiVersion when + // then VkInstance was created. + uint32_t fMaxAPIVersion; + const skgpu::VulkanExtensions* fVkExtensions = nullptr; + // The client can create their VkDevice with either a VkPhysicalDeviceFeatures or + // VkPhysicalDeviceFeatures2 struct, thus we have to support taking both. The + // VkPhysicalDeviceFeatures2 struct is needed so we know if the client enabled any extension + // specific features. If fDeviceFeatures2 is not null then we ignore fDeviceFeatures. If both + // fDeviceFeatures and fDeviceFeatures2 are null we will assume no features are enabled. + const VkPhysicalDeviceFeatures* fDeviceFeatures = nullptr; + const VkPhysicalDeviceFeatures2* fDeviceFeatures2 = nullptr; + // Optional. The client may provide an inplementation of a VulkanMemoryAllocator for Skia to use + // for allocating Vulkan resources that use VkDeviceMemory. + sk_sp fMemoryAllocator; + skgpu::VulkanGetProc fGetProc; + Protected fProtectedContext; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_VulkanBackendContext_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanExtensions.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanExtensions.h new file mode 100644 index 00000000000000..90a40c0e674d88 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanExtensions.h @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_VulkanExtensions_DEFINED +#define skgpu_VulkanExtensions_DEFINED + +#include "include/core/SkString.h" +#include "include/gpu/vk/VulkanTypes.h" +#include "include/private/base/SkTArray.h" + +namespace skgpu { + +/** + * Helper class that eats in an array of extensions strings for instance and device and allows for + * quicker querying if an extension is present. + */ +class SK_API VulkanExtensions { +public: + VulkanExtensions() {} + + void init(VulkanGetProc, VkInstance, VkPhysicalDevice, + uint32_t instanceExtensionCount, const char* const* instanceExtensions, + uint32_t deviceExtensionCount, const char* const* deviceExtensions); + + bool hasExtension(const char[], uint32_t minVersion) const; + + struct Info { + Info() {} + Info(const char* name) : fName(name), fSpecVersion(0) {} + + SkString fName; + uint32_t fSpecVersion; + + struct Less { + bool operator()(const Info& a, const SkString& b) const { + return strcmp(a.fName.c_str(), b.c_str()) < 0; + } + bool operator()(const SkString& a, const VulkanExtensions::Info& b) const { + return strcmp(a.c_str(), b.fName.c_str()) < 0; + } + }; + }; + +#ifdef SK_DEBUG + void dump() const { + SkDebugf("**Vulkan Extensions**\n"); + for (int i = 0; i < fExtensions.size(); ++i) { + SkDebugf("%s. Version: %d\n", + fExtensions[i].fName.c_str(), fExtensions[i].fSpecVersion); + } + SkDebugf("**End Vulkan Extensions**\n"); + } +#endif + +private: + void getSpecVersions(VulkanGetProc getProc, VkInstance, VkPhysicalDevice); + + skia_private::TArray fExtensions; +}; + +} // namespace skgpu + +#endif // skgpu_VulkanExtensions_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanMemoryAllocator.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanMemoryAllocator.h new file mode 100644 index 00000000000000..ebaa28ed1b4b08 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanMemoryAllocator.h @@ -0,0 +1,114 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_VulkanMemoryAllocator_DEFINED +#define skgpu_VulkanMemoryAllocator_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/GpuTypes.h" +#include "include/gpu/vk/VulkanTypes.h" + +namespace skgpu { + +class VulkanMemoryAllocator : public SkRefCnt { +public: + enum AllocationPropertyFlags { + kNone_AllocationPropertyFlag = 0b0000, + // Allocation will be placed in its own VkDeviceMemory and not suballocated from some larger + // block. + kDedicatedAllocation_AllocationPropertyFlag = 0b0001, + // Says that the backing memory can only be accessed by the device. Additionally the device + // may lazily allocate the memory. This cannot be used with buffers that will be host + // visible. Setting this flag does not guarantee that we will allocate memory that respects + // it, but we will try to prefer memory that can respect it. + kLazyAllocation_AllocationPropertyFlag = 0b0010, + // The allocation will be mapped immediately and stay mapped until it is destroyed. This + // flag is only valid for buffers which are host visible (i.e. must have a usage other than + // BufferUsage::kGpuOnly). + kPersistentlyMapped_AllocationPropertyFlag = 0b0100, + // Allocation can only be accessed by the device using a protected context. + kProtected_AllocationPropertyFlag = 0b1000, + }; + + enum class BufferUsage { + // Buffers that will only be accessed from the device (large const buffers) will always be + // in device local memory. + kGpuOnly, + // Buffers that typically will be updated multiple times by the host and read on the gpu + // (e.g. uniform or vertex buffers). CPU writes will generally be sequential in the buffer + // and will try to take advantage of the write-combined nature of the gpu buffers. Thus this + // will always be mappable and coherent memory, and it will prefer to be in device local + // memory. + kCpuWritesGpuReads, + // Buffers that will be accessed on the host and copied to another GPU resource (transfer + // buffers). Will always be mappable and coherent memory. + kTransfersFromCpuToGpu, + // Buffers which are typically writted to by the GPU and then read on the host. Will always + // be mappable memory, and will prefer cached memory. + kTransfersFromGpuToCpu, + }; + + virtual VkResult allocateImageMemory(VkImage image, + uint32_t allocationPropertyFlags, + skgpu::VulkanBackendMemory* memory) = 0; + + virtual VkResult allocateBufferMemory(VkBuffer buffer, + BufferUsage usage, + uint32_t allocationPropertyFlags, + skgpu::VulkanBackendMemory* memory) = 0; + + // Fills out the passed in skgpu::VulkanAlloc struct for the passed in + // skgpu::VulkanBackendMemory. + virtual void getAllocInfo(const skgpu::VulkanBackendMemory&, skgpu::VulkanAlloc*) const = 0; + + // Maps the entire allocation and returns a pointer to the start of the allocation. The + // implementation may map more memory than just the allocation, but the returned pointer must + // point at the start of the memory for the requested allocation. + virtual void* mapMemory(const skgpu::VulkanBackendMemory&) { return nullptr; } + virtual VkResult mapMemory(const skgpu::VulkanBackendMemory& memory, void** data) { + *data = this->mapMemory(memory); + // VK_ERROR_INITIALIZATION_FAILED is a bogus result to return from this function, but it is + // just something to return that is not VK_SUCCESS and can't be interpreted by a caller to + // mean something specific happened like device lost or oom. This will be removed once we + // update clients to implement this virtual. + return *data ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED; + } + virtual void unmapMemory(const skgpu::VulkanBackendMemory&) = 0; + + // The following two calls are used for managing non-coherent memory. The offset is relative to + // the start of the allocation and not the underlying VkDeviceMemory. Additionaly the client + // must make sure that the offset + size passed in is less that or equal to the allocation size. + // It is the responsibility of the implementation to make sure all alignment requirements are + // followed. The client should not have to deal with any sort of alignment issues. + virtual void flushMappedMemory(const skgpu::VulkanBackendMemory&, VkDeviceSize, VkDeviceSize) {} + virtual VkResult flushMemory(const skgpu::VulkanBackendMemory& memory, + VkDeviceSize offset, + VkDeviceSize size) { + this->flushMappedMemory(memory, offset, size); + return VK_SUCCESS; + } + virtual void invalidateMappedMemory(const skgpu::VulkanBackendMemory&, + VkDeviceSize, + VkDeviceSize) {} + virtual VkResult invalidateMemory(const skgpu::VulkanBackendMemory& memory, + VkDeviceSize offset, + VkDeviceSize size) { + this->invalidateMappedMemory(memory, offset, size); + return VK_SUCCESS; + } + + virtual void freeMemory(const skgpu::VulkanBackendMemory&) = 0; + + // Returns the total amount of memory that is allocated as well as total + // amount of memory in use by an allocation from this allocator. + // Return 1st param is total allocated memory, 2nd is total used memory. + virtual std::pair totalAllocatedAndUsedMemory() const = 0; +}; + +} // namespace skgpu + +#endif // skgpu_VulkanMemoryAllocator_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanTypes.h new file mode 100644 index 00000000000000..5468c592114866 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/gpu/vk/VulkanTypes.h @@ -0,0 +1,59 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_VulkanTypes_DEFINED +#define skgpu_VulkanTypes_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/gpu/vk/SkiaVulkan.h" + +#include + +#ifndef VK_VERSION_1_1 +#error Skia requires the use of Vulkan 1.1 headers +#endif + +namespace skgpu { + +using VulkanGetProc = std::function; + +typedef intptr_t VulkanBackendMemory; + +/** + * Types for interacting with Vulkan resources created externally to Skia. + */ +struct VulkanAlloc { + // can be VK_NULL_HANDLE iff is an RT and is borrowed + VkDeviceMemory fMemory = VK_NULL_HANDLE; + VkDeviceSize fOffset = 0; + VkDeviceSize fSize = 0; // this can be indeterminate iff Tex uses borrow semantics + uint32_t fFlags = 0; + // handle to memory allocated via skgpu::VulkanMemoryAllocator. + VulkanBackendMemory fBackendMemory = 0; + + enum Flag { + kNoncoherent_Flag = 0x1, // memory must be flushed to device after mapping + kMappable_Flag = 0x2, // memory is able to be mapped. + kLazilyAllocated_Flag = 0x4, // memory was created with lazy allocation + }; + + bool operator==(const VulkanAlloc& that) const { + return fMemory == that.fMemory && fOffset == that.fOffset && fSize == that.fSize && + fFlags == that.fFlags && fUsesSystemHeap == that.fUsesSystemHeap; + } + +private: + bool fUsesSystemHeap = false; +}; + +} // namespace skgpu + +#endif // skgpu_VulkanTypes_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/pathops/SkPathOps.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/pathops/SkPathOps.h new file mode 100644 index 00000000000000..47d2b3118fbf6a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/pathops/SkPathOps.h @@ -0,0 +1,113 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkPathOps_DEFINED +#define SkPathOps_DEFINED + +#include "include/core/SkPath.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTArray.h" +#include "include/private/base/SkTDArray.h" + +struct SkRect; + + +// FIXME: move everything below into the SkPath class +/** + * The logical operations that can be performed when combining two paths. + */ +enum SkPathOp { + kDifference_SkPathOp, //!< subtract the op path from the first path + kIntersect_SkPathOp, //!< intersect the two paths + kUnion_SkPathOp, //!< union (inclusive-or) the two paths + kXOR_SkPathOp, //!< exclusive-or the two paths + kReverseDifference_SkPathOp, //!< subtract the first path from the op path +}; + +/** Set this path to the result of applying the Op to this path and the + specified path: this = (this op operand). + The resulting path will be constructed from non-overlapping contours. + The curve order is reduced where possible so that cubics may be turned + into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param one The first operand (for difference, the minuend) + @param two The second operand (for difference, the subtrahend) + @param op The operator to apply. + @param result The product of the operands. The result may be one of the + inputs. + @return True if the operation succeeded. + */ +bool SK_API Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result); + +/** Set this path to a set of non-overlapping contours that describe the + same area as the original path. + The curve order is reduced where possible so that cubics may + be turned into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param path The path to simplify. + @param result The simplified path. The result may be the input. + @return True if simplification succeeded. + */ +bool SK_API Simplify(const SkPath& path, SkPath* result); + +/** Set the resulting rectangle to the tight bounds of the path. + + @param path The path measured. + @param result The tight bounds of the path. + @return True if the bounds could be computed. + */ +bool SK_API TightBounds(const SkPath& path, SkRect* result); + +/** Set the result with fill type winding to area equivalent to path. + Returns true if successful. Does not detect if path contains contours which + contain self-crossings or cross other contours; in these cases, may return + true even though result does not fill same area as path. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. The result may be the input. + + @param path The path typically with fill type set to even odd. + @param result The equivalent path with fill type set to winding. + @return True if winding path was set. + */ +bool SK_API AsWinding(const SkPath& path, SkPath* result); + +/** Perform a series of path operations, optimized for unioning many paths together. + */ +class SK_API SkOpBuilder { +public: + /** Add one or more paths and their operand. The builder is empty before the first + path is added, so the result of a single add is (emptyPath OP path). + + @param path The second operand. + @param _operator The operator to apply to the existing and supplied paths. + */ + void add(const SkPath& path, SkPathOp _operator); + + /** Computes the sum of all paths and operands, and resets the builder to its + initial state. + + @param result The product of the operands. + @return True if the operation succeeded. + */ + bool resolve(SkPath* result); + +private: + skia_private::TArray fPathRefs; + SkTDArray fOps; + + static bool FixWinding(SkPath* path); + static void ReversePath(SkPath* path); + void reset(); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkCFObject.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkCFObject.h new file mode 100644 index 00000000000000..20e86671b79041 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkCFObject.h @@ -0,0 +1,180 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCFObject_DEFINED +#define SkCFObject_DEFINED + +#ifdef __APPLE__ + +#include "include/core/SkTypes.h" + +#include // std::nullptr_t + +#import + +/** + * Wrapper class for managing lifetime of CoreFoundation objects. It will call + * CFRetain and CFRelease appropriately on creation, assignment, and deletion. + * Based on sk_sp<>. + */ +template static inline T SkCFSafeRetain(T obj) { + if (obj) { + CFRetain(obj); + } + return obj; +} + +template static inline void SkCFSafeRelease(T obj) { + if (obj) { + CFRelease(obj); + } +} + +template class sk_cfp { +public: + using element_type = T; + + constexpr sk_cfp() {} + constexpr sk_cfp(std::nullptr_t) {} + + /** + * Shares the underlying object by calling CFRetain(), so that both the argument and the newly + * created sk_cfp both have a reference to it. + */ + sk_cfp(const sk_cfp& that) : fObject(SkCFSafeRetain(that.get())) {} + + /** + * Move the underlying object from the argument to the newly created sk_cfp. Afterwards only + * the new sk_cfp will have a reference to the object, and the argument will point to null. + * No call to CFRetain() or CFRelease() will be made. + */ + sk_cfp(sk_cfp&& that) : fObject(that.release()) {} + + /** + * Adopt the bare object into the newly created sk_cfp. + * No call to CFRetain() or CFRelease() will be made. + */ + explicit sk_cfp(T obj) { + fObject = obj; + } + + /** + * Calls CFRelease() on the underlying object pointer. + */ + ~sk_cfp() { + SkCFSafeRelease(fObject); + SkDEBUGCODE(fObject = nil); + } + + sk_cfp& operator=(std::nullptr_t) { this->reset(); return *this; } + + /** + * Shares the underlying object referenced by the argument by calling CFRetain() on it. If this + * sk_cfp previously had a reference to an object (i.e. not null) it will call CFRelease() + * on that object. + */ + sk_cfp& operator=(const sk_cfp& that) { + if (this != &that) { + this->reset(SkCFSafeRetain(that.get())); + } + return *this; + } + + /** + * Move the underlying object from the argument to the sk_cfp. If the sk_cfp + * previously held a reference to another object, CFRelease() will be called on that object. + * No call to CFRetain() will be made. + */ + sk_cfp& operator=(sk_cfp&& that) { + this->reset(that.release()); + return *this; + } + + explicit operator bool() const { return this->get() != nil; } + + T get() const { return fObject; } + T operator*() const { + SkASSERT(fObject); + return fObject; + } + + /** + * Adopt the new object, and call CFRelease() on any previously held object (if not null). + * No call to CFRetain() will be made. + */ + void reset(T object = nil) { + // Need to unref after assigning, see + // http://wg21.cmeerw.net/lwg/issue998 + // http://wg21.cmeerw.net/lwg/issue2262 + T oldObject = fObject; + fObject = object; + SkCFSafeRelease(oldObject); + } + + /** + * Shares the new object by calling CFRetain() on it. If this sk_cfp previously had a + * reference to an object (i.e. not null) it will call CFRelease() on that object. + */ + void retain(T object) { + if (fObject != object) { + this->reset(SkCFSafeRetain(object)); + } + } + + /** + * Return the original object, and set the internal object to nullptr. + * The caller must assume ownership of the object, and manage its reference count directly. + * No call to CFRelease() will be made. + */ + T SK_WARN_UNUSED_RESULT release() { + T obj = fObject; + fObject = nil; + return obj; + } + +private: + T fObject = nil; +}; + +template inline bool operator==(const sk_cfp& a, + const sk_cfp& b) { + return a.get() == b.get(); +} +template inline bool operator==(const sk_cfp& a, + std::nullptr_t) { + return !a; +} +template inline bool operator==(std::nullptr_t, + const sk_cfp& b) { + return !b; +} + +template inline bool operator!=(const sk_cfp& a, + const sk_cfp& b) { + return a.get() != b.get(); +} +template inline bool operator!=(const sk_cfp& a, + std::nullptr_t) { + return static_cast(a); +} +template inline bool operator!=(std::nullptr_t, + const sk_cfp& b) { + return static_cast(b); +} + +/* + * Returns a sk_cfp wrapping the provided object AND calls retain on it (if not null). + * + * This is different than the semantics of the constructor for sk_cfp, which just wraps the + * object, effectively "adopting" it. + */ +template sk_cfp sk_ret_cfp(T obj) { + return sk_cfp(SkCFSafeRetain(obj)); +} + +#endif // __APPLE__ +#endif // SkCFObject_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontConfigInterface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontConfigInterface.h new file mode 100644 index 00000000000000..65fd612593f1a2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontConfigInterface.h @@ -0,0 +1,115 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontConfigInterface_DEFINED +#define SkFontConfigInterface_DEFINED + +#include "include/core/SkFontStyle.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkStream.h" +#include "include/core/SkTypeface.h" + +class SkFontMgr; + +/** + * \class SkFontConfigInterface + * + * A simple interface for remotable font management. + * The global instance can be found with RefGlobal(). + */ +class SK_API SkFontConfigInterface : public SkRefCnt { +public: + + /** + * Returns the global SkFontConfigInterface instance. If it is not + * nullptr, calls ref() on it. The caller must balance this with a call to + * unref(). The default SkFontConfigInterface is the result of calling + * GetSingletonDirectInterface. + */ + static sk_sp RefGlobal(); + + /** + * Replace the current global instance with the specified one. + */ + static void SetGlobal(sk_sp fc); + + /** + * This should be treated as private to the impl of SkFontConfigInterface. + * Callers should not change or expect any particular values. It is meant + * to be a union of possible storage types to aid the impl. + */ + struct FontIdentity { + FontIdentity() : fID(0), fTTCIndex(0) {} + + bool operator==(const FontIdentity& other) const { + return fID == other.fID && + fTTCIndex == other.fTTCIndex && + fString == other.fString; + } + bool operator!=(const FontIdentity& other) const { + return !(*this == other); + } + + uint32_t fID; + int32_t fTTCIndex; + SkString fString; + SkFontStyle fStyle; + + // If buffer is NULL, just return the number of bytes that would have + // been written. Will pad contents to a multiple of 4. + size_t writeToMemory(void* buffer = nullptr) const; + + // Recreate from a flattened buffer, returning the number of bytes read. + size_t readFromMemory(const void* buffer, size_t length); + }; + + /** + * Given a familyName and style, find the best match. + * + * If a match is found, return true and set its outFontIdentifier. + * If outFamilyName is not null, assign the found familyName to it + * (which may differ from the requested familyName). + * If outStyle is not null, assign the found style to it + * (which may differ from the requested style). + * + * If a match is not found, return false, and ignore all out parameters. + */ + virtual bool matchFamilyName(const char familyName[], + SkFontStyle requested, + FontIdentity* outFontIdentifier, + SkString* outFamilyName, + SkFontStyle* outStyle) = 0; + + /** + * Given a FontRef, open a stream to access its data, or return null + * if the FontRef's data is not available. The caller is responsible for + * deleting the stream when it is done accessing the data. + */ + virtual SkStreamAsset* openStream(const FontIdentity&) = 0; + + /** + * Return an SkTypeface for the given FontIdentity. + * + * The default implementation simply returns a new typeface built using data obtained from + * openStream(), but derived classes may implement more complex caching schemes. + */ + virtual sk_sp makeTypeface(const FontIdentity& identity) { + return SkTypeface::MakeFromStream(std::unique_ptr(this->openStream(identity)), + identity.fTTCIndex); + + } + + /** + * Return a singleton instance of a direct subclass that calls into + * libfontconfig. This does not affect the refcnt of the returned instance. + */ + static SkFontConfigInterface* GetSingletonDirectInterface(); + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_FontConfigInterface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_FontConfigInterface.h new file mode 100644 index 00000000000000..05771257d25fbf --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_FontConfigInterface.h @@ -0,0 +1,20 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_FontConfigInterface_DEFINED +#define SkFontMgr_FontConfigInterface_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; +class SkFontConfigInterface; + +/** Creates a SkFontMgr which wraps a SkFontConfigInterface. */ +SK_API sk_sp SkFontMgr_New_FCI(sk_sp fci); + +#endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_android.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_android.h new file mode 100644 index 00000000000000..d68f3ba034a05b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_android.h @@ -0,0 +1,45 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_android_DEFINED +#define SkFontMgr_android_DEFINED + +#include "include/core/SkRefCnt.h" + +class SkFontMgr; + +struct SkFontMgr_Android_CustomFonts { + /** When specifying custom fonts, indicates how to use system fonts. */ + enum SystemFontUse { + kOnlyCustom, /** Use only custom fonts. NDK compliant. */ + kPreferCustom, /** Use custom fonts before system fonts. */ + kPreferSystem /** Use system fonts before custom fonts. */ + }; + /** Whether or not to use system fonts. */ + SystemFontUse fSystemFontUse; + + /** Base path to resolve relative font file names. If a directory, should end with '/'. */ + const char* fBasePath; + + /** Optional custom configuration file to use. */ + const char* fFontsXml; + + /** Optional custom configuration file for fonts which provide fallback. + * In the new style (version > 21) fontsXml format is used, this should be NULL. + */ + const char* fFallbackFontsXml; + + /** Optional custom flag. If set to true the SkFontMgr will acquire all requisite + * system IO resources on initialization. + */ + bool fIsolated; +}; + +/** Create a font manager for Android. If 'custom' is NULL, use only system fonts. */ +SK_API sk_sp SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom); + +#endif // SkFontMgr_android_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_data.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_data.h new file mode 100644 index 00000000000000..6a22365af433bc --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_data.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkFontMgr_data_DEFINED +#define SkFontMgr_data_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSpan.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager which wraps a collection of SkData-stored fonts. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Data(SkSpan>); + +#endif // SkFontMgr_data_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_directory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_directory.h new file mode 100644 index 00000000000000..b1a60fb4dac151 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_directory.h @@ -0,0 +1,21 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_directory_DEFINED +#define SkFontMgr_directory_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager which scans a given directory for font files. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Directory(const char* dir); + +#endif // SkFontMgr_directory_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_empty.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_empty.h new file mode 100644 index 00000000000000..e5756421d0c52f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_empty.h @@ -0,0 +1,21 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_empty_DEFINED +#define SkFontMgr_empty_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager that contains no built-in fonts. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Empty(); + +#endif // SkFontMgr_empty_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_fontconfig.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_fontconfig.h new file mode 100644 index 00000000000000..4b2bb2d297f309 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_fontconfig.h @@ -0,0 +1,22 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_fontconfig_DEFINED +#define SkFontMgr_fontconfig_DEFINED + +#include "include/core/SkRefCnt.h" +#include + +class SkFontMgr; + +/** Create a font manager around a FontConfig instance. + * If 'fc' is NULL, will use a new default config. + * Takes ownership of 'fc' and will call FcConfigDestroy on it. + */ +SK_API sk_sp SkFontMgr_New_FontConfig(FcConfig* fc); + +#endif // #ifndef SkFontMgr_fontconfig_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_fuchsia.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_fuchsia.h new file mode 100644 index 00000000000000..d20530af723cb2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_fuchsia.h @@ -0,0 +1,19 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_fuchsia_DEFINED +#define SkFontMgr_fuchsia_DEFINED + +#include + +#include "include/core/SkRefCnt.h" + +class SkFontMgr; + +SK_API sk_sp SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider); + +#endif // SkFontMgr_fuchsia_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_indirect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_indirect.h new file mode 100644 index 00000000000000..99a1813456f09f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_indirect.h @@ -0,0 +1,102 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_indirect_DEFINED +#define SkFontMgr_indirect_DEFINED + +#include "include/core/SkFontMgr.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" +#include "include/ports/SkRemotableFontMgr.h" +#include "include/private/base/SkMutex.h" +#include "include/private/base/SkOnce.h" +#include "include/private/base/SkTArray.h" + +class SkData; +class SkFontStyle; +class SkStreamAsset; +class SkString; + +class SK_API SkFontMgr_Indirect : public SkFontMgr { +public: + // TODO: The SkFontMgr is only used for createFromStream/File/Data. + // In the future these calls should be broken out into their own interface + // with a name like SkFontRenderer. + SkFontMgr_Indirect(sk_sp impl, sk_sp proxy) + : fImpl(std::move(impl)), fProxy(std::move(proxy)) + { } + +protected: + int onCountFamilies() const override; + void onGetFamilyName(int index, SkString* familyName) const override; + sk_sp onCreateStyleSet(int index) const override; + + sk_sp onMatchFamily(const char familyName[]) const override; + + sk_sp onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const override; + + sk_sp onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle&, + const char* bcp47[], + int bcp47Count, + SkUnichar character) const override; + + sk_sp onMakeFromStreamIndex(std::unique_ptr, int ttcIndex) const override; + sk_sp onMakeFromStreamArgs(std::unique_ptr stream, + const SkFontArguments& args) const override; + sk_sp onMakeFromFile(const char path[], int ttcIndex) const override; + sk_sp onMakeFromData(sk_sp, int ttcIndex) const override; + sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override; + +private: + sk_sp createTypefaceFromFontId(const SkFontIdentity& fontId) const; + + sk_sp fImpl; + sk_sp fProxy; + + struct DataEntry { + uint32_t fDataId; // key1 + uint32_t fTtcIndex; // key2 + SkTypeface* fTypeface; // value: weak ref to typeface + + DataEntry() = default; + + DataEntry(DataEntry&& that) { *this = std::move(that); } + DataEntry& operator=(DataEntry&& that) { + if (this != &that) { + fDataId = that.fDataId; + fTtcIndex = that.fTtcIndex; + fTypeface = that.fTypeface; + + SkDEBUGCODE(that.fDataId = SkFontIdentity::kInvalidDataId;) + SkDEBUGCODE(that.fTtcIndex = 0xbbadbeef;) + that.fTypeface = nullptr; + } + return *this; + } + + ~DataEntry() { + if (fTypeface) { + fTypeface->weak_unref(); + } + } + }; + /** + * This cache is essentially { dataId: { ttcIndex: typeface } } + * For data caching we want a mapping from data id to weak references to + * typefaces with that data id. By storing the index next to the typeface, + * this data cache also acts as a typeface cache. + */ + mutable skia_private::TArray fDataCache; + mutable SkMutex fDataCacheMutex; + + friend class SkStyleSet_Indirect; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_mac_ct.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_mac_ct.h new file mode 100644 index 00000000000000..45cba65b5da3ce --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkFontMgr_mac_ct.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_mac_ct_DEFINED +#define SkFontMgr_mac_ct_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#ifdef SK_BUILD_FOR_MAC +#import +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +class SkFontMgr; + +/** Create a font manager for CoreText. If the collection is nullptr the system default will be used. */ +SK_API extern sk_sp SkFontMgr_New_CoreText(CTFontCollectionRef); + +#endif // SkFontMgr_mac_ct_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorCG.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorCG.h new file mode 100644 index 00000000000000..93592cde4ece48 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorCG.h @@ -0,0 +1,20 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "include/core/SkData.h" +#include "include/core/SkImageGenerator.h" + +#include + +namespace SkImageGeneratorCG { +SK_API std::unique_ptr MakeFromEncodedCG(sk_sp); +} // namespace SkImageGeneratorCG + +#endif //defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorNDK.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorNDK.h new file mode 100644 index 00000000000000..739a586f0d169d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorNDK.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageGeneratorNDK_DEFINED +#define SkImageGeneratorNDK_DEFINED + +#include "include/core/SkTypes.h" +#ifdef SK_ENABLE_NDK_IMAGES + +#include "include/core/SkData.h" +#include "include/core/SkImageGenerator.h" + +#include + +namespace SkImageGeneratorNDK { +/** + * Create a generator that uses the Android NDK's APIs for decoding images. + * + * Only supported on devices where __ANDROID_API__ >= 30. + * + * As with SkCodec, the SkColorSpace passed to getPixels() determines the + * type of color space transformations to apply. A null SkColorSpace means to + * apply none. + * + * A note on scaling: Calling getPixels() on the resulting SkImageGenerator + * with dimensions that do not match getInfo() requests a scale. For WebP + * files, dimensions smaller than those of getInfo are supported. For Jpeg + * files, dimensions of 1/2, 1/4, and 1/8 are supported. TODO: Provide an + * API like SkCodecImageGenerator::getScaledDimensions() to report which + * dimensions are supported? + */ +SK_API std::unique_ptr MakeFromEncodedNDK(sk_sp); +} + +#endif // SK_ENABLE_NDK_IMAGES +#endif // SkImageGeneratorNDK_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorWIC.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorWIC.h new file mode 100644 index 00000000000000..eb57a209567aed --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkImageGeneratorWIC.h @@ -0,0 +1,35 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" + +#if defined(SK_BUILD_FOR_WIN) + +#include "include/core/SkData.h" +#include "include/core/SkImageGenerator.h" + +#include + +/* + * Any Windows program that uses COM must initialize the COM library by calling + * the CoInitializeEx function. In addition, each thread that uses a COM + * interface must make a separate call to this function. + * + * For every successful call to CoInitializeEx, the thread must call + * CoUninitialize before it exits. + * + * SkImageGeneratorWIC requires the COM library and leaves it to the client to + * initialize COM for their application. + * + * For more information on initializing COM, please see: + * https://msdn.microsoft.com/en-us/library/windows/desktop/ff485844.aspx + */ +namespace SkImageGeneratorWIC { +SK_API std::unique_ptr MakeFromEncodedWIC(sk_sp); +} + +#endif // SK_BUILD_FOR_WIN diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkRemotableFontMgr.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkRemotableFontMgr.h new file mode 100644 index 00000000000000..eacb6bde9c5400 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkRemotableFontMgr.h @@ -0,0 +1,139 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRemotableFontMgr_DEFINED +#define SkRemotableFontMgr_DEFINED + +#include "include/core/SkFontStyle.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTemplates.h" + +class SkDataTable; +class SkStreamAsset; + +struct SK_API SkFontIdentity { + static const uint32_t kInvalidDataId = 0xFFFFFFFF; + + // Note that fDataId is a data identifier, not a font identifier. + // (fDataID, fTtcIndex) can be seen as a font identifier. + uint32_t fDataId; + uint32_t fTtcIndex; + + // On Linux/FontConfig there is also the ability to specify preferences for rendering + // antialias, embedded bitmaps, autohint, hinting, hintstyle, lcd rendering + // may all be set or set to no-preference + // (No-preference is resolved against globals set by the platform) + // Since they may be selected against, these are really 'extensions' to SkFontStyle. + // SkFontStyle should pick these up. + SkFontStyle fFontStyle; +}; + +class SK_API SkRemotableFontIdentitySet : public SkRefCnt { +public: + SkRemotableFontIdentitySet(int count, SkFontIdentity** data); + + int count() const { return fCount; } + const SkFontIdentity& at(int index) const { return fData[index]; } + + static SkRemotableFontIdentitySet* NewEmpty(); + +private: + SkRemotableFontIdentitySet() : fCount(0), fData() { } + + friend SkRemotableFontIdentitySet* sk_remotable_font_identity_set_new(); + + int fCount; + skia_private::AutoTArray fData; + + using INHERITED = SkRefCnt; +}; + +class SK_API SkRemotableFontMgr : public SkRefCnt { +public: + /** + * Returns all of the fonts with the given familyIndex. + * Returns NULL if the index is out of bounds. + * Returns empty if there are no fonts at the given index. + * + * The caller must unref() the returned object. + */ + virtual SkRemotableFontIdentitySet* getIndex(int familyIndex) const = 0; + + /** + * Returns the closest match to the given style in the given index. + * If there are no available fonts at the given index, the return value's + * data id will be kInvalidDataId. + */ + virtual SkFontIdentity matchIndexStyle(int familyIndex, const SkFontStyle&) const = 0; + + /** + * Returns all the fonts on the system with the given name. + * If the given name is NULL, will return the default font family. + * Never returns NULL; will return an empty set if the name is not found. + * + * It is possible that this will return fonts not accessible from + * getIndex(int) or matchIndexStyle(int, SkFontStyle) due to + * hidden or auto-activated fonts. + * + * The matching may be done in a system dependent way. The name may be + * matched case-insensitive, there may be system aliases which resolve, + * and names outside the current locale may be considered. However, this + * should only return fonts which are somehow associated with the requested + * name. + * + * The caller must unref() the returned object. + */ + virtual SkRemotableFontIdentitySet* matchName(const char familyName[]) const = 0; + + /** + * Returns the closest matching font to the specified name and style. + * If there are no available fonts which match the name, the return value's + * data id will be kInvalidDataId. + * If the given name is NULL, the match will be against any default fonts. + * + * It is possible that this will return a font identity not accessible from + * methods returning sets due to hidden or auto-activated fonts. + * + * The matching may be done in a system dependent way. The name may be + * matched case-insensitive, there may be system aliases which resolve, + * and names outside the current locale may be considered. However, this + * should only return a font which is somehow associated with the requested + * name. + * + * The caller must unref() the returned object. + */ + virtual SkFontIdentity matchNameStyle(const char familyName[], const SkFontStyle&) const = 0; + + /** + * Use the system fall-back to find a font for the given character. + * If no font can be found for the character, the return value's data id + * will be kInvalidDataId. + * If the name is NULL, the match will start against any default fonts. + * If the bpc47 is NULL, a default locale will be assumed. + * + * Note that bpc47 is a combination of ISO 639, 15924, and 3166-1 codes, + * so it is fine to just pass a ISO 639 here. + */ + virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const=0; + + /** + * Returns the data for the given data id. + * Will return NULL if the data id is invalid. + * Note that this is a data id, not a font id. + * + * The caller must unref() the returned object. + */ + virtual SkStreamAsset* getData(int dataId) const = 0; + +private: + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkTypeface_mac.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkTypeface_mac.h new file mode 100644 index 00000000000000..ec68e05492599d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkTypeface_mac.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTypeface_mac_DEFINED +#define SkTypeface_mac_DEFINED + +#include "include/core/SkTypeface.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include + +#ifdef SK_BUILD_FOR_MAC +#import +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +/** + * Like the other Typeface make methods, this returns a new reference to the + * corresponding typeface for the specified CTFontRef. + */ +SK_API extern sk_sp SkMakeTypefaceFromCTFont(CTFontRef); + +/** + * Returns the platform-specific CTFontRef handle for a + * given SkTypeface. Note that the returned CTFontRef gets + * released when the source SkTypeface is destroyed. + * + * This method is deprecated. It may only be used by Blink Mac + * legacy code in special cases related to text-shaping + * with AAT fonts, clipboard handling and font fallback. + * See https://code.google.com/p/skia/issues/detail?id=3408 + */ +SK_API extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face); + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkTypeface_mac_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkTypeface_win.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkTypeface_win.h new file mode 100644 index 00000000000000..0f0d21ad2a67c2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/ports/SkTypeface_win.h @@ -0,0 +1,80 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTypeface_win_DEFINED +#define SkTypeface_win_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN + +#ifdef UNICODE +typedef struct tagLOGFONTW LOGFONTW; +typedef LOGFONTW LOGFONT; +#else +typedef struct tagLOGFONTA LOGFONTA; +typedef LOGFONTA LOGFONT; +#endif // UNICODE + +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified logfont. The caller is responsible + * for calling unref() when it is finished. + */ +SK_API sk_sp SkCreateTypefaceFromLOGFONT(const LOGFONT&); + +/** + * Copy the LOGFONT associated with this typeface into the lf parameter. Note + * that the lfHeight will need to be set afterwards, since the typeface does + * not track this (the paint does). + * typeface may be NULL, in which case we return the logfont for the default font. + */ +SK_API void SkLOGFONTFromTypeface(const SkTypeface* typeface, LOGFONT* lf); + +/** + * Set an optional callback to ensure that the data behind a LOGFONT is loaded. + * This will get called if Skia tries to access the data but hits a failure. + * Normally this is null, and is only required if the font data needs to be + * remotely (re)loaded. + */ +SK_API void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*)(const LOGFONT&)); + +// Experimental! +// +class SkFontMgr; +class SkRemotableFontMgr; +struct IDWriteFactory; +struct IDWriteFontCollection; +struct IDWriteFontFallback; + +SK_API sk_sp SkFontMgr_New_GDI(); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory = nullptr, + IDWriteFontCollection* collection = nullptr); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection, + IDWriteFontFallback* fallback); + +/** + * Creates an SkFontMgr which renders using DirectWrite and obtains its data + * from the SkRemotableFontMgr. + * + * If DirectWrite could not be initialized, will return NULL. + */ +SK_API sk_sp SkFontMgr_New_DirectWriteRenderer(sk_sp); + +/** + * Creates an SkRemotableFontMgr backed by DirectWrite using the default + * system font collection in the current locale. + * + * If DirectWrite could not be initialized, will return NULL. + */ +SK_API sk_sp SkRemotableFontMgr_New_DirectWrite(); + +#endif // SK_BUILD_FOR_WIN +#endif // SkTypeface_win_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkBitmaskEnum.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkBitmaskEnum.h new file mode 100644 index 00000000000000..b25045359d837a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkBitmaskEnum.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkEnumOperators_DEFINED +#define SkEnumOperators_DEFINED + +#include + +namespace sknonstd { +template struct is_bitmask_enum : std::false_type {}; + +template +std::enable_if_t::value, bool> constexpr Any(E e) { + return static_cast>(e) != 0; +} +} // namespace sknonstd + +template +std::enable_if_t::value, E> constexpr operator|(E l, E r) { + using U = std::underlying_type_t; + return static_cast(static_cast(l) | static_cast(r)); +} + +template +std::enable_if_t::value, E&> constexpr operator|=(E& l, E r) { + return l = l | r; +} + +template +std::enable_if_t::value, E> constexpr operator&(E l, E r) { + using U = std::underlying_type_t; + return static_cast(static_cast(l) & static_cast(r)); +} + +template +std::enable_if_t::value, E&> constexpr operator&=(E& l, E r) { + return l = l & r; +} + +template +std::enable_if_t::value, E> constexpr operator^(E l, E r) { + using U = std::underlying_type_t; + return static_cast(static_cast(l) ^ static_cast(r)); +} + +template +std::enable_if_t::value, E&> constexpr operator^=(E& l, E r) { + return l = l ^ r; +} + +template +std::enable_if_t::value, E> constexpr operator~(E e) { + return static_cast(~static_cast>(e)); +} + +#endif // SkEnumOperators_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkChecksum.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkChecksum.h new file mode 100644 index 00000000000000..e703b622bf3637 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkChecksum.h @@ -0,0 +1,102 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkChecksum_DEFINED +#define SkChecksum_DEFINED + +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" +#include "include/private/SkOpts_spi.h" +#include "include/private/base/SkTLogic.h" + +#include +#include +#include + +class SkChecksum { +public: + SkChecksum() = default; + // Make noncopyable + SkChecksum(const SkChecksum&) = delete; + SkChecksum& operator=(const SkChecksum&) = delete; + + /** + * uint32_t -> uint32_t hash, useful for when you're about to truncate this hash but you + * suspect its low bits aren't well mixed. + * + * This is the Murmur3 finalizer. + */ + static uint32_t Mix(uint32_t hash) { + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + return hash; + } + + /** + * uint32_t -> uint32_t hash, useful for when you're about to truncate this hash but you + * suspect its low bits aren't well mixed. + * + * This version is 2-lines cheaper than Mix, but seems to be sufficient for the font cache. + */ + static uint32_t CheapMix(uint32_t hash) { + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 16; + return hash; + } +}; + +// SkGoodHash should usually be your first choice in hashing data. +// It should be both reasonably fast and high quality. +struct SkGoodHash { + template + std::enable_if_t::value && sizeof(K) == 4, uint32_t> + operator()(const K& k) const { + return SkChecksum::Mix(*(const uint32_t*)&k); + } + + template + std::enable_if_t::value && sizeof(K) != 4, uint32_t> + operator()(const K& k) const { + return SkOpts::hash_fn(&k, sizeof(K), 0); + } + + uint32_t operator()(const SkString& k) const { + return SkOpts::hash_fn(k.c_str(), k.size(), 0); + } + + uint32_t operator()(const std::string& k) const { + return SkOpts::hash_fn(k.c_str(), k.size(), 0); + } + + uint32_t operator()(std::string_view k) const { + return SkOpts::hash_fn(k.data(), k.size(), 0); + } +}; + +// The default hashing behavior in SkGoodHash requires the type to have a unique object +// representation (i.e. all bits in contribute to its identity so can be hashed directly). This is +// false when a struct has padding for alignment (which can be avoided by using +// SK_BEGIN|END_REQUIRE_DENSE) or if the struct has floating point members since there are multiple +// bit representations for NaN. +// +// Often Skia code has externally removed the possibility of NaN so the bit representation of a +// non-NaN float will still hash correctly. SkForceDirectHash produces the same as SkGoodHash +// for K's that do not satisfy std::has_unique_object_representation. It should be used sparingly +// and it's use may highlight design issues with the key's data that might warrant an explicitly +// implemented hash function. +template +struct SkForceDirectHash { + uint32_t operator()(const K& k) const { + return SkOpts::hash_fn(&k, sizeof(K), 0); + } +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkColorData.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkColorData.h new file mode 100644 index 00000000000000..1bef596a3628f7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkColorData.h @@ -0,0 +1,386 @@ +/* + * 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 SkColorData_DEFINED +#define SkColorData_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkColorPriv.h" +#include "include/private/base/SkTo.h" + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 16bit pixel to a 32bit pixel + +#define SK_R16_BITS 5 +#define SK_G16_BITS 6 +#define SK_B16_BITS 5 + +#define SK_R16_SHIFT (SK_B16_BITS + SK_G16_BITS) +#define SK_G16_SHIFT (SK_B16_BITS) +#define SK_B16_SHIFT 0 + +#define SK_R16_MASK ((1 << SK_R16_BITS) - 1) +#define SK_G16_MASK ((1 << SK_G16_BITS) - 1) +#define SK_B16_MASK ((1 << SK_B16_BITS) - 1) + +#define SkGetPackedR16(color) (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK) +#define SkGetPackedG16(color) (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK) +#define SkGetPackedB16(color) (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK) + +static inline unsigned SkR16ToR32(unsigned r) { + return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8)); +} + +static inline unsigned SkG16ToG32(unsigned g) { + return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8)); +} + +static inline unsigned SkB16ToB32(unsigned b) { + return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8)); +} + +#define SkPacked16ToR32(c) SkR16ToR32(SkGetPackedR16(c)) +#define SkPacked16ToG32(c) SkG16ToG32(SkGetPackedG16(c)) +#define SkPacked16ToB32(c) SkB16ToB32(SkGetPackedB16(c)) + +////////////////////////////////////////////////////////////////////////////// + +#define SkASSERT_IS_BYTE(x) SkASSERT(0 == ((x) & ~0xFFu)) + +// Reverse the bytes coorsponding to RED and BLUE in a packed pixels. Note the +// pair of them are in the same 2 slots in both RGBA and BGRA, thus there is +// no need to pass in the colortype to this function. +static inline uint32_t SkSwizzle_RB(uint32_t c) { + static const uint32_t kRBMask = (0xFF << SK_R32_SHIFT) | (0xFF << SK_B32_SHIFT); + + unsigned c0 = (c >> SK_R32_SHIFT) & 0xFF; + unsigned c1 = (c >> SK_B32_SHIFT) & 0xFF; + return (c & ~kRBMask) | (c0 << SK_B32_SHIFT) | (c1 << SK_R32_SHIFT); +} + +static inline uint32_t SkPackARGB_as_RGBA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkASSERT_IS_BYTE(a); + SkASSERT_IS_BYTE(r); + SkASSERT_IS_BYTE(g); + SkASSERT_IS_BYTE(b); + return (a << SK_RGBA_A32_SHIFT) | (r << SK_RGBA_R32_SHIFT) | + (g << SK_RGBA_G32_SHIFT) | (b << SK_RGBA_B32_SHIFT); +} + +static inline uint32_t SkPackARGB_as_BGRA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkASSERT_IS_BYTE(a); + SkASSERT_IS_BYTE(r); + SkASSERT_IS_BYTE(g); + SkASSERT_IS_BYTE(b); + return (a << SK_BGRA_A32_SHIFT) | (r << SK_BGRA_R32_SHIFT) | + (g << SK_BGRA_G32_SHIFT) | (b << SK_BGRA_B32_SHIFT); +} + +static inline SkPMColor SkSwizzle_RGBA_to_PMColor(uint32_t c) { +#ifdef SK_PMCOLOR_IS_RGBA + return c; +#else + return SkSwizzle_RB(c); +#endif +} + +static inline SkPMColor SkSwizzle_BGRA_to_PMColor(uint32_t c) { +#ifdef SK_PMCOLOR_IS_BGRA + return c; +#else + return SkSwizzle_RB(c); +#endif +} + +////////////////////////////////////////////////////////////////////////////// + +///@{ +/** See ITU-R Recommendation BT.709 at http://www.itu.int/rec/R-REC-BT.709/ .*/ +#define SK_ITU_BT709_LUM_COEFF_R (0.2126f) +#define SK_ITU_BT709_LUM_COEFF_G (0.7152f) +#define SK_ITU_BT709_LUM_COEFF_B (0.0722f) +///@} + +///@{ +/** A float value which specifies this channel's contribution to luminance. */ +#define SK_LUM_COEFF_R SK_ITU_BT709_LUM_COEFF_R +#define SK_LUM_COEFF_G SK_ITU_BT709_LUM_COEFF_G +#define SK_LUM_COEFF_B SK_ITU_BT709_LUM_COEFF_B +///@} + +/** Computes the luminance from the given r, g, and b in accordance with + SK_LUM_COEFF_X. For correct results, r, g, and b should be in linear space. +*/ +static inline U8CPU SkComputeLuminance(U8CPU r, U8CPU g, U8CPU b) { + //The following is + //r * SK_LUM_COEFF_R + g * SK_LUM_COEFF_G + b * SK_LUM_COEFF_B + //with SK_LUM_COEFF_X in 1.8 fixed point (rounding adjusted to sum to 256). + return (r * 54 + g * 183 + b * 19) >> 8; +} + +/** Calculates 256 - (value * alpha256) / 255 in range [0,256], + * for [0,255] value and [0,256] alpha256. + */ +static inline U16CPU SkAlphaMulInv256(U16CPU value, U16CPU alpha256) { + unsigned prod = 0xFFFF - value * alpha256; + return (prod + (prod >> 8)) >> 8; +} + +// The caller may want negative values, so keep all params signed (int) +// so we don't accidentally slip into unsigned math and lose the sign +// extension when we shift (in SkAlphaMul) +static inline int SkAlphaBlend(int src, int dst, int scale256) { + SkASSERT((unsigned)scale256 <= 256); + return dst + SkAlphaMul(src - dst, scale256); +} + +static inline uint16_t SkPackRGB16(unsigned r, unsigned g, unsigned b) { + SkASSERT(r <= SK_R16_MASK); + SkASSERT(g <= SK_G16_MASK); + SkASSERT(b <= SK_B16_MASK); + + return SkToU16((r << SK_R16_SHIFT) | (g << SK_G16_SHIFT) | (b << SK_B16_SHIFT)); +} + +#define SK_R16_MASK_IN_PLACE (SK_R16_MASK << SK_R16_SHIFT) +#define SK_G16_MASK_IN_PLACE (SK_G16_MASK << SK_G16_SHIFT) +#define SK_B16_MASK_IN_PLACE (SK_B16_MASK << SK_B16_SHIFT) + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + * scale is [0..256], unlike SkFourByteInterp which takes [0..255] + */ +static inline SkPMColor SkFourByteInterp256(SkPMColor src, SkPMColor dst, int scale) { + unsigned a = SkTo(SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale)); + unsigned r = SkTo(SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale)); + unsigned g = SkTo(SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale)); + unsigned b = SkTo(SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale)); + + return SkPackARGB32(a, r, g, b); +} + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + */ +static inline SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU srcWeight) { + int scale = (int)SkAlpha255To256(srcWeight); + return SkFourByteInterp256(src, dst, scale); +} + +/** + * 0xAARRGGBB -> 0x00AA00GG, 0x00RR00BB + */ +static inline void SkSplay(uint32_t color, uint32_t* ag, uint32_t* rb) { + const uint32_t mask = 0x00FF00FF; + *ag = (color >> 8) & mask; + *rb = color & mask; +} + +/** + * 0xAARRGGBB -> 0x00AA00GG00RR00BB + * (note, ARGB -> AGRB) + */ +static inline uint64_t SkSplay(uint32_t color) { + const uint32_t mask = 0x00FF00FF; + uint64_t agrb = (color >> 8) & mask; // 0x0000000000AA00GG + agrb <<= 32; // 0x00AA00GG00000000 + agrb |= color & mask; // 0x00AA00GG00RR00BB + return agrb; +} + +/** + * 0xAAxxGGxx, 0xRRxxBBxx-> 0xAARRGGBB + */ +static inline uint32_t SkUnsplay(uint32_t ag, uint32_t rb) { + const uint32_t mask = 0xFF00FF00; + return (ag & mask) | ((rb & mask) >> 8); +} + +/** + * 0xAAxxGGxxRRxxBBxx -> 0xAARRGGBB + * (note, AGRB -> ARGB) + */ +static inline uint32_t SkUnsplay(uint64_t agrb) { + const uint32_t mask = 0xFF00FF00; + return SkPMColor( + ((agrb & mask) >> 8) | // 0x00RR00BB + ((agrb >> 32) & mask)); // 0xAARRGGBB +} + +static inline SkPMColor SkFastFourByteInterp256_32(SkPMColor src, SkPMColor dst, unsigned scale) { + SkASSERT(scale <= 256); + + // Two 8-bit blends per two 32-bit registers, with space to make sure the math doesn't collide. + uint32_t src_ag, src_rb, dst_ag, dst_rb; + SkSplay(src, &src_ag, &src_rb); + SkSplay(dst, &dst_ag, &dst_rb); + + const uint32_t ret_ag = src_ag * scale + (256 - scale) * dst_ag; + const uint32_t ret_rb = src_rb * scale + (256 - scale) * dst_rb; + + return SkUnsplay(ret_ag, ret_rb); +} + +static inline SkPMColor SkFastFourByteInterp256_64(SkPMColor src, SkPMColor dst, unsigned scale) { + SkASSERT(scale <= 256); + // Four 8-bit blends in one 64-bit register, with space to make sure the math doesn't collide. + return SkUnsplay(SkSplay(src) * scale + (256-scale) * SkSplay(dst)); +} + +// TODO(mtklein): Replace slow versions with fast versions, using scale + (scale>>7) everywhere. + +/** + * Same as SkFourByteInterp256, but faster. + */ +static inline SkPMColor SkFastFourByteInterp256(SkPMColor src, SkPMColor dst, unsigned scale) { + // On a 64-bit machine, _64 is about 10% faster than _32, but ~40% slower on a 32-bit machine. + if (sizeof(void*) == 4) { + return SkFastFourByteInterp256_32(src, dst, scale); + } else { + return SkFastFourByteInterp256_64(src, dst, scale); + } +} + +/** + * Nearly the same as SkFourByteInterp, but faster and a touch more accurate, due to better + * srcWeight scaling to [0, 256]. + */ +static inline SkPMColor SkFastFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU srcWeight) { + SkASSERT(srcWeight <= 255); + // scale = srcWeight + (srcWeight >> 7) is more accurate than + // scale = srcWeight + 1, but 7% slower + return SkFastFourByteInterp256(src, dst, srcWeight + (srcWeight >> 7)); +} + +/** + * Interpolates between colors src and dst using [0,256] scale. + */ +static inline SkPMColor SkPMLerp(SkPMColor src, SkPMColor dst, unsigned scale) { + return SkFastFourByteInterp256(src, dst, scale); +} + +static inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa) { + SkASSERT((unsigned)aa <= 255); + + unsigned src_scale = SkAlpha255To256(aa); + unsigned dst_scale = SkAlphaMulInv256(SkGetPackedA32(src), src_scale); + + const uint32_t mask = 0xFF00FF; + + uint32_t src_rb = (src & mask) * src_scale; + uint32_t src_ag = ((src >> 8) & mask) * src_scale; + + uint32_t dst_rb = (dst & mask) * dst_scale; + uint32_t dst_ag = ((dst >> 8) & mask) * dst_scale; + + return (((src_rb + dst_rb) >> 8) & mask) | ((src_ag + dst_ag) & ~mask); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 32bit pixel to a 16bit pixel (no dither) + +#define SkR32ToR16_MACRO(r) ((unsigned)(r) >> (SK_R32_BITS - SK_R16_BITS)) +#define SkG32ToG16_MACRO(g) ((unsigned)(g) >> (SK_G32_BITS - SK_G16_BITS)) +#define SkB32ToB16_MACRO(b) ((unsigned)(b) >> (SK_B32_BITS - SK_B16_BITS)) + +#ifdef SK_DEBUG + static inline unsigned SkR32ToR16(unsigned r) { + SkR32Assert(r); + return SkR32ToR16_MACRO(r); + } + static inline unsigned SkG32ToG16(unsigned g) { + SkG32Assert(g); + return SkG32ToG16_MACRO(g); + } + static inline unsigned SkB32ToB16(unsigned b) { + SkB32Assert(b); + return SkB32ToB16_MACRO(b); + } +#else + #define SkR32ToR16(r) SkR32ToR16_MACRO(r) + #define SkG32ToG16(g) SkG32ToG16_MACRO(g) + #define SkB32ToB16(b) SkB32ToB16_MACRO(b) +#endif + +static inline U16CPU SkPixel32ToPixel16(SkPMColor c) { + unsigned r = ((c >> (SK_R32_SHIFT + (8 - SK_R16_BITS))) & SK_R16_MASK) << SK_R16_SHIFT; + unsigned g = ((c >> (SK_G32_SHIFT + (8 - SK_G16_BITS))) & SK_G16_MASK) << SK_G16_SHIFT; + unsigned b = ((c >> (SK_B32_SHIFT + (8 - SK_B16_BITS))) & SK_B16_MASK) << SK_B16_SHIFT; + return r | g | b; +} + +static inline U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b) { + return (SkR32ToR16(r) << SK_R16_SHIFT) | + (SkG32ToG16(g) << SK_G16_SHIFT) | + (SkB32ToB16(b) << SK_B16_SHIFT); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static inline SkColor SkPixel16ToColor(U16CPU src) { + SkASSERT(src == SkToU16(src)); + + unsigned r = SkPacked16ToR32(src); + unsigned g = SkPacked16ToG32(src); + unsigned b = SkPacked16ToB32(src); + + SkASSERT((r >> (8 - SK_R16_BITS)) == SkGetPackedR16(src)); + SkASSERT((g >> (8 - SK_G16_BITS)) == SkGetPackedG16(src)); + SkASSERT((b >> (8 - SK_B16_BITS)) == SkGetPackedB16(src)); + + return SkColorSetRGB(r, g, b); +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef uint16_t SkPMColor16; + +// Put in OpenGL order (r g b a) +#define SK_A4444_SHIFT 0 +#define SK_R4444_SHIFT 12 +#define SK_G4444_SHIFT 8 +#define SK_B4444_SHIFT 4 + +static inline U8CPU SkReplicateNibble(unsigned nib) { + SkASSERT(nib <= 0xF); + return (nib << 4) | nib; +} + +#define SkGetPackedA4444(c) (((unsigned)(c) >> SK_A4444_SHIFT) & 0xF) +#define SkGetPackedR4444(c) (((unsigned)(c) >> SK_R4444_SHIFT) & 0xF) +#define SkGetPackedG4444(c) (((unsigned)(c) >> SK_G4444_SHIFT) & 0xF) +#define SkGetPackedB4444(c) (((unsigned)(c) >> SK_B4444_SHIFT) & 0xF) + +#define SkPacked4444ToA32(c) SkReplicateNibble(SkGetPackedA4444(c)) + +static inline SkPMColor SkPixel4444ToPixel32(U16CPU c) { + uint32_t d = (SkGetPackedA4444(c) << SK_A32_SHIFT) | + (SkGetPackedR4444(c) << SK_R32_SHIFT) | + (SkGetPackedG4444(c) << SK_G32_SHIFT) | + (SkGetPackedB4444(c) << SK_B32_SHIFT); + return d | (d << 4); +} + +using SkPMColor4f = SkRGBA4f; + +constexpr SkPMColor4f SK_PMColor4fTRANSPARENT = { 0, 0, 0, 0 }; +constexpr SkPMColor4f SK_PMColor4fBLACK = { 0, 0, 0, 1 }; +constexpr SkPMColor4f SK_PMColor4fWHITE = { 1, 1, 1, 1 }; +constexpr SkPMColor4f SK_PMColor4fILLEGAL = { SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity }; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkEncodedInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkEncodedInfo.h new file mode 100644 index 00000000000000..74e2ad1480cefe --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkEncodedInfo.h @@ -0,0 +1,272 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEncodedInfo_DEFINED +#define SkEncodedInfo_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkColorSpace.h" +#include "include/core/SkColorType.h" +#include "include/core/SkData.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "modules/skcms/skcms.h" + +#include +#include +#include + +struct SkEncodedInfo { +public: + class ICCProfile { + public: + static std::unique_ptr Make(sk_sp); + static std::unique_ptr Make(const skcms_ICCProfile&); + + const skcms_ICCProfile* profile() const { return &fProfile; } + private: + ICCProfile(const skcms_ICCProfile&, sk_sp = nullptr); + + skcms_ICCProfile fProfile; + sk_sp fData; + }; + + enum Alpha { + kOpaque_Alpha, + kUnpremul_Alpha, + + // Each pixel is either fully opaque or fully transparent. + // There is no difference between requesting kPremul or kUnpremul. + kBinary_Alpha, + }; + + /* + * We strive to make the number of components per pixel obvious through + * our naming conventions. + * Ex: kRGB has 3 components. kRGBA has 4 components. + * + * This sometimes results in redundant Alpha and Color information. + * Ex: kRGB images must also be kOpaque. + */ + enum Color { + // PNG, WBMP + kGray_Color, + + // PNG + kGrayAlpha_Color, + + // PNG with Skia-specific sBIT + // Like kGrayAlpha, except this expects to be treated as + // kAlpha_8_SkColorType, which ignores the gray component. If + // decoded to full color (e.g. kN32), the gray component is respected + // (so it can share code with kGrayAlpha). + kXAlpha_Color, + + // PNG + // 565 images may be encoded to PNG by specifying the number of + // significant bits for each channel. This is a strange 565 + // representation because the image is still encoded with 8 bits per + // component. + k565_Color, + + // PNG, GIF, BMP + kPalette_Color, + + // PNG, RAW + kRGB_Color, + kRGBA_Color, + + // BMP + kBGR_Color, + kBGRX_Color, + kBGRA_Color, + + // JPEG, WEBP + kYUV_Color, + + // WEBP + kYUVA_Color, + + // JPEG + // Photoshop actually writes inverted CMYK data into JPEGs, where zero + // represents 100% ink coverage. For this reason, we treat CMYK JPEGs + // as having inverted CMYK. libjpeg-turbo warns that this may break + // other applications, but the CMYK JPEGs we see on the web expect to + // be treated as inverted CMYK. + kInvertedCMYK_Color, + kYCCK_Color, + }; + + static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, + int bitsPerComponent) { + return Make(width, height, color, alpha, bitsPerComponent, nullptr); + } + + static SkEncodedInfo Make(int width, int height, Color color, + Alpha alpha, int bitsPerComponent, std::unique_ptr profile) { + return Make(width, height, color, alpha, /*bitsPerComponent*/ bitsPerComponent, + std::move(profile), /*colorDepth*/ bitsPerComponent); + } + + static SkEncodedInfo Make(int width, int height, Color color, + Alpha alpha, int bitsPerComponent, std::unique_ptr profile, + int colorDepth) { + SkASSERT(1 == bitsPerComponent || + 2 == bitsPerComponent || + 4 == bitsPerComponent || + 8 == bitsPerComponent || + 16 == bitsPerComponent); + + switch (color) { + case kGray_Color: + SkASSERT(kOpaque_Alpha == alpha); + break; + case kGrayAlpha_Color: + SkASSERT(kOpaque_Alpha != alpha); + break; + case kPalette_Color: + SkASSERT(16 != bitsPerComponent); + break; + case kRGB_Color: + case kBGR_Color: + case kBGRX_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(bitsPerComponent >= 8); + break; + case kYUV_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case kRGBA_Color: + SkASSERT(bitsPerComponent >= 8); + break; + case kBGRA_Color: + case kYUVA_Color: + SkASSERT(8 == bitsPerComponent); + break; + case kXAlpha_Color: + SkASSERT(kUnpremul_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case k565_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + default: + SkASSERT(false); + break; + } + + return SkEncodedInfo(width, height, color, alpha, + bitsPerComponent, colorDepth, std::move(profile)); + } + + /* + * Returns a recommended SkImageInfo. + * + * TODO: Leave this up to the client. + */ + SkImageInfo makeImageInfo() const { + auto ct = kGray_Color == fColor ? kGray_8_SkColorType : + kXAlpha_Color == fColor ? kAlpha_8_SkColorType : + k565_Color == fColor ? kRGB_565_SkColorType : + kN32_SkColorType ; + auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType + : kUnpremul_SkAlphaType; + sk_sp cs = fProfile ? SkColorSpace::Make(*fProfile->profile()) + : nullptr; + if (!cs) { + cs = SkColorSpace::MakeSRGB(); + } + return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs)); + } + + int width() const { return fWidth; } + int height() const { return fHeight; } + Color color() const { return fColor; } + Alpha alpha() const { return fAlpha; } + bool opaque() const { return fAlpha == kOpaque_Alpha; } + const skcms_ICCProfile* profile() const { + if (!fProfile) return nullptr; + return fProfile->profile(); + } + + uint8_t bitsPerComponent() const { return fBitsPerComponent; } + + uint8_t bitsPerPixel() const { + switch (fColor) { + case kGray_Color: + return fBitsPerComponent; + case kXAlpha_Color: + case kGrayAlpha_Color: + return 2 * fBitsPerComponent; + case kPalette_Color: + return fBitsPerComponent; + case kRGB_Color: + case kBGR_Color: + case kYUV_Color: + case k565_Color: + return 3 * fBitsPerComponent; + case kRGBA_Color: + case kBGRA_Color: + case kBGRX_Color: + case kYUVA_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + return 4 * fBitsPerComponent; + default: + SkASSERT(false); + return 0; + } + } + + SkEncodedInfo(const SkEncodedInfo& orig) = delete; + SkEncodedInfo& operator=(const SkEncodedInfo&) = delete; + + SkEncodedInfo(SkEncodedInfo&& orig) = default; + SkEncodedInfo& operator=(SkEncodedInfo&&) = default; + + // Explicit copy method, to avoid accidental copying. + SkEncodedInfo copy() const { + auto copy = SkEncodedInfo::Make( + fWidth, fHeight, fColor, fAlpha, fBitsPerComponent, nullptr, fColorDepth); + if (fProfile) { + copy.fProfile = std::make_unique(*fProfile); + } + return copy; + } + + // Return number of bits of R/G/B channel + uint8_t getColorDepth() const { + return fColorDepth; + } + +private: + SkEncodedInfo(int width, int height, Color color, Alpha alpha, + uint8_t bitsPerComponent, uint8_t colorDepth, std::unique_ptr profile) + : fWidth(width) + , fHeight(height) + , fColor(color) + , fAlpha(alpha) + , fBitsPerComponent(bitsPerComponent) + , fColorDepth(colorDepth) + , fProfile(std::move(profile)) + {} + + int fWidth; + int fHeight; + Color fColor; + Alpha fAlpha; + uint8_t fBitsPerComponent; + uint8_t fColorDepth; + std::unique_ptr fProfile; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkGainmapInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkGainmapInfo.h new file mode 100644 index 00000000000000..8cf511a10c2659 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkGainmapInfo.h @@ -0,0 +1,97 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGainmapInfo_DEFINED +#define SkGainmapInfo_DEFINED + +#include "include/core/SkColor.h" + +/** + * Gainmap rendering parameters. Suppose our display has HDR to SDR ratio of H and we wish to + * display an image with gainmap on this display. Let B be the pixel value from the base image + * in a color space that has the primaries of the base image and a linear transfer function. Let + * G be the pixel value from the gainmap. Let D be the output pixel in the same color space as B. + * The value of D is computed as follows: + * + * First, let W be a weight parameter determing how much the gainmap will be applied. + * W = clamp((log(H) - log(fDisplayRatioSdr)) / + * (log(fDisplayRatioHdr) - log(fDisplayRatioSdr), 0, 1) + * + * Next, let L be the gainmap value in log space. We compute this from the value G that was + * sampled from the texture as follows: + * L = mix(log(fGainmapRatioMin), log(fGainmapRatioMax), pow(G, fGainmapGamma)) + * + * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then + * compute: + * D = (B + fEpsilonSdr) * exp(L * W) - fEpsilonHdr + * If the base image is HDR then compute: + * D = (B + fEpsilonHdr) * exp(L * (W - 1)) - fEpsilonSdr + * + * In the above math, log() is a natural logarithm and exp() is natural exponentiation. Note, + * however, that the base used for the log() and exp() functions does not affect the results of + * the computation (it cancels out, as long as the same base is used throughout). + */ +struct SkGainmapInfo { + /** + * Parameters for converting the gainmap from its image encoding to log space. These are + * specified per color channel. The alpha value is unused. + */ + SkColor4f fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0}; + SkColor4f fGainmapRatioMax = {2.f, 2.f, 2.f, 1.0}; + SkColor4f fGainmapGamma = {1.f, 1.f, 1.f, 1.f}; + + /** + * Parameters sometimes used in gainmap computation to avoid numerical instability. + */ + SkColor4f fEpsilonSdr = {0.f, 0.f, 0.f, 1.0}; + SkColor4f fEpsilonHdr = {0.f, 0.f, 0.f, 1.0}; + + /** + * If the output display's HDR to SDR ratio is less or equal than fDisplayRatioSdr then the SDR + * rendition is displayed. If the output display's HDR to SDR ratio is greater or equal than + * fDisplayRatioHdr then the HDR rendition is displayed. If the output display's HDR to SDR + * ratio is between these values then an interpolation between the two is displayed using the + * math above. + */ + float fDisplayRatioSdr = 1.f; + float fDisplayRatioHdr = 2.f; + + /** + * Whether the base image is the SDR image or the HDR image. + */ + enum class BaseImageType { + kSDR, + kHDR, + }; + BaseImageType fBaseImageType = BaseImageType::kSDR; + + inline bool operator==(const SkGainmapInfo& other) { + return fGainmapRatioMin == other.fGainmapRatioMin && + fGainmapRatioMax == other.fGainmapRatioMax && fGainmapGamma == other.fGainmapGamma && + fEpsilonSdr == other.fEpsilonSdr && fEpsilonHdr == other.fEpsilonHdr && + fDisplayRatioSdr == other.fDisplayRatioSdr && + fDisplayRatioHdr == other.fDisplayRatioHdr && fBaseImageType == other.fBaseImageType; + } + inline bool operator!=(const SkGainmapInfo& other) { return !(*this == other); } + + // TODO(ccameron): Remove these parameters once we are certain they are not used in Android. + enum class Type { + kUnknown, + kMultiPicture, + kJpegR_Linear, + kJpegR_HLG, + kJpegR_PQ, + kHDRGM, + }; + SkColor4f fLogRatioMin = {0.f, 0.f, 0.f, 1.0}; + SkColor4f fLogRatioMax = {1.f, 1.f, 1.f, 1.0}; + float fHdrRatioMin = 1.f; + float fHdrRatioMax = 50.f; + Type fType = Type::kUnknown; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkGainmapShader.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkGainmapShader.h new file mode 100644 index 00000000000000..f490ab96a4cfc9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkGainmapShader.h @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGainmapShader_DEFINED +#define SkGainmapShader_DEFINED + +#include "include/core/SkRefCnt.h" + +class SkColorSpace; +class SkShader; +class SkImage; +struct SkGainmapInfo; +struct SkRect; +struct SkSamplingOptions; + +/** + * A gainmap shader will apply a gainmap to an base image using the math described alongside the + * definition of SkGainmapInfo. + */ +class SK_API SkGainmapShader { +public: + /** + * Make a gainmap shader. + * + * When sampling the base image baseImage, the rectangle baseRect will be sampled to map to + * the rectangle dstRect. Sampling will be done according to baseSamplingOptions. + * + * When sampling the gainmap image gainmapImage, the rectangle gainmapRect will be sampled to + * map to the rectangle dstRect. Sampling will be done according to gainmapSamplingOptions. + * + * The gainmap will be applied according to the HDR to SDR ratio specified in dstHdrRatio. + * + * This shader must know the color space of the canvas that it will be rendered to. This color + * space must be specified in dstColorSpace. + * TODO(ccameron): Remove the need for dstColorSpace. + */ + static sk_sp Make(const sk_sp& baseImage, + const SkRect& baseRect, + const SkSamplingOptions& baseSamplingOptions, + const sk_sp& gainmapImage, + const SkRect& gainmapRect, + const SkSamplingOptions& gainmapSamplingOptions, + const SkGainmapInfo& gainmapInfo, + const SkRect& dstRect, + float dstHdrRatio, + sk_sp dstColorSpace); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkIDChangeListener.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkIDChangeListener.h new file mode 100644 index 00000000000000..8ebb6ca18e53f6 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkIDChangeListener.h @@ -0,0 +1,76 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkIDChangeListener_DEFINED +#define SkIDChangeListener_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkMutex.h" +#include "include/private/base/SkTArray.h" +#include "include/private/base/SkThreadAnnotations.h" + +#include + +/** + * Used to be notified when a gen/unique ID is invalidated, typically to preemptively purge + * associated items from a cache that are no longer reachable. The listener can + * be marked for deregistration if the cached item is remove before the listener is + * triggered. This prevents unbounded listener growth when cache items are routinely + * removed before the gen ID/unique ID is invalidated. + */ +class SkIDChangeListener : public SkRefCnt { +public: + SkIDChangeListener(); + + ~SkIDChangeListener() override; + + virtual void changed() = 0; + + /** + * Mark the listener is no longer needed. It should be removed and changed() should not be + * called. + */ + void markShouldDeregister() { fShouldDeregister.store(true, std::memory_order_relaxed); } + + /** Indicates whether markShouldDeregister was called. */ + bool shouldDeregister() { return fShouldDeregister.load(std::memory_order_acquire); } + + /** Manages a list of SkIDChangeListeners. */ + class List { + public: + List(); + + ~List(); + + /** + * Add a new listener to the list. It must not already be deregistered. Also clears out + * previously deregistered listeners. + */ + void add(sk_sp listener) SK_EXCLUDES(fMutex); + + /** + * The number of registered listeners (including deregisterd listeners that are yet-to-be + * removed. + */ + int count() const SK_EXCLUDES(fMutex); + + /** Calls changed() on all listeners that haven't been deregistered and resets the list. */ + void changed() SK_EXCLUDES(fMutex); + + /** Resets without calling changed() on the listeners. */ + void reset() SK_EXCLUDES(fMutex); + + private: + mutable SkMutex fMutex; + skia_private::STArray<1, sk_sp> fListeners SK_GUARDED_BY(fMutex); + }; + +private: + std::atomic fShouldDeregister; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkJpegGainmapEncoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkJpegGainmapEncoder.h new file mode 100644 index 00000000000000..756de78b231010 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkJpegGainmapEncoder.h @@ -0,0 +1,71 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJpegGainmapEncoder_DEFINED +#define SkJpegGainmapEncoder_DEFINED + +#include "include/encode/SkJpegEncoder.h" + +class SkPixmap; +class SkWStream; +struct SkGainmapInfo; + +class SK_API SkJpegGainmapEncoder { +public: + /** + * Encode a JpegR image to |dst|. + * + * The base image is specified by |base|, and |baseOptions| controls the encoding behavior for + * the base image. + * + * The gainmap image is specified by |gainmap|, and |gainmapOptions| controls the encoding + * behavior for the gainmap image. + * + * The rendering behavior of the gainmap image is provided in |gainmapInfo|. Not all gainmap + * based images are compatible with JpegR. If the image is not compatible with JpegR, then + * convert the gainmap to a format that is capable with JpegR. This conversion may result in + * less precise quantization of the gainmap image. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ + static bool EncodeJpegR(SkWStream* dst, + const SkPixmap& base, + const SkJpegEncoder::Options& baseOptions, + const SkPixmap& gainmap, + const SkJpegEncoder::Options& gainmapOptions, + const SkGainmapInfo& gainmapInfo); + + /** + * Encode an HDRGM image to |dst|. + * + * The base image is specified by |base|, and |baseOptions| controls the encoding behavior for + * the base image. + * + * The gainmap image is specified by |gainmap|, and |gainmapOptions| controls the encoding + * behavior for the gainmap image. + * + * The rendering behavior of the gainmap image is provided in |gainmapInfo|. + * + * If |baseOptions| or |gainmapOptions| specify XMP metadata, then that metadata will be + * overwritten. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ + static bool EncodeHDRGM(SkWStream* dst, + const SkPixmap& base, + const SkJpegEncoder::Options& baseOptions, + const SkPixmap& gainmap, + const SkJpegEncoder::Options& gainmapOptions, + const SkGainmapInfo& gainmapInfo); + + /** + * Write a Multi Picture Format containing the |imageCount| images specified by |images|. + */ + static bool MakeMPF(SkWStream* dst, const SkData** images, size_t imageCount); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkJpegMetadataDecoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkJpegMetadataDecoder.h new file mode 100644 index 00000000000000..0b8f6ce1f7577b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkJpegMetadataDecoder.h @@ -0,0 +1,61 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJpegMetadataDecoder_DEFINED +#define SkJpegMetadataDecoder_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include +#include + +struct SkGainmapInfo; + +/** + * An interface that can be used to extract metadata from an encoded JPEG file. + * TODO(https://crbug.com/1404000): Add interface for ICC profile and EXIF extraction. + */ +class SK_API SkJpegMetadataDecoder { +public: + SkJpegMetadataDecoder() {} + virtual ~SkJpegMetadataDecoder() {} + + SkJpegMetadataDecoder(const SkJpegMetadataDecoder&) = delete; + SkJpegMetadataDecoder& operator=(const SkJpegMetadataDecoder&) = delete; + + /** + * A segment from a JPEG file. This is usually populated from a jpeg_marker_struct. + */ + struct SK_API Segment { + Segment(uint8_t marker, sk_sp data) : fMarker(marker), fData(std::move(data)) {} + + // The segment's marker. + uint8_t fMarker = 0; + + // The segment's parameters (not including the marker and parameter length). + sk_sp fData; + }; + + /** + * Create metadata for the specified segments from a JPEG file's header (defined as all segments + * before the first StartOfScan). This may return nullptr. + */ + static std::unique_ptr Make(std::vector headerSegments); + + /** + * Given a JPEG encoded image |baseImageData|, return in |outGainmapImageData| the JPEG encoded + * gainmap image and return in |outGainmapInfo| its gainmap rendering parameters. Return true if + * both output variables were successfully populated, otherwise return false. + */ + virtual bool findGainmapImage(sk_sp baseImageData, + sk_sp& outGainmapImagedata, + SkGainmapInfo& outGainmapInfo) = 0; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkOpts_spi.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkOpts_spi.h new file mode 100644 index 00000000000000..6e888b77c84c31 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkOpts_spi.h @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOpts_spi_DEFINED +#define SkOpts_spi_DEFINED + +#include "include/private/base/SkAPI.h" + +#include + +// These are exposed as SK_SPI (e.g. SkParagraph), the rest of SkOpts is +// declared in src/core + +namespace SkOpts { + // The fastest high quality 32-bit hash we can provide on this platform. + extern uint32_t SK_SPI (*hash_fn)(const void* data, size_t bytes, uint32_t seed); +} // namespace SkOpts + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkPathRef.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkPathRef.h new file mode 100644 index 00000000000000..c0e0f08aa1bd9f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkPathRef.h @@ -0,0 +1,539 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPathRef_DEFINED +#define SkPathRef_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/SkIDChangeListener.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkTArray.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include +#include + +class SkMatrix; +class SkRRect; + +// These are computed from a stream of verbs +struct SkPathVerbAnalysis { + bool valid; + int points, weights; + unsigned segmentMask; +}; +SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t verbs[], int count); + + +/** + * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods + * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an + * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs + * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's + * constructor a pointer to a sk_sp, which may be updated to point to a new SkPathRef + * after the editor's constructor returns. + * + * The points and verbs are stored in a single allocation. The points are at the begining of the + * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points + * and verbs both grow into the middle of the allocation until the meet. To access verb i in the + * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first + * logical verb or the last verb in memory). + */ + +class SK_API SkPathRef final : public SkNVRefCnt { +public: + // See https://bugs.chromium.org/p/skia/issues/detail?id=13817 for how these sizes were + // determined. + using PointsArray = skia_private::STArray<4, SkPoint>; + using VerbsArray = skia_private::STArray<4, uint8_t>; + using ConicWeightsArray = skia_private::STArray<2, SkScalar>; + + SkPathRef(PointsArray points, VerbsArray verbs, ConicWeightsArray weights, + unsigned segmentMask) + : fPoints(std::move(points)) + , fVerbs(std::move(verbs)) + , fConicWeights(std::move(weights)) + { + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = 0; // recompute + fSegmentMask = segmentMask; + fIsOval = false; + fIsRRect = false; + // The next two values don't matter unless fIsOval or fIsRRect are true. + fRRectOrOvalIsCCW = false; + fRRectOrOvalStartIdx = 0xAC; + SkDEBUGCODE(fEditorsAttached.store(0);) + + this->computeBounds(); // do this now, before we worry about multiple owners/threads + SkDEBUGCODE(this->validate();) + } + + class Editor { + public: + Editor(sk_sp* pathRef, + int incReserveVerbs = 0, + int incReservePoints = 0); + + ~Editor() { SkDEBUGCODE(fPathRef->fEditorsAttached--;) } + + /** + * Returns the array of points. + */ + SkPoint* writablePoints() { return fPathRef->getWritablePoints(); } + const SkPoint* points() const { return fPathRef->points(); } + + /** + * Gets the ith point. Shortcut for this->points() + i + */ + SkPoint* atPoint(int i) { return fPathRef->getWritablePoints() + i; } + const SkPoint* atPoint(int i) const { return &fPathRef->fPoints[i]; } + + /** + * Adds the verb and allocates space for the number of points indicated by the verb. The + * return value is a pointer to where the points for the verb should be written. + * 'weight' is only used if 'verb' is kConic_Verb + */ + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) { + SkDEBUGCODE(fPathRef->validate();) + return fPathRef->growForVerb(verb, weight); + } + + /** + * Allocates space for multiple instances of a particular verb and the + * requisite points & weights. + * The return pointer points at the first new point (indexed normally []). + * If 'verb' is kConic_Verb, 'weights' will return a pointer to the + * space for the conic weights (indexed normally). + */ + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, + int numVbs, + SkScalar** weights = nullptr) { + return fPathRef->growForRepeatedVerb(verb, numVbs, weights); + } + + /** + * Concatenates all verbs from 'path' onto the pathRef's verbs array. Increases the point + * count by the number of points in 'path', and the conic weight count by the number of + * conics in 'path'. + * + * Returns pointers to the uninitialized points and conic weights data. + */ + std::tuple growForVerbsInPath(const SkPathRef& path) { + return fPathRef->growForVerbsInPath(path); + } + + /** + * Resets the path ref to a new verb and point count. The new verbs and points are + * uninitialized. + */ + void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { + fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); + } + + /** + * Gets the path ref that is wrapped in the Editor. + */ + SkPathRef* pathRef() { return fPathRef; } + + void setIsOval(bool isOval, bool isCCW, unsigned start) { + fPathRef->setIsOval(isOval, isCCW, start); + } + + void setIsRRect(bool isRRect, bool isCCW, unsigned start) { + fPathRef->setIsRRect(isRRect, isCCW, start); + } + + void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } + + private: + SkPathRef* fPathRef; + }; + + class SK_API Iter { + public: + Iter(); + Iter(const SkPathRef&); + + void setPathRef(const SkPathRef&); + + /** Return the next verb in this iteration of the path. When all + segments have been visited, return kDone_Verb. + + If any point in the path is non-finite, return kDone_Verb immediately. + + @param pts The points representing the current verb and/or segment + This must not be NULL. + @return The verb for the current segment + */ + uint8_t next(SkPoint pts[4]); + uint8_t peek() const; + + SkScalar conicWeight() const { return *fConicWeights; } + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + const SkScalar* fConicWeights; + }; + +public: + /** + * Gets a path ref with no verbs or points. + */ + static SkPathRef* CreateEmpty(); + + /** + * Returns true if all of the points in this path are finite, meaning there + * are no infinities and no NaNs. + */ + bool isFinite() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return SkToBool(fIsFinite); + } + + /** + * Returns a mask, where each bit corresponding to a SegmentMask is + * set if the path contains 1 or more segments of that type. + * Returns 0 for an empty path (no segments). + */ + uint32_t getSegmentMasks() const { return fSegmentMask; } + + /** Returns true if the path is an oval. + * + * @param rect returns the bounding rect of this oval. It's a circle + * if the height and width are the same. + * @param isCCW is the oval CCW (or CW if false). + * @param start indicates where the contour starts on the oval (see + * SkPath::addOval for intepretation of the index). + * + * @return true if this path is an oval. + * Tracking whether a path is an oval is considered an + * optimization for performance and so some paths that are in + * fact ovals can report false. + */ + bool isOval(SkRect* rect, bool* isCCW, unsigned* start) const { + if (fIsOval) { + if (rect) { + *rect = this->getBounds(); + } + if (isCCW) { + *isCCW = SkToBool(fRRectOrOvalIsCCW); + } + if (start) { + *start = fRRectOrOvalStartIdx; + } + } + + return SkToBool(fIsOval); + } + + bool isRRect(SkRRect* rrect, bool* isCCW, unsigned* start) const; + + bool hasComputedBounds() const { + return !fBoundsIsDirty; + } + + /** Returns the bounds of the path's points. If the path contains 0 or 1 + points, the bounds is set to (0,0,0,0), and isEmpty() will return true. + Note: this bounds may be larger than the actual shape, since curves + do not extend as far as their control points. + */ + const SkRect& getBounds() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return fBounds; + } + + SkRRect getRRect() const; + + /** + * Transforms a path ref by a matrix, allocating a new one only if necessary. + */ + static void CreateTransformedCopy(sk_sp* dst, + const SkPathRef& src, + const SkMatrix& matrix); + + // static SkPathRef* CreateFromBuffer(SkRBuffer* buffer); + + /** + * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be + * repopulated with approximately the same number of verbs and points. A new path ref is created + * only if necessary. + */ + static void Rewind(sk_sp* pathRef); + + ~SkPathRef(); + int countPoints() const { return fPoints.size(); } + int countVerbs() const { return fVerbs.size(); } + int countWeights() const { return fConicWeights.size(); } + + size_t approximateBytesUsed() const; + + /** + * Returns a pointer one beyond the first logical verb (last verb in memory order). + */ + const uint8_t* verbsBegin() const { return fVerbs.begin(); } + + /** + * Returns a const pointer to the first verb in memory (which is the last logical verb). + */ + const uint8_t* verbsEnd() const { return fVerbs.end(); } + + /** + * Returns a const pointer to the first point. + */ + const SkPoint* points() const { return fPoints.begin(); } + + /** + * Shortcut for this->points() + this->countPoints() + */ + const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } + + const SkScalar* conicWeights() const { return fConicWeights.begin(); } + const SkScalar* conicWeightsEnd() const { return fConicWeights.end(); } + + /** + * Convenience methods for getting to a verb or point by index. + */ + uint8_t atVerb(int index) const { return fVerbs[index]; } + const SkPoint& atPoint(int index) const { return fPoints[index]; } + + bool operator== (const SkPathRef& ref) const; + + void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const; + + /** + * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the + * same ID then they have the same verbs and points. However, two path refs may have the same + * contents but different genIDs. + * skbug.com/1762 for background on why fillType is necessary (for now). + */ + uint32_t genID(uint8_t fillType) const; + + void addGenIDChangeListener(sk_sp); // Threadsafe. + int genIDChangeListenerCount(); // Threadsafe + + bool dataMatchesVerbs() const; + bool isValid() const; + SkDEBUGCODE(void validate() const { SkASSERT(this->isValid()); } ) + + /** + * Resets this SkPathRef to a clean state. + */ + void reset(); + + bool isInitialEmptyPathRef() const { + return fGenerationID == kEmptyGenID; + } + +private: + enum SerializationOffsets { + kLegacyRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits, ignored. + kLegacyRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit, ignored. + kLegacyIsRRect_SerializationShift = 26, // requires 1 bit, ignored. + kIsFinite_SerializationShift = 25, // requires 1 bit + kLegacyIsOval_SerializationShift = 24, // requires 1 bit, ignored. + kSegmentMask_SerializationShift = 0 // requires 4 bits (deprecated) + }; + + SkPathRef(int numVerbs = 0, int numPoints = 0) { + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = kEmptyGenID; + fSegmentMask = 0; + fIsOval = false; + fIsRRect = false; + // The next two values don't matter unless fIsOval or fIsRRect are true. + fRRectOrOvalIsCCW = false; + fRRectOrOvalStartIdx = 0xAC; + if (numPoints > 0) + fPoints.reserve_back(numPoints); + if (numVerbs > 0) + fVerbs.reserve_back(numVerbs); + SkDEBUGCODE(fEditorsAttached.store(0);) + SkDEBUGCODE(this->validate();) + } + + void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints); + + // Return true if the computed bounds are finite. + static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { + return bounds->setBoundsCheck(ref.points(), ref.countPoints()); + } + + // called, if dirty, by getBounds() + void computeBounds() const { + SkDEBUGCODE(this->validate();) + // TODO(mtklein): remove fBoundsIsDirty and fIsFinite, + // using an inverted rect instead of fBoundsIsDirty and always recalculating fIsFinite. + SkASSERT(fBoundsIsDirty); + + fIsFinite = ComputePtBounds(&fBounds, *this); + fBoundsIsDirty = false; + } + + void setBounds(const SkRect& rect) { + SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); + fBounds = rect; + fBoundsIsDirty = false; + fIsFinite = fBounds.isFinite(); + } + + /** Makes additional room but does not change the counts or change the genID */ + void incReserve(int additionalVerbs, int additionalPoints) { + SkDEBUGCODE(this->validate();) + // Use reserve() so that if there is not enough space, the array will grow with some + // additional space. This ensures repeated calls to grow won't always allocate. + if (additionalPoints > 0) + fPoints.reserve(fPoints.size() + additionalPoints); + if (additionalVerbs > 0) + fVerbs.reserve(fVerbs.size() + additionalVerbs); + SkDEBUGCODE(this->validate();) + } + + /** + * Resets all state except that of the verbs, points, and conic-weights. + * Intended to be called from other functions that reset state. + */ + void commonReset() { + SkDEBUGCODE(this->validate();) + this->callGenIDChangeListeners(); + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = 0; + + fSegmentMask = 0; + fIsOval = false; + fIsRRect = false; + } + + /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also + * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ + void resetToSize(int verbCount, int pointCount, int conicCount, + int reserveVerbs = 0, int reservePoints = 0) { + commonReset(); + // Use reserve_back() so the arrays are sized to exactly fit the data. + const int pointDelta = pointCount + reservePoints - fPoints.size(); + if (pointDelta > 0) { + fPoints.reserve_back(pointDelta); + } + fPoints.resize_back(pointCount); + const int verbDelta = verbCount + reserveVerbs - fVerbs.size(); + if (verbDelta > 0) { + fVerbs.reserve_back(verbDelta); + } + fVerbs.resize_back(verbCount); + fConicWeights.resize_back(conicCount); + SkDEBUGCODE(this->validate();) + } + + /** + * Increases the verb count by numVbs and point count by the required amount. + * The new points are uninitialized. All the new verbs are set to the specified + * verb. If 'verb' is kConic_Verb, 'weights' will return a pointer to the + * uninitialized conic weights. + */ + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights); + + /** + * Increases the verb count 1, records the new verb, and creates room for the requisite number + * of additional points. A pointer to the first point is returned. Any new points are + * uninitialized. + */ + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight); + + /** + * Concatenates all verbs from 'path' onto our own verbs array. Increases the point count by the + * number of points in 'path', and the conic weight count by the number of conics in 'path'. + * + * Returns pointers to the uninitialized points and conic weights data. + */ + std::tuple growForVerbsInPath(const SkPathRef& path); + + /** + * Private, non-const-ptr version of the public function verbsMemBegin(). + */ + uint8_t* verbsBeginWritable() { return fVerbs.begin(); } + + /** + * Called the first time someone calls CreateEmpty to actually create the singleton. + */ + friend SkPathRef* sk_create_empty_pathref(); + + void setIsOval(bool isOval, bool isCCW, unsigned start) { + fIsOval = isOval; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = SkToU8(start); + } + + void setIsRRect(bool isRRect, bool isCCW, unsigned start) { + fIsRRect = isRRect; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = SkToU8(start); + } + + // called only by the editor. Note that this is not a const function. + SkPoint* getWritablePoints() { + SkDEBUGCODE(this->validate();) + fIsOval = false; + fIsRRect = false; + return fPoints.begin(); + } + + const SkPoint* getPoints() const { + SkDEBUGCODE(this->validate();) + return fPoints.begin(); + } + + void callGenIDChangeListeners(); + + enum { + kMinSize = 256, + }; + + mutable SkRect fBounds; + + PointsArray fPoints; + VerbsArray fVerbs; + ConicWeightsArray fConicWeights; + + enum { + kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. + }; + mutable uint32_t fGenerationID; + SkDEBUGCODE(std::atomic fEditorsAttached;) // assert only one editor in use at any time. + + SkIDChangeListener::List fGenIDChangeListeners; + + mutable uint8_t fBoundsIsDirty; + mutable bool fIsFinite; // only meaningful if bounds are valid + + bool fIsOval; + bool fIsRRect; + // Both the circle and rrect special cases have a notion of direction and starting point + // The next two variables store that information for either. + bool fRRectOrOvalIsCCW; + uint8_t fRRectOrOvalStartIdx; + uint8_t fSegmentMask; + + friend class PathRefTest_Private; + friend class ForceIsRRect_Private; // unit test isRRect + friend class SkPath; + friend class SkPathBuilder; + friend class SkPathPriv; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSLDefines.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSLDefines.h new file mode 100644 index 00000000000000..058b231b138a32 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSLDefines.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_DEFINES +#define SKSL_DEFINES + +#include + +#include "include/core/SkTypes.h" +#include "include/private/base/SkTArray.h" + +using SKSL_INT = int64_t; +using SKSL_FLOAT = float; + +namespace SkSL { + +class Expression; +class Statement; + +using ComponentArray = skia_private::STArray<4, int8_t>; // for Swizzles + +class ExpressionArray : public skia_private::STArray<2, std::unique_ptr> { +public: + using STArray::STArray; + + /** Returns a new ExpressionArray containing a clone of every element. */ + ExpressionArray clone() const; +}; + +using StatementArray = skia_private::STArray<2, std::unique_ptr>; + +// Functions larger than this (measured in IR nodes) will not be inlined. This growth factor +// accounts for the number of calls being inlined--i.e., a function called five times (that is, with +// five inlining opportunities) would be considered 5x larger than if it were called once. This +// default threshold value is arbitrary, but tends to work well in practice. +static constexpr int kDefaultInlineThreshold = 50; + +// A hard upper limit on the number of variable slots allowed in a function/global scope. +// This is an arbitrary limit, but is needed to prevent code generation from taking unbounded +// amounts of time or space. +static constexpr int kVariableSlotLimit = 100000; + +// The SwizzleComponent namespace is used both by the SkSL::Swizzle expression, and the DSL swizzle. +// This namespace is injected into SkSL::dsl so that `using namespace SkSL::dsl` enables DSL code +// like `Swizzle(var, X, Y, ONE)` to compile without any extra qualifications. +namespace SwizzleComponent { + +enum Type : int8_t { + X = 0, Y = 1, Z = 2, W = 3, + R = 4, G = 5, B = 6, A = 7, + S = 8, T = 9, P = 10, Q = 11, + UL = 12, UT = 13, UR = 14, UB = 15, + ZERO, + ONE +}; + +} // namespace SwizzleComponent +} // namespace SkSL + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSLSampleUsage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSLSampleUsage.h new file mode 100644 index 00000000000000..39d9e258180e8b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSLSampleUsage.h @@ -0,0 +1,85 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSLSampleUsage_DEFINED +#define SkSLSampleUsage_DEFINED + +#include "include/core/SkTypes.h" + +namespace SkSL { + +/** + * Represents all of the ways that a fragment processor is sampled by its parent. + */ +class SampleUsage { +public: + enum class Kind { + // Child is never sampled + kNone, + // Child is only sampled at the same coordinates as the parent + kPassThrough, + // Child is sampled with a matrix whose value is uniform + kUniformMatrix, + // Child is sampled with sk_FragCoord.xy + kFragCoord, + // Child is sampled using explicit coordinates + kExplicit, + }; + + // Make a SampleUsage that corresponds to no sampling of the child at all + SampleUsage() = default; + + SampleUsage(Kind kind, bool hasPerspective) : fKind(kind), fHasPerspective(hasPerspective) { + if (kind != Kind::kUniformMatrix) { + SkASSERT(!fHasPerspective); + } + } + + // Child is sampled with a matrix whose value is uniform. The name is fixed. + static SampleUsage UniformMatrix(bool hasPerspective) { + return SampleUsage(Kind::kUniformMatrix, hasPerspective); + } + + static SampleUsage Explicit() { + return SampleUsage(Kind::kExplicit, false); + } + + static SampleUsage PassThrough() { + return SampleUsage(Kind::kPassThrough, false); + } + + static SampleUsage FragCoord() { return SampleUsage(Kind::kFragCoord, false); } + + bool operator==(const SampleUsage& that) const { + return fKind == that.fKind && fHasPerspective == that.fHasPerspective; + } + + bool operator!=(const SampleUsage& that) const { return !(*this == that); } + + // Arbitrary name used by all uniform sampling matrices + static const char* MatrixUniformName() { return "matrix"; } + + SampleUsage merge(const SampleUsage& other); + + Kind kind() const { return fKind; } + + bool hasPerspective() const { return fHasPerspective; } + + bool isSampled() const { return fKind != Kind::kNone; } + bool isPassThrough() const { return fKind == Kind::kPassThrough; } + bool isExplicit() const { return fKind == Kind::kExplicit; } + bool isUniformMatrix() const { return fKind == Kind::kUniformMatrix; } + bool isFragCoord() const { return fKind == Kind::kFragCoord; } + +private: + Kind fKind = Kind::kNone; + bool fHasPerspective = false; // Only valid if fKind is kUniformMatrix +}; + +} // namespace SkSL + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkShadowFlags.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkShadowFlags.h new file mode 100644 index 00000000000000..99ed6cb8a03f1a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkShadowFlags.h @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkShadowFlags_DEFINED +#define SkShadowFlags_DEFINED + +// A set of flags shared between the SkAmbientShadowMaskFilter and the SkSpotShadowMaskFilter +enum SkShadowFlags { + kNone_ShadowFlag = 0x00, + /** The occluding object is not opaque. Knowing that the occluder is opaque allows + * us to cull shadow geometry behind it and improve performance. */ + kTransparentOccluder_ShadowFlag = 0x01, + /** Don't try to use analytic shadows. */ + kGeometricOnly_ShadowFlag = 0x02, + /** Light position represents a direction, light radius is blur radius at elevation 1 */ + kDirectionalLight_ShadowFlag = 0x04, + /** Concave paths will only use blur to generate the shadow */ + kConcaveBlurOnly_ShadowFlag = 0x08, + /** mask for all shadow flags */ + kAll_ShadowFlag = 0x0F +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSpinlock.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSpinlock.h new file mode 100644 index 00000000000000..3816dc9dff0226 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkSpinlock.h @@ -0,0 +1,57 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSpinlock_DEFINED +#define SkSpinlock_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/base/SkThreadAnnotations.h" +#include + +class SK_CAPABILITY("mutex") SkSpinlock { +public: + constexpr SkSpinlock() = default; + + void acquire() SK_ACQUIRE() { + // To act as a mutex, we need an acquire barrier when we acquire the lock. + if (fLocked.exchange(true, std::memory_order_acquire)) { + // Lock was contended. Fall back to an out-of-line spin loop. + this->contendedAcquire(); + } + } + + // Acquire the lock or fail (quickly). Lets the caller decide to do something other than wait. + bool tryAcquire() SK_TRY_ACQUIRE(true) { + // To act as a mutex, we need an acquire barrier when we acquire the lock. + if (fLocked.exchange(true, std::memory_order_acquire)) { + // Lock was contended. Let the caller decide what to do. + return false; + } + return true; + } + + void release() SK_RELEASE_CAPABILITY() { + // To act as a mutex, we need a release barrier when we release the lock. + fLocked.store(false, std::memory_order_release); + } + +private: + SK_API void contendedAcquire(); + + std::atomic fLocked{false}; +}; + +class SK_SCOPED_CAPABILITY SkAutoSpinlock { +public: + SkAutoSpinlock(SkSpinlock& mutex) SK_ACQUIRE(mutex) : fSpinlock(mutex) { fSpinlock.acquire(); } + ~SkAutoSpinlock() SK_RELEASE_CAPABILITY() { fSpinlock.release(); } + +private: + SkSpinlock& fSpinlock; +}; + +#endif//SkSpinlock_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkWeakRefCnt.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkWeakRefCnt.h new file mode 100644 index 00000000000000..058a18652ba519 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/SkWeakRefCnt.h @@ -0,0 +1,173 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkWeakRefCnt_DEFINED +#define SkWeakRefCnt_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include +#include + +/** \class SkWeakRefCnt + + SkWeakRefCnt is the base class for objects that may be shared by multiple + objects. When an existing strong owner wants to share a reference, it calls + ref(). When a strong owner wants to release its reference, it calls + unref(). When the shared object's strong reference count goes to zero as + the result of an unref() call, its (virtual) weak_dispose method is called. + It is an error for the destructor to be called explicitly (or via the + object going out of scope on the stack or calling delete) if + getRefCnt() > 1. + + In addition to strong ownership, an owner may instead obtain a weak + reference by calling weak_ref(). A call to weak_ref() must be balanced by a + call to weak_unref(). To obtain a strong reference from a weak reference, + call try_ref(). If try_ref() returns true, the owner's pointer is now also + a strong reference on which unref() must be called. Note that this does not + affect the original weak reference, weak_unref() must still be called. When + the weak reference count goes to zero, the object is deleted. While the + weak reference count is positive and the strong reference count is zero the + object still exists, but will be in the disposed state. It is up to the + object to define what this means. + + Note that a strong reference implicitly implies a weak reference. As a + result, it is allowable for the owner of a strong ref to call try_ref(). + This will have the same effect as calling ref(), but may be more expensive. + + Example: + + SkWeakRefCnt myRef = strongRef.weak_ref(); + ... // strongRef.unref() may or may not be called + if (myRef.try_ref()) { + ... // use myRef + myRef.unref(); + } else { + // myRef is in the disposed state + } + myRef.weak_unref(); +*/ +class SK_API SkWeakRefCnt : public SkRefCnt { +public: + /** Default construct, initializing the reference counts to 1. + The strong references collectively hold one weak reference. When the + strong reference count goes to zero, the collectively held weak + reference is released. + */ + SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {} + + /** Destruct, asserting that the weak reference count is 1. + */ + ~SkWeakRefCnt() override { +#ifdef SK_DEBUG + SkASSERT(getWeakCnt() == 1); + fWeakCnt.store(0, std::memory_order_relaxed); +#endif + } + +#ifdef SK_DEBUG + /** Return the weak reference count. */ + int32_t getWeakCnt() const { + return fWeakCnt.load(std::memory_order_relaxed); + } +#endif + +private: + /** If fRefCnt is 0, returns 0. + * Otherwise increments fRefCnt, acquires, and returns the old value. + */ + int32_t atomic_conditional_acquire_strong_ref() const { + int32_t prev = fRefCnt.load(std::memory_order_relaxed); + do { + if (0 == prev) { + break; + } + } while(!fRefCnt.compare_exchange_weak(prev, prev+1, std::memory_order_acquire, + std::memory_order_relaxed)); + return prev; + } + +public: + /** Creates a strong reference from a weak reference, if possible. The + caller must already be an owner. If try_ref() returns true the owner + is in posession of an additional strong reference. Both the original + reference and new reference must be properly unreferenced. If try_ref() + returns false, no strong reference could be created and the owner's + reference is in the same state as before the call. + */ + bool SK_WARN_UNUSED_RESULT try_ref() const { + if (atomic_conditional_acquire_strong_ref() != 0) { + // Acquire barrier (L/SL), if not provided above. + // Prevents subsequent code from happening before the increment. + return true; + } + return false; + } + + /** Increment the weak reference count. Must be balanced by a call to + weak_unref(). + */ + void weak_ref() const { + SkASSERT(getRefCnt() > 0); + SkASSERT(getWeakCnt() > 0); + // No barrier required. + (void)fWeakCnt.fetch_add(+1, std::memory_order_relaxed); + } + + /** Decrement the weak reference count. If the weak reference count is 1 + before the decrement, then call delete on the object. Note that if this + is the case, then the object needs to have been allocated via new, and + not on the stack. + */ + void weak_unref() const { + SkASSERT(getWeakCnt() > 0); + // A release here acts in place of all releases we "should" have been doing in ref(). + if (1 == fWeakCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // Like try_ref(), the acquire is only needed on success, to make sure + // code in internal_dispose() doesn't happen before the decrement. +#ifdef SK_DEBUG + // so our destructor won't complain + fWeakCnt.store(1, std::memory_order_relaxed); +#endif + this->INHERITED::internal_dispose(); + } + } + + /** Returns true if there are no strong references to the object. When this + is the case all future calls to try_ref() will return false. + */ + bool weak_expired() const { + return fRefCnt.load(std::memory_order_relaxed) == 0; + } + +protected: + /** Called when the strong reference count goes to zero. This allows the + object to free any resources it may be holding. Weak references may + still exist and their level of allowed access to the object is defined + by the object's class. + */ + virtual void weak_dispose() const { + } + +private: + /** Called when the strong reference count goes to zero. Calls weak_dispose + on the object and releases the implicit weak reference held + collectively by the strong references. + */ + void internal_dispose() const override { + weak_dispose(); + weak_unref(); + } + + /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ + mutable std::atomic fWeakCnt; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SingleOwner.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SingleOwner.h new file mode 100644 index 00000000000000..473981e1fb83f2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SingleOwner.h @@ -0,0 +1,75 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_SingleOwner_DEFINED +#define skgpu_SingleOwner_DEFINED + +#include "include/private/base/SkDebug.h" // IWYU pragma: keep + +#if defined(SK_DEBUG) +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkMutex.h" +#include "include/private/base/SkThreadAnnotations.h" +#include "include/private/base/SkThreadID.h" + +#endif + +namespace skgpu { + +#if defined(SK_DEBUG) + +#define SKGPU_ASSERT_SINGLE_OWNER(obj) \ + skgpu::SingleOwner::AutoEnforce debug_SingleOwner(obj, __FILE__, __LINE__); + +// This is a debug tool to verify an object is only being used from one thread at a time. +class SingleOwner { +public: + SingleOwner() : fOwner(kIllegalThreadID), fReentranceCount(0) {} + + struct AutoEnforce { + AutoEnforce(SingleOwner* so, const char* file, int line) + : fFile(file), fLine(line), fSO(so) { + fSO->enter(file, line); + } + ~AutoEnforce() { fSO->exit(fFile, fLine); } + + const char* fFile; + int fLine; + SingleOwner* fSO; + }; + +private: + void enter(const char* file, int line) { + SkAutoMutexExclusive lock(fMutex); + SkThreadID self = SkGetThreadID(); + SkASSERTF(fOwner == self || fOwner == kIllegalThreadID, "%s:%d Single owner failure.", + file, line); + fReentranceCount++; + fOwner = self; + } + + void exit(const char* file, int line) { + SkAutoMutexExclusive lock(fMutex); + SkASSERTF(fOwner == SkGetThreadID(), "%s:%d Single owner failure.", file, line); + fReentranceCount--; + if (fReentranceCount == 0) { + fOwner = kIllegalThreadID; + } + } + + SkMutex fMutex; + SkThreadID fOwner SK_GUARDED_BY(fMutex); + int fReentranceCount SK_GUARDED_BY(fMutex); +}; +#else +#define SKGPU_ASSERT_SINGLE_OWNER(obj) +class SingleOwner {}; // Provide a no-op implementation so we can pass pointers to constructors +#endif + +} // namespace skgpu + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAPI.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAPI.h new file mode 100644 index 00000000000000..4028f95d87d2b5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAPI.h @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAPI_DEFINED +#define SkAPI_DEFINED + +#include "include/private/base/SkLoadUserConfig.h" // IWYU pragma: keep + +// If SKIA_IMPLEMENTATION is defined as 1, that signals we are building Skia and should +// export our symbols. If it is not set (or set to 0), then Skia is being used by a client +// and we should not export our symbols. +#if !defined(SKIA_IMPLEMENTATION) + #define SKIA_IMPLEMENTATION 0 +#endif + +// If we are compiling Skia is being as a DLL, we need to be sure to export all of our public +// APIs to that DLL. If a client is using Skia which was compiled as a DLL, we need to instruct +// the linker to use the symbols from that DLL. This is the goal of the SK_API define. +#if !defined(SK_API) + #if defined(SKIA_DLL) + #if defined(_MSC_VER) + #if SKIA_IMPLEMENTATION + #define SK_API __declspec(dllexport) + #else + #define SK_API __declspec(dllimport) + #endif + #else + #define SK_API __attribute__((visibility("default"))) + #endif + #else + #define SK_API + #endif +#endif + +// SK_SPI is functionally identical to SK_API, but used within src to clarify that it's less stable +#if !defined(SK_SPI) + #define SK_SPI SK_API +#endif + +// See https://clang.llvm.org/docs/AttributeReference.html#availability +// The API_AVAILABLE macro comes from on MacOS +#if defined(SK_ENABLE_API_AVAILABLE) +# define SK_API_AVAILABLE API_AVAILABLE +#else +# define SK_API_AVAILABLE(...) +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAlign.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAlign.h new file mode 100644 index 00000000000000..2b2138ddd49c27 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAlign.h @@ -0,0 +1,39 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAlign_DEFINED +#define SkAlign_DEFINED + +#include "include/private/base/SkAssert.h" + +#include + +template static constexpr T SkAlign2(T x) { return (x + 1) >> 1 << 1; } +template static constexpr T SkAlign4(T x) { return (x + 3) >> 2 << 2; } +template static constexpr T SkAlign8(T x) { return (x + 7) >> 3 << 3; } + +template static constexpr bool SkIsAlign2(T x) { return 0 == (x & 1); } +template static constexpr bool SkIsAlign4(T x) { return 0 == (x & 3); } +template static constexpr bool SkIsAlign8(T x) { return 0 == (x & 7); } + +template static constexpr T SkAlignPtr(T x) { + return sizeof(void*) == 8 ? SkAlign8(x) : SkAlign4(x); +} +template static constexpr bool SkIsAlignPtr(T x) { + return sizeof(void*) == 8 ? SkIsAlign8(x) : SkIsAlign4(x); +} + +/** + * align up to a power of 2 + */ +static inline constexpr size_t SkAlignTo(size_t x, size_t alignment) { + // The same as alignment && SkIsPow2(value), w/o a dependency cycle. + SkASSERT(alignment && (alignment & (alignment - 1)) == 0); + return (x + alignment - 1) & ~(alignment - 1); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAlignedStorage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAlignedStorage.h new file mode 100644 index 00000000000000..532ad03978fac5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAlignedStorage.h @@ -0,0 +1,32 @@ +// Copyright 2022 Google LLC +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#ifndef SkAlignedStorage_DEFINED +#define SkAlignedStorage_DEFINED + +#include +#include + +template class SkAlignedSTStorage { +public: + SkAlignedSTStorage() {} + SkAlignedSTStorage(SkAlignedSTStorage&&) = delete; + SkAlignedSTStorage(const SkAlignedSTStorage&) = delete; + SkAlignedSTStorage& operator=(SkAlignedSTStorage&&) = delete; + SkAlignedSTStorage& operator=(const SkAlignedSTStorage&) = delete; + + // Returns void* because this object does not initialize the + // memory. Use placement new for types that require a constructor. + void* get() { return fStorage; } + const void* get() const { return fStorage; } + + // Act as a container of bytes because the storage is uninitialized. + std::byte* data() { return fStorage; } + const std::byte* data() const { return fStorage; } + size_t size() const { return std::size(fStorage); } + +private: + alignas(T) std::byte fStorage[sizeof(T) * N]; +}; + +#endif // SkAlignedStorage_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAssert.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAssert.h new file mode 100644 index 00000000000000..97d43d4f64ff45 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAssert.h @@ -0,0 +1,92 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAssert_DEFINED +#define SkAssert_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkDebug.h" // IWYU pragma: keep + +/** Called internally if we hit an unrecoverable error. + The platform implementation must not return, but should either throw + an exception or otherwise exit. +*/ +[[noreturn]] SK_API extern void sk_abort_no_print(void); + +#if defined(SK_BUILD_FOR_GOOGLE3) + void SkDebugfForDumpStackTrace(const char* data, void* unused); + namespace base { + void DumpStackTrace(int skip_count, void w(const char*, void*), void* arg); + } +# define SK_DUMP_GOOGLE3_STACK() ::base::DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr) +#else +# define SK_DUMP_GOOGLE3_STACK() +#endif + +#if !defined(SK_ABORT) +# if defined(SK_BUILD_FOR_WIN) + // This style lets Visual Studio follow errors back to the source file. +# define SK_DUMP_LINE_FORMAT "%s(%d)" +# else +# define SK_DUMP_LINE_FORMAT "%s:%d" +# endif +# define SK_ABORT(message, ...) \ + do { \ + SkDebugf(SK_DUMP_LINE_FORMAT ": fatal error: \"" message "\"\n", \ + __FILE__, __LINE__, ##__VA_ARGS__); \ + SK_DUMP_GOOGLE3_STACK(); \ + sk_abort_no_print(); \ + } while (false) +#endif + +// SkASSERT, SkASSERTF and SkASSERT_RELEASE can be used as stand alone assertion expressions, e.g. +// uint32_t foo(int x) { +// SkASSERT(x > 4); +// return x - 4; +// } +// and are also written to be compatible with constexpr functions: +// constexpr uint32_t foo(int x) { +// return SkASSERT(x > 4), +// x - 4; +// } +#define SkASSERT_RELEASE(cond) \ + static_cast( (cond) ? (void)0 : []{ SK_ABORT("assert(%s)", #cond); }() ) + +#if defined(SK_DEBUG) + #define SkASSERT(cond) SkASSERT_RELEASE(cond) + #define SkASSERTF(cond, fmt, ...) static_cast( (cond) ? (void)0 : [&]{ \ + SkDebugf(fmt"\n", ##__VA_ARGS__); \ + SK_ABORT("assert(%s)", #cond); \ + }() ) + #define SkDEBUGFAIL(message) SK_ABORT("%s", message) + #define SkDEBUGFAILF(fmt, ...) SK_ABORT(fmt, ##__VA_ARGS__) + #define SkAssertResult(cond) SkASSERT(cond) +#else + #define SkASSERT(cond) static_cast(0) + #define SkASSERTF(cond, fmt, ...) static_cast(0) + #define SkDEBUGFAIL(message) + #define SkDEBUGFAILF(fmt, ...) + + // unlike SkASSERT, this macro executes its condition in the non-debug build. + // The if is present so that this can be used with functions marked SK_WARN_UNUSED_RESULT. + #define SkAssertResult(cond) if (cond) {} do {} while(false) +#endif + +#if !defined(SkUNREACHABLE) +# if defined(_MSC_VER) && !defined(__clang__) +# include +# define FAST_FAIL_INVALID_ARG 5 +// See https://developercommunity.visualstudio.com/content/problem/1128631/code-flow-doesnt-see-noreturn-with-extern-c.html +// for why this is wrapped. Hopefully removable after msvc++ 19.27 is no longer supported. +[[noreturn]] static inline void sk_fast_fail() { __fastfail(FAST_FAIL_INVALID_ARG); } +# define SkUNREACHABLE sk_fast_fail() +# else +# define SkUNREACHABLE __builtin_trap() +# endif +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAttributes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAttributes.h new file mode 100644 index 00000000000000..34fdf0e09c92ed --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkAttributes.h @@ -0,0 +1,102 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAttributes_DEFINED +#define SkAttributes_DEFINED + +#include "include/private/base/SkFeatures.h" // IWYU pragma: keep +#include "include/private/base/SkLoadUserConfig.h" // IWYU pragma: keep + +#if defined(__clang__) || defined(__GNUC__) +# define SK_ATTRIBUTE(attr) __attribute__((attr)) +#else +# define SK_ATTRIBUTE(attr) +#endif + +#if !defined(SK_UNUSED) +# if !defined(__clang__) && defined(_MSC_VER) +# define SK_UNUSED __pragma(warning(suppress:4189)) +# else +# define SK_UNUSED SK_ATTRIBUTE(unused) +# endif +#endif + +#if !defined(SK_WARN_UNUSED_RESULT) + #define SK_WARN_UNUSED_RESULT SK_ATTRIBUTE(warn_unused_result) +#endif + +/** + * If your judgment is better than the compiler's (i.e. you've profiled it), + * you can use SK_ALWAYS_INLINE to force inlining. E.g. + * inline void someMethod() { ... } // may not be inlined + * SK_ALWAYS_INLINE void someMethod() { ... } // should always be inlined + */ +#if !defined(SK_ALWAYS_INLINE) +# if defined(SK_BUILD_FOR_WIN) +# define SK_ALWAYS_INLINE __forceinline +# else +# define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline +# endif +#endif + +/** + * If your judgment is better than the compiler's (i.e. you've profiled it), + * you can use SK_NEVER_INLINE to prevent inlining. + */ +#if !defined(SK_NEVER_INLINE) +# if defined(SK_BUILD_FOR_WIN) +# define SK_NEVER_INLINE __declspec(noinline) +# else +# define SK_NEVER_INLINE SK_ATTRIBUTE(noinline) +# endif +#endif + +/** + * Used to annotate a function as taking printf style arguments. + * `A` is the (1 based) index of the format string argument. + * `B` is the (1 based) index of the first argument used by the format string. + */ +#if !defined(SK_PRINTF_LIKE) +# define SK_PRINTF_LIKE(A, B) SK_ATTRIBUTE(format(printf, (A), (B))) +#endif + +/** + * Used to ignore sanitizer warnings. + */ +#if !defined(SK_NO_SANITIZE) +# define SK_NO_SANITIZE(A) SK_ATTRIBUTE(no_sanitize(A)) +#endif + +/** + * Helper macro to define no_sanitize attributes only with clang. + */ +#if defined(__clang__) && defined(__has_attribute) + #if __has_attribute(no_sanitize) + #define SK_CLANG_NO_SANITIZE(A) SK_NO_SANITIZE(A) + #endif +#endif + +#if !defined(SK_CLANG_NO_SANITIZE) + #define SK_CLANG_NO_SANITIZE(A) +#endif + +/** + * Annotates a class' non-trivial special functions as trivial for the purposes of calls. + * Allows a class with a non-trivial destructor to be __is_trivially_relocatable. + * Use of this attribute on a public API breaks platform ABI. + * Annotated classes may not hold pointers derived from `this`. + * Annotated classes must implement move+delete as equivalent to memcpy+free. + * Use may require more complete types, as callee destroys. + * + * https://clang.llvm.org/docs/AttributeReference.html#trivial-abi + * https://libcxx.llvm.org/DesignDocs/UniquePtrTrivialAbi.html + */ +#if !defined(SK_TRIVIAL_ABI) +# define SK_TRIVIAL_ABI +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkCPUTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkCPUTypes.h new file mode 100644 index 00000000000000..a5f60fd3ef191c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkCPUTypes.h @@ -0,0 +1,25 @@ +/* + * Copyright 2023 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkCPUTypes_DEFINED +#define SkCPUTypes_DEFINED + +// TODO(bungeman,kjlubick) There are a lot of assumptions throughout the codebase that +// these types are 32 bits, when they could be more or less. Public APIs should stop +// using these. Internally, we could use uint_fast8_t and uint_fast16_t, but not in +// public APIs due to ABI incompatibilities. + +/** Fast type for unsigned 8 bits. Use for parameter passing and local + variables, not for storage +*/ +typedef unsigned U8CPU; + +/** Fast type for unsigned 16 bits. Use for parameter passing and local + variables, not for storage +*/ +typedef unsigned U16CPU; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkContainers.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkContainers.h new file mode 100644 index 00000000000000..2ece73e28761bb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkContainers.h @@ -0,0 +1,46 @@ +// Copyright 2022 Google LLC. +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#ifndef SkContainers_DEFINED +#define SkContainers_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkSpan_impl.h" + +#include +#include + +class SK_SPI SkContainerAllocator { +public: + SkContainerAllocator(size_t sizeOfT, int maxCapacity) + : fSizeOfT{sizeOfT} + , fMaxCapacity{maxCapacity} {} + + // allocate will abort on failure. Given a capacity of 0, it will return the empty span. + // The bytes allocated are freed using sk_free(). + SkSpan allocate(int capacity, double growthFactor = 1.0); + +private: + friend struct SkContainerAllocatorTestingPeer; + // All capacity counts will be rounded up to kCapacityMultiple. + // TODO: this is a constant from the original SkTArray code. This should be checked some how. + static constexpr int64_t kCapacityMultiple = 8; + + // Rounds up capacity to next multiple of kCapacityMultiple and pin to fMaxCapacity. + size_t roundUpCapacity(int64_t capacity) const; + + // Grows the capacity by growthFactor being sure to stay with in kMinBytes and fMaxCapacity. + size_t growthFactorCapacity(int capacity, double growthFactor) const; + + const size_t fSizeOfT; + const int64_t fMaxCapacity; +}; + +// sk_allocate_canfail returns the empty span on failure. Parameter size must be > 0. +SkSpan sk_allocate_canfail(size_t size); + +// Returns the empty span if size is 0. sk_allocate_throw aborts on failure. +SkSpan sk_allocate_throw(size_t size); + +SK_SPI void sk_report_container_overflow_and_die(); +#endif // SkContainers_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkDebug.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkDebug.h new file mode 100644 index 00000000000000..2e4810fc1c961c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkDebug.h @@ -0,0 +1,27 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDebug_DEFINED +#define SkDebug_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkLoadUserConfig.h" // IWYU pragma: keep + +#if !defined(SkDebugf) + void SK_SPI SkDebugf(const char format[], ...) SK_PRINTF_LIKE(1, 2); +#endif + +#if defined(SK_DEBUG) + #define SkDEBUGCODE(...) __VA_ARGS__ + #define SkDEBUGF(...) SkDebugf(__VA_ARGS__) +#else + #define SkDEBUGCODE(...) + #define SkDEBUGF(...) +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkDeque.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkDeque.h new file mode 100644 index 00000000000000..fbc61673131b40 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkDeque.h @@ -0,0 +1,143 @@ + +/* + * 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 SkDeque_DEFINED +#define SkDeque_DEFINED + +#include "include/private/base/SkAPI.h" + +#include + +/* + * The deque class works by blindly creating memory space of a specified element + * size. It manages the memory as a doubly linked list of blocks each of which + * can contain multiple elements. Pushes and pops add/remove blocks from the + * beginning/end of the list as necessary while each block tracks the used + * portion of its memory. + * One behavior to be aware of is that the pops do not immediately remove an + * empty block from the beginning/end of the list (Presumably so push/pop pairs + * on the block boundaries don't cause thrashing). This can result in the first/ + * last element not residing in the first/last block. + */ +class SK_API SkDeque { +public: + /** + * elemSize specifies the size of each individual element in the deque + * allocCount specifies how many elements are to be allocated as a block + */ + explicit SkDeque(size_t elemSize, int allocCount = 1); + SkDeque(size_t elemSize, void* storage, size_t storageSize, int allocCount = 1); + ~SkDeque(); + + bool empty() const { return 0 == fCount; } + int count() const { return fCount; } + size_t elemSize() const { return fElemSize; } + + const void* front() const { return fFront; } + const void* back() const { return fBack; } + + void* front() { + return (void*)((const SkDeque*)this)->front(); + } + + void* back() { + return (void*)((const SkDeque*)this)->back(); + } + + /** + * push_front and push_back return a pointer to the memory space + * for the new element + */ + void* push_front(); + void* push_back(); + + void pop_front(); + void pop_back(); + +private: + struct Block; + +public: + class Iter { + public: + enum IterStart { + kFront_IterStart, + kBack_IterStart, + }; + + /** + * Creates an uninitialized iterator. Must be reset() + */ + Iter(); + + Iter(const SkDeque& d, IterStart startLoc); + void* next(); + void* prev(); + + void reset(const SkDeque& d, IterStart startLoc); + + private: + SkDeque::Block* fCurBlock; + char* fPos; + size_t fElemSize; + }; + + // Inherit privately from Iter to prevent access to reverse iteration + class F2BIter : private Iter { + public: + F2BIter() {} + + /** + * Wrap Iter's 2 parameter ctor to force initialization to the + * beginning of the deque + */ + F2BIter(const SkDeque& d) : INHERITED(d, kFront_IterStart) {} + + using Iter::next; + + /** + * Wrap Iter::reset to force initialization to the beginning of the + * deque + */ + void reset(const SkDeque& d) { + this->INHERITED::reset(d, kFront_IterStart); + } + + private: + using INHERITED = Iter; + }; + +private: + // allow unit test to call numBlocksAllocated + friend class DequeUnitTestHelper; + + void* fFront; + void* fBack; + + Block* fFrontBlock; + Block* fBackBlock; + size_t fElemSize; + void* fInitialStorage; + int fCount; // number of elements in the deque + int fAllocCount; // number of elements to allocate per block + + Block* allocateBlock(int allocCount); + void freeBlock(Block* block); + + /** + * This returns the number of chunk blocks allocated by the deque. It + * can be used to gauge the effectiveness of the selected allocCount. + */ + int numBlocksAllocated() const; + + SkDeque(const SkDeque&) = delete; + SkDeque& operator=(const SkDeque&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFeatures.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFeatures.h new file mode 100644 index 00000000000000..662bf0321161ec --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFeatures.h @@ -0,0 +1,151 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFeatures_DEFINED +#define SkFeatures_DEFINED + +#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_WIN) && \ + !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) + + #ifdef __APPLE__ + #include + #endif + + #if defined(_WIN32) || defined(__SYMBIAN32__) + #define SK_BUILD_FOR_WIN + #elif defined(ANDROID) || defined(__ANDROID__) + #define SK_BUILD_FOR_ANDROID + #elif defined(linux) || defined(__linux) || defined(__FreeBSD__) || \ + defined(__OpenBSD__) || defined(__sun) || defined(__NetBSD__) || \ + defined(__DragonFly__) || defined(__Fuchsia__) || \ + defined(__GLIBC__) || defined(__GNU__) || defined(__unix__) + #define SK_BUILD_FOR_UNIX + #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #define SK_BUILD_FOR_IOS + #else + #define SK_BUILD_FOR_MAC + #endif +#endif // end SK_BUILD_FOR_* + + +#if defined(SK_BUILD_FOR_WIN) && !defined(__clang__) + #if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict + #endif + #if !defined(SK_WARN_UNUSED_RESULT) + #define SK_WARN_UNUSED_RESULT + #endif +#endif + +#if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict__ +#endif + +#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN) + #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define SK_CPU_BENDIAN + #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define SK_CPU_LENDIAN + #elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__hppa) || \ + defined(__PPC__) || defined(__PPC64__) || \ + defined(_MIPSEB) || defined(__ARMEB__) || \ + defined(__s390__) || \ + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ + (defined(__ia64) && defined(__BIG_ENDIAN__)) + #define SK_CPU_BENDIAN + #else + #define SK_CPU_LENDIAN + #endif +#endif + +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + #define SK_CPU_X86 1 +#endif + +/** + * SK_CPU_SSE_LEVEL + * + * If defined, SK_CPU_SSE_LEVEL should be set to the highest supported level. + * On non-intel CPU this should be undefined. + */ +#define SK_CPU_SSE_LEVEL_SSE1 10 +#define SK_CPU_SSE_LEVEL_SSE2 20 +#define SK_CPU_SSE_LEVEL_SSE3 30 +#define SK_CPU_SSE_LEVEL_SSSE3 31 +#define SK_CPU_SSE_LEVEL_SSE41 41 +#define SK_CPU_SSE_LEVEL_SSE42 42 +#define SK_CPU_SSE_LEVEL_AVX 51 +#define SK_CPU_SSE_LEVEL_AVX2 52 +#define SK_CPU_SSE_LEVEL_SKX 60 + +// TODO(brianosman,kjlubick) clean up these checks + +// Are we in GCC/Clang? +#ifndef SK_CPU_SSE_LEVEL + // These checks must be done in descending order to ensure we set the highest + // available SSE level. + #if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512CD__) && \ + defined(__AVX512BW__) && defined(__AVX512VL__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SKX + #elif defined(__AVX2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 + #elif defined(__AVX__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX + #elif defined(__SSE4_2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42 + #elif defined(__SSE4_1__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41 + #elif defined(__SSSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3 + #elif defined(__SSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3 + #elif defined(__SSE2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #endif +#endif + +// Are we in VisualStudio? +#ifndef SK_CPU_SSE_LEVEL + // These checks must be done in descending order to ensure we set the highest + // available SSE level. 64-bit intel guarantees at least SSE2 support. + #if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512CD__) && \ + defined(__AVX512BW__) && defined(__AVX512VL__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SKX + #elif defined(__AVX2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 + #elif defined(__AVX__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX + #elif defined(_M_X64) || defined(_M_AMD64) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif defined(_M_IX86_FP) + #if _M_IX86_FP >= 2 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif _M_IX86_FP == 1 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1 + #endif + #endif +#endif + +// ARM defines +#if defined(__arm__) && (!defined(__APPLE__) || !TARGET_IPHONE_SIMULATOR) + #define SK_CPU_ARM32 +#elif defined(__aarch64__) + #define SK_CPU_ARM64 +#endif + +// All 64-bit ARM chips have NEON. Many 32-bit ARM chips do too. +#if !defined(SK_ARM_HAS_NEON) && defined(__ARM_NEON) + #define SK_ARM_HAS_NEON +#endif + +#if defined(__ARM_FEATURE_CRC32) + #define SK_ARM_HAS_CRC32 +#endif + +#endif // SkFeatures_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFixed.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFixed.h new file mode 100644 index 00000000000000..2c8f2fb56c188c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFixed.h @@ -0,0 +1,143 @@ +/* + * 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 SkFixed_DEFINED +#define SkFixed_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMath.h" // IWYU pragma: keep +#include "include/private/base/SkTPin.h" // IWYU pragma: keep + +#include + +/** \file SkFixed.h + + Types and macros for 16.16 fixed point +*/ + +/** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point +*/ +typedef int32_t SkFixed; +#define SK_Fixed1 (1 << 16) +#define SK_FixedHalf (1 << 15) +#define SK_FixedQuarter (1 << 14) +#define SK_FixedMax (0x7FFFFFFF) +#define SK_FixedMin (-SK_FixedMax) +#define SK_FixedPI (0x3243F) +#define SK_FixedSqrt2 (92682) +#define SK_FixedTanPIOver8 (0x6A0A) +#define SK_FixedRoot2Over2 (0xB505) + +// NOTE: SkFixedToFloat is exact. SkFloatToFixed seems to lack a rounding step. For all fixed-point +// values, this version is as accurate as possible for (fixed -> float -> fixed). Rounding reduces +// accuracy if the intermediate floats are in the range that only holds integers (adding 0.5f to an +// odd integer then snaps to nearest even). Using double for the rounding math gives maximum +// accuracy for (float -> fixed -> float), but that's usually overkill. +#define SkFixedToFloat(x) ((x) * 1.52587890625e-5f) +#define SkFloatToFixed(x) sk_float_saturate2int((x) * SK_Fixed1) + +#ifdef SK_DEBUG + static inline SkFixed SkFloatToFixed_Check(float x) { + int64_t n64 = (int64_t)(x * SK_Fixed1); + SkFixed n32 = (SkFixed)n64; + SkASSERT(n64 == n32); + return n32; + } +#else + #define SkFloatToFixed_Check(x) SkFloatToFixed(x) +#endif + +#define SkFixedToDouble(x) ((x) * 1.52587890625e-5) +#define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) + +/** Converts an integer to a SkFixed, asserting that the result does not overflow + a 32 bit signed integer +*/ +#ifdef SK_DEBUG + inline SkFixed SkIntToFixed(int n) + { + SkASSERT(n >= -32768 && n <= 32767); + // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before + // shifting. + return (SkFixed)( (unsigned)n << 16 ); + } +#else + // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before + // shifting. Then we force the cast to SkFixed to ensure that the answer is signed (like the + // debug version). + #define SkIntToFixed(n) (SkFixed)((unsigned)(n) << 16) +#endif + +#define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) +#define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) +#define SkFixedFloorToInt(x) ((x) >> 16) + +static inline SkFixed SkFixedRoundToFixed(SkFixed x) { + return (SkFixed)( (uint32_t)(x + SK_FixedHalf) & 0xFFFF0000 ); +} +static inline SkFixed SkFixedCeilToFixed(SkFixed x) { + return (SkFixed)( (uint32_t)(x + SK_Fixed1 - 1) & 0xFFFF0000 ); +} +static inline SkFixed SkFixedFloorToFixed(SkFixed x) { + return (SkFixed)( (uint32_t)x & 0xFFFF0000 ); +} + +#define SkFixedAve(a, b) (((a) + (b)) >> 1) + +// The divide may exceed 32 bits. Clamp to a signed 32 bit result. +#define SkFixedDiv(numer, denom) \ + SkToS32(SkTPin((SkLeftShift((int64_t)(numer), 16) / (denom)), SK_MinS32, SK_MaxS32)) + +static inline SkFixed SkFixedMul(SkFixed a, SkFixed b) { + return (SkFixed)((int64_t)a * b >> 16); +} + +/////////////////////////////////////////////////////////////////////////////// +// Platform-specific alternatives to our portable versions. + +// The VCVT float-to-fixed instruction is part of the VFPv3 instruction set. +#if defined(__ARM_VFPV3__) + #include + + /* This does not handle NaN or other obscurities, but is faster than + than (int)(x*65536). When built on Android with -Os, needs forcing + to inline or we lose the speed benefit. + */ + SK_ALWAYS_INLINE SkFixed SkFloatToFixed_arm(float x) + { + int32_t y; + asm("vcvt.s32.f32 %0, %0, #16": "+w"(x)); + std::memcpy(&y, &x, sizeof(y)); + return y; + } + #undef SkFloatToFixed + #define SkFloatToFixed(x) SkFloatToFixed_arm(x) +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#define SkFixedToScalar(x) SkFixedToFloat(x) +#define SkScalarToFixed(x) SkFloatToFixed(x) + +/////////////////////////////////////////////////////////////////////////////// + +typedef int64_t SkFixed3232; // 32.32 + +#define SkFixed3232Max SK_MaxS64 +#define SkFixed3232Min (-SkFixed3232Max) + +#define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) +#define SkFixed3232ToInt(x) ((int)((x) >> 32)) +#define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) +#define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) +#define SkFloatToFixed3232(x) sk_float_saturate2int64((x) * (65536.0f * 65536.0f)) +#define SkFixed3232ToFloat(x) (x * (1 / (65536.0f * 65536.0f))) + +#define SkScalarToFixed3232(x) SkFloatToFixed3232(x) + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFloatBits.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFloatBits.h new file mode 100644 index 00000000000000..37a7b271aee12d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFloatBits.h @@ -0,0 +1,90 @@ +/* + * Copyright 2008 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 SkFloatBits_DEFINED +#define SkFloatBits_DEFINED + +#include "include/private/base/SkMath.h" + +#include + +/** Convert a sign-bit int (i.e. float interpreted as int) into a 2s compliement + int. This also converts -0 (0x80000000) to 0. Doing this to a float allows + it to be compared using normal C operators (<, <=, etc.) +*/ +static inline int32_t SkSignBitTo2sCompliment(int32_t x) { + if (x < 0) { + x &= 0x7FFFFFFF; + x = -x; + } + return x; +} + +/** Convert a 2s compliment int to a sign-bit (i.e. int interpreted as float). + This undoes the result of SkSignBitTo2sCompliment(). + */ +static inline int32_t Sk2sComplimentToSignBit(int32_t x) { + int sign = x >> 31; + // make x positive + x = (x ^ sign) - sign; + // set the sign bit as needed + x |= SkLeftShift(sign, 31); + return x; +} + +union SkFloatIntUnion { + float fFloat; + int32_t fSignBitInt; +}; + +// Helper to see a float as its bit pattern (w/o aliasing warnings) +static inline int32_t SkFloat2Bits(float x) { + SkFloatIntUnion data; + data.fFloat = x; + return data.fSignBitInt; +} + +// Helper to see a bit pattern as a float (w/o aliasing warnings) +static inline float SkBits2Float(int32_t floatAsBits) { + SkFloatIntUnion data; + data.fSignBitInt = floatAsBits; + return data.fFloat; +} + +constexpr int32_t gFloatBits_exponent_mask = 0x7F800000; +constexpr int32_t gFloatBits_matissa_mask = 0x007FFFFF; + +static inline bool SkFloatBits_IsFinite(int32_t bits) { + return (bits & gFloatBits_exponent_mask) != gFloatBits_exponent_mask; +} + +static inline bool SkFloatBits_IsInf(int32_t bits) { + return ((bits & gFloatBits_exponent_mask) == gFloatBits_exponent_mask) && + (bits & gFloatBits_matissa_mask) == 0; +} + +/** Return the float as a 2s compliment int. Just to be used to compare floats + to each other or against positive float-bit-constants (like 0). This does + not return the int equivalent of the float, just something cheaper for + compares-only. + */ +static inline int32_t SkFloatAs2sCompliment(float x) { + return SkSignBitTo2sCompliment(SkFloat2Bits(x)); +} + +/** Return the 2s compliment int as a float. This undos the result of + SkFloatAs2sCompliment + */ +static inline float Sk2sComplimentAsFloat(int32_t x) { + return SkBits2Float(Sk2sComplimentToSignBit(x)); +} + +// Scalar wrappers for float-bit routines + +#define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x) + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFloatingPoint.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFloatingPoint.h new file mode 100644 index 00000000000000..7aa8909f3a5eb7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkFloatingPoint.h @@ -0,0 +1,231 @@ +/* + * 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 SkFloatingPoint_DEFINED +#define SkFloatingPoint_DEFINED + +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkFloatBits.h" +#include "include/private/base/SkMath.h" + +#include +#include +#include +#include + +constexpr float SK_FloatSqrt2 = 1.41421356f; +constexpr float SK_FloatPI = 3.14159265f; +constexpr double SK_DoublePI = 3.14159265358979323846264338327950288; + +// C++98 cmath std::pow seems to be the earliest portable way to get float pow. +// However, on Linux including cmath undefines isfinite. +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14608 +static inline float sk_float_pow(float base, float exp) { + return powf(base, exp); +} + +#define sk_float_sqrt(x) sqrtf(x) +#define sk_float_sin(x) sinf(x) +#define sk_float_cos(x) cosf(x) +#define sk_float_tan(x) tanf(x) +#define sk_float_floor(x) floorf(x) +#define sk_float_ceil(x) ceilf(x) +#define sk_float_trunc(x) truncf(x) +#ifdef SK_BUILD_FOR_MAC +# define sk_float_acos(x) static_cast(acos(x)) +# define sk_float_asin(x) static_cast(asin(x)) +#else +# define sk_float_acos(x) acosf(x) +# define sk_float_asin(x) asinf(x) +#endif +#define sk_float_atan2(y,x) atan2f(y,x) +#define sk_float_abs(x) fabsf(x) +#define sk_float_copysign(x, y) copysignf(x, y) +#define sk_float_mod(x,y) fmodf(x,y) +#define sk_float_exp(x) expf(x) +#define sk_float_log(x) logf(x) + +constexpr float sk_float_degrees_to_radians(float degrees) { + return degrees * (SK_FloatPI / 180); +} + +constexpr float sk_float_radians_to_degrees(float radians) { + return radians * (180 / SK_FloatPI); +} + +// floor(double+0.5) vs. floorf(float+0.5f) give comparable performance, but upcasting to double +// means tricky values like 0.49999997 and 2^24 get rounded correctly. If these were rounded +// as floatf(x + .5f), they would be 1 higher than expected. +#define sk_float_round(x) (float)sk_double_round((double)(x)) + +// can't find log2f on android, but maybe that just a tool bug? +#ifdef SK_BUILD_FOR_ANDROID + static inline float sk_float_log2(float x) { + const double inv_ln_2 = 1.44269504088896; + return (float)(log(x) * inv_ln_2); + } +#else + #define sk_float_log2(x) log2f(x) +#endif + +static inline bool sk_float_isfinite(float x) { + return SkFloatBits_IsFinite(SkFloat2Bits(x)); +} + +static inline bool sk_floats_are_finite(float a, float b) { + return sk_float_isfinite(a) && sk_float_isfinite(b); +} + +static inline bool sk_floats_are_finite(const float array[], int count) { + float prod = 0; + for (int i = 0; i < count; ++i) { + prod *= array[i]; + } + // At this point, prod will either be NaN or 0 + return prod == 0; // if prod is NaN, this check will return false +} + +static inline bool sk_float_isinf(float x) { + return SkFloatBits_IsInf(SkFloat2Bits(x)); +} + +static inline bool sk_float_isnan(float x) { + return !(x == x); +} + +#define sk_double_isnan(a) sk_float_isnan(a) + +#define SK_MaxS32FitsInFloat 2147483520 +#define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat + +#define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24)) // 0x7fffff8000000000 +#define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat + +/** + * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN. + */ +static inline int sk_float_saturate2int(float x) { + x = x < SK_MaxS32FitsInFloat ? x : SK_MaxS32FitsInFloat; + x = x > SK_MinS32FitsInFloat ? x : SK_MinS32FitsInFloat; + return (int)x; +} + +/** + * Return the closest int for the given double. Returns SK_MaxS32 for NaN. + */ +static inline int sk_double_saturate2int(double x) { + x = x < SK_MaxS32 ? x : SK_MaxS32; + x = x > SK_MinS32 ? x : SK_MinS32; + return (int)x; +} + +/** + * Return the closest int64_t for the given float. Returns SK_MaxS64FitsInFloat for NaN. + */ +static inline int64_t sk_float_saturate2int64(float x) { + x = x < SK_MaxS64FitsInFloat ? x : SK_MaxS64FitsInFloat; + x = x > SK_MinS64FitsInFloat ? x : SK_MinS64FitsInFloat; + return (int64_t)x; +} + +#define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x)) +#define sk_float_round2int(x) sk_float_saturate2int(sk_float_round(x)) +#define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x)) + +#define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x) +#define sk_float_round2int_no_saturate(x) (int)sk_float_round(x) +#define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x) + +#define sk_double_floor(x) floor(x) +#define sk_double_round(x) floor((x) + 0.5) +#define sk_double_ceil(x) ceil(x) +#define sk_double_floor2int(x) (int)sk_double_floor(x) +#define sk_double_round2int(x) (int)sk_double_round(x) +#define sk_double_ceil2int(x) (int)sk_double_ceil(x) + +// Cast double to float, ignoring any warning about too-large finite values being cast to float. +// Clang thinks this is undefined, but it's actually implementation defined to return either +// the largest float or infinity (one of the two bracketing representable floats). Good enough! +SK_NO_SANITIZE("float-cast-overflow") +static inline float sk_double_to_float(double x) { + return static_cast(x); +} + +#define SK_FloatNaN std::numeric_limits::quiet_NaN() +#define SK_FloatInfinity (+std::numeric_limits::infinity()) +#define SK_FloatNegativeInfinity (-std::numeric_limits::infinity()) + +#define SK_DoubleNaN std::numeric_limits::quiet_NaN() + +// Returns false if any of the floats are outside of [0...1] +// Returns true if count is 0 +bool sk_floats_are_unit(const float array[], size_t count); + +static inline float sk_float_rsqrt_portable(float x) { return 1.0f / sk_float_sqrt(x); } +static inline float sk_float_rsqrt (float x) { return 1.0f / sk_float_sqrt(x); } + +// Returns the log2 of the provided value, were that value to be rounded up to the next power of 2. +// Returns 0 if value <= 0: +// Never returns a negative number, even if value is NaN. +// +// sk_float_nextlog2((-inf..1]) -> 0 +// sk_float_nextlog2((1..2]) -> 1 +// sk_float_nextlog2((2..4]) -> 2 +// sk_float_nextlog2((4..8]) -> 3 +// ... +static inline int sk_float_nextlog2(float x) { + uint32_t bits = (uint32_t)SkFloat2Bits(x); + bits += (1u << 23) - 1u; // Increment the exponent for non-powers-of-2. + int exp = ((int32_t)bits >> 23) - 127; + return exp & ~(exp >> 31); // Return 0 for negative or denormalized floats, and exponents < 0. +} + +// This is the number of significant digits we can print in a string such that when we read that +// string back we get the floating point number we expect. The minimum value C requires is 6, but +// most compilers support 9 +#ifdef FLT_DECIMAL_DIG +#define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG +#else +#define SK_FLT_DECIMAL_DIG 9 +#endif + +// IEEE defines how float divide behaves for non-finite values and zero-denoms, but C does not +// so we have a helper that suppresses the possible undefined-behavior warnings. + +SK_NO_SANITIZE("float-divide-by-zero") +static inline float sk_ieee_float_divide(float numer, float denom) { + return numer / denom; +} + +SK_NO_SANITIZE("float-divide-by-zero") +static inline double sk_ieee_double_divide(double numer, double denom) { + return numer / denom; +} + +// While we clean up divide by zero, we'll replace places that do divide by zero with this TODO. +static inline float sk_ieee_float_divide_TODO_IS_DIVIDE_BY_ZERO_SAFE_HERE(float n, float d) { + return sk_ieee_float_divide(n,d); +} + +static inline float sk_fmaf(float f, float m, float a) { +#if defined(FP_FAST_FMA) + return std::fmaf(f,m,a); +#else + return f*m+a; +#endif +} + +// Returns true iff the provided number is within a small epsilon of 0. +bool sk_double_nearly_zero(double a); + +// Comparing floating point numbers is complicated. This helper only works if one or none +// of the two inputs is not very close to zero. It also does not work if both inputs could be NaN. +// The term "ulps" stands for "units of least precision". Read the following for more nuance: +// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ +bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t max_ulps_diff=16); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkLoadUserConfig.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkLoadUserConfig.h new file mode 100644 index 00000000000000..b212ada86b0e5c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkLoadUserConfig.h @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SK_USER_CONFIG_WAS_LOADED + +// Include this to set reasonable defaults (e.g. for SK_CPU_LENDIAN) +#include "include/private/base/SkFeatures.h" + +// Allows embedders that want to disable macros that take arguments to just +// define that symbol to be one of these +#define SK_NOTHING_ARG1(arg1) +#define SK_NOTHING_ARG2(arg1, arg2) +#define SK_NOTHING_ARG3(arg1, arg2, arg3) + +// IWYU pragma: begin_exports + +// Note: SK_USER_CONFIG_HEADER will not work with Bazel builds and some C++ compilers. +#if defined(SK_USER_CONFIG_HEADER) + #include SK_USER_CONFIG_HEADER +#elif defined(SK_USE_BAZEL_CONFIG_HEADER) + // The Bazel config file is presumed to be in the root directory of its Bazel Workspace. + // This is achieved in Skia by having a nested WORKSPACE in include/config and a cc_library + // defined in that folder. As a result, we do not try to include SkUserConfig.h from the + // top of Skia because Bazel sandboxing will move it to a different location. + #include "SkUserConfig.h" +#else + #include "include/config/SkUserConfig.h" +#endif +// IWYU pragma: end_exports + +// Checks to make sure the SkUserConfig options do not conflict. +#if !defined(SK_DEBUG) && !defined(SK_RELEASE) + #ifdef NDEBUG + #define SK_RELEASE + #else + #define SK_DEBUG + #endif +#endif + +#if defined(SK_DEBUG) && defined(SK_RELEASE) +# error "cannot define both SK_DEBUG and SK_RELEASE" +#elif !defined(SK_DEBUG) && !defined(SK_RELEASE) +# error "must define either SK_DEBUG or SK_RELEASE" +#endif + +#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN) +# error "cannot define both SK_CPU_LENDIAN and SK_CPU_BENDIAN" +#elif !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN) +# error "must define either SK_CPU_LENDIAN or SK_CPU_BENDIAN" +#endif + +#if defined(SK_CPU_BENDIAN) && !defined(I_ACKNOWLEDGE_SKIA_DOES_NOT_SUPPORT_BIG_ENDIAN) + #error "The Skia team is not endian-savvy enough to support big-endian CPUs." + #error "If you still want to use Skia," + #error "please define I_ACKNOWLEDGE_SKIA_DOES_NOT_SUPPORT_BIG_ENDIAN." +#endif + +#define SK_USER_CONFIG_WAS_LOADED +#endif // SK_USER_CONFIG_WAS_LOADED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMacros.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMacros.h new file mode 100644 index 00000000000000..5d1835d0130966 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMacros.h @@ -0,0 +1,94 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkMacros_DEFINED +#define SkMacros_DEFINED + +/* + * Usage: SK_MACRO_CONCAT(a, b) to construct the symbol ab + * + * SK_MACRO_CONCAT_IMPL_PRIV just exists to make this work. Do not use directly + * + */ +#define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y) +#define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y + +/* + * Usage: SK_MACRO_APPEND_LINE(foo) to make foo123, where 123 is the current + * line number. Easy way to construct + * unique names for local functions or + * variables. + */ +#define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__) + +#define SK_MACRO_APPEND_COUNTER(name) SK_MACRO_CONCAT(name, __COUNTER__) + +//////////////////////////////////////////////////////////////////////////////// + +// Can be used to bracket data types that must be dense/packed, e.g. hash keys. +#if defined(__clang__) // This should work on GCC too, but GCC diagnostic pop didn't seem to work! + #define SK_BEGIN_REQUIRE_DENSE _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic error \"-Wpadded\"") + #define SK_END_REQUIRE_DENSE _Pragma("GCC diagnostic pop") +#else + #define SK_BEGIN_REQUIRE_DENSE + #define SK_END_REQUIRE_DENSE +#endif + +#if defined(__clang__) && defined(__has_feature) + // Some compilers have a preprocessor that does not appear to do short-circuit + // evaluation as expected + #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) + // Chrome had issues if we tried to include lsan_interface.h ourselves. + // https://github.com/llvm/llvm-project/blob/10a35632d55bb05004fe3d0c2d4432bb74897ee7/compiler-rt/include/sanitizer/lsan_interface.h#L26 +extern "C" { + void __lsan_ignore_object(const void *p); +} + #define SK_INTENTIONALLY_LEAKED(X) __lsan_ignore_object(X) + #else + #define SK_INTENTIONALLY_LEAKED(X) ((void)0) + #endif +#else + #define SK_INTENTIONALLY_LEAKED(X) ((void)0) +#endif + +#define SK_INIT_TO_AVOID_WARNING = 0 + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Defines overloaded bitwise operators to make it easier to use an enum as a + * bitfield. + */ +#define SK_MAKE_BITFIELD_OPS(X) \ + inline X operator ~(X a) { \ + using U = std::underlying_type_t; \ + return (X) (~static_cast(a)); \ + } \ + inline X operator |(X a, X b) { \ + using U = std::underlying_type_t; \ + return (X) (static_cast(a) | static_cast(b)); \ + } \ + inline X& operator |=(X& a, X b) { \ + return (a = a | b); \ + } \ + inline X operator &(X a, X b) { \ + using U = std::underlying_type_t; \ + return (X) (static_cast(a) & static_cast(b)); \ + } \ + inline X& operator &=(X& a, X b) { \ + return (a = a & b); \ + } + +#define SK_DECL_BITFIELD_OPS_FRIENDS(X) \ + friend X operator ~(X a); \ + friend X operator |(X a, X b); \ + friend X& operator |=(X& a, X b); \ + \ + friend X operator &(X a, X b); \ + friend X& operator &=(X& a, X b); + +#endif // SkMacros_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMalloc.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMalloc.h new file mode 100644 index 00000000000000..1c0c2e73da6252 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMalloc.h @@ -0,0 +1,144 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMalloc_DEFINED +#define SkMalloc_DEFINED + +#include + +#include "include/private/base/SkAPI.h" + +/* + memory wrappers to be implemented by the porting layer (platform) +*/ + + +/** Free memory returned by sk_malloc(). It is safe to pass null. */ +SK_API extern void sk_free(void*); + +/** + * Called internally if we run out of memory. The platform implementation must + * not return, but should either throw an exception or otherwise exit. + */ +SK_API extern void sk_out_of_memory(void); + +enum { + /** + * If this bit is set, the returned buffer must be zero-initialized. If this bit is not set + * the buffer can be uninitialized. + */ + SK_MALLOC_ZERO_INITIALIZE = 1 << 0, + + /** + * If this bit is set, the implementation must throw/crash/quit if the request cannot + * be fulfilled. If this bit is not set, then it should return nullptr on failure. + */ + SK_MALLOC_THROW = 1 << 1, +}; +/** + * Return a block of memory (at least 4-byte aligned) of at least the specified size. + * If the requested memory cannot be returned, either return nullptr or throw/exit, depending + * on the SK_MALLOC_THROW bit. If the allocation succeeds, the memory will be zero-initialized + * if the SK_MALLOC_ZERO_INITIALIZE bit was set. + * + * To free the memory, call sk_free() + */ +SK_API extern void* sk_malloc_flags(size_t size, unsigned flags); + +/** Same as standard realloc(), but this one never returns null on failure. It will throw + * if it fails. + * If size is 0, it will call sk_free on buffer and return null. (This behavior is implementation- + * defined for normal realloc. We follow what glibc does.) + */ +SK_API extern void* sk_realloc_throw(void* buffer, size_t size); + +static inline void* sk_malloc_throw(size_t size) { + return sk_malloc_flags(size, SK_MALLOC_THROW); +} + +static inline void* sk_calloc_throw(size_t size) { + return sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE); +} + +static inline void* sk_calloc_canfail(size_t size) { +#if defined(SK_BUILD_FOR_FUZZER) + // To reduce the chance of OOM, pretend we can't allocate more than 200kb. + if (size > 200000) { + return nullptr; + } +#endif + return sk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE); +} + +// Performs a safe multiply count * elemSize, checking for overflow +SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize); + +/** + * These variants return nullptr on failure + */ +static inline void* sk_malloc_canfail(size_t size) { +#if defined(SK_BUILD_FOR_FUZZER) + // To reduce the chance of OOM, pretend we can't allocate more than 200kb. + if (size > 200000) { + return nullptr; + } +#endif + return sk_malloc_flags(size, 0); +} +SK_API extern void* sk_malloc_canfail(size_t count, size_t elemSize); + +// bzero is safer than memset, but we can't rely on it, so... sk_bzero() +static inline void sk_bzero(void* buffer, size_t size) { + // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). + if (size) { + memset(buffer, 0, size); + } +} + +/** + * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior. + * + * It is undefined behavior to call memcpy() with null dst or src, even if len is 0. + * If an optimizer is "smart" enough, it can exploit this to do unexpected things. + * memcpy(dst, src, 0); + * if (src) { + * printf("%x\n", *src); + * } + * In this code the compiler can assume src is not null and omit the if (src) {...} check, + * unconditionally running the printf, crashing the program if src really is null. + * Of the compilers we pay attention to only GCC performs this optimization in practice. + */ +static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memcpy(dst,src,len); + } + return dst; +} + +static inline void* sk_careful_memmove(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memmove(dst,src,len); + } + return dst; +} + +static inline int sk_careful_memcmp(const void* a, const void* b, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcmp when len == 0. + if (len == 0) { + return 0; // we treat zero-length buffers as "equal" + } + return memcmp(a, b, len); +} + +#endif // SkMalloc_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMath.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMath.h new file mode 100644 index 00000000000000..34bfa739f7a976 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMath.h @@ -0,0 +1,77 @@ +/* + * 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 SkMath_DEFINED +#define SkMath_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkCPUTypes.h" + +#include +#include + +// Max Signed 16 bit value +static constexpr int16_t SK_MaxS16 = INT16_MAX; +static constexpr int16_t SK_MinS16 = -SK_MaxS16; + +static constexpr int32_t SK_MaxS32 = INT32_MAX; +static constexpr int32_t SK_MinS32 = -SK_MaxS32; +static constexpr int32_t SK_NaN32 = INT32_MIN; + +static constexpr int64_t SK_MaxS64 = INT64_MAX; +static constexpr int64_t SK_MinS64 = -SK_MaxS64; + +// 64bit -> 32bit utilities + +// Handy util that can be passed two ints, and will automatically promote to +// 64bits before the multiply, so the caller doesn't have to remember to cast +// e.g. (int64_t)a * b; +static inline int64_t sk_64_mul(int64_t a, int64_t b) { + return a * b; +} + +static inline constexpr int32_t SkLeftShift(int32_t value, int32_t shift) { + return (int32_t) ((uint32_t) value << shift); +} + +static inline constexpr int64_t SkLeftShift(int64_t value, int32_t shift) { + return (int64_t) ((uint64_t) value << shift); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Returns true if value is a power of 2. Does not explicitly check for + * value <= 0. + */ +template constexpr inline bool SkIsPow2(T value) { + return (value & (value - 1)) == 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Return a*b/((1 << shift) - 1), rounding any fractional bits. + * Only valid if a and b are unsigned and <= 32767 and shift is > 0 and <= 8 + */ +static inline unsigned SkMul16ShiftRound(U16CPU a, U16CPU b, int shift) { + SkASSERT(a <= 32767); + SkASSERT(b <= 32767); + SkASSERT(shift > 0 && shift <= 8); + unsigned prod = a*b + (1 << (shift - 1)); + return (prod + (prod >> shift)) >> shift; +} + +/** + * Return a*b/255, rounding any fractional bits. + * Only valid if a and b are unsigned and <= 32767. + */ +static inline U8CPU SkMulDiv255Round(U16CPU a, U16CPU b) { + return SkMul16ShiftRound(a, b, 8); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMutex.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMutex.h new file mode 100644 index 00000000000000..4452beb912f560 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkMutex.h @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMutex_DEFINED +#define SkMutex_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkSemaphore.h" +#include "include/private/base/SkThreadAnnotations.h" +#include "include/private/base/SkThreadID.h" + +class SK_CAPABILITY("mutex") SkMutex { +public: + constexpr SkMutex() = default; + + ~SkMutex() { + this->assertNotHeld(); + } + + void acquire() SK_ACQUIRE() { + fSemaphore.wait(); + SkDEBUGCODE(fOwner = SkGetThreadID();) + } + + void release() SK_RELEASE_CAPABILITY() { + this->assertHeld(); + SkDEBUGCODE(fOwner = kIllegalThreadID;) + fSemaphore.signal(); + } + + void assertHeld() SK_ASSERT_CAPABILITY(this) { + SkASSERT(fOwner == SkGetThreadID()); + } + + void assertNotHeld() { + SkASSERT(fOwner == kIllegalThreadID); + } + +private: + SkSemaphore fSemaphore{1}; + SkDEBUGCODE(SkThreadID fOwner{kIllegalThreadID};) +}; + +class SK_SCOPED_CAPABILITY SkAutoMutexExclusive { +public: + SkAutoMutexExclusive(SkMutex& mutex) SK_ACQUIRE(mutex) : fMutex(mutex) { fMutex.acquire(); } + ~SkAutoMutexExclusive() SK_RELEASE_CAPABILITY() { fMutex.release(); } + + SkAutoMutexExclusive(const SkAutoMutexExclusive&) = delete; + SkAutoMutexExclusive(SkAutoMutexExclusive&&) = delete; + + SkAutoMutexExclusive& operator=(const SkAutoMutexExclusive&) = delete; + SkAutoMutexExclusive& operator=(SkAutoMutexExclusive&&) = delete; + +private: + SkMutex& fMutex; +}; + +#endif // SkMutex_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkNoncopyable.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkNoncopyable.h new file mode 100644 index 00000000000000..ec4a4e51611995 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkNoncopyable.h @@ -0,0 +1,30 @@ +/* + * 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 SkNoncopyable_DEFINED +#define SkNoncopyable_DEFINED + +#include "include/private/base/SkAPI.h" + +/** \class SkNoncopyable (DEPRECATED) + + SkNoncopyable is the base class for objects that do not want to + be copied. It hides its copy-constructor and its assignment-operator. +*/ +class SK_API SkNoncopyable { +public: + SkNoncopyable() = default; + + SkNoncopyable(SkNoncopyable&&) = default; + SkNoncopyable& operator =(SkNoncopyable&&) = default; + +private: + SkNoncopyable(const SkNoncopyable&) = delete; + SkNoncopyable& operator=(const SkNoncopyable&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkOnce.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkOnce.h new file mode 100644 index 00000000000000..97ce6b6311e0bf --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkOnce.h @@ -0,0 +1,55 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOnce_DEFINED +#define SkOnce_DEFINED + +#include "include/private/base/SkThreadAnnotations.h" + +#include +#include +#include + +// SkOnce provides call-once guarantees for Skia, much like std::once_flag/std::call_once(). +// +// There should be no particularly error-prone gotcha use cases when using SkOnce. +// It works correctly as a class member, a local, a global, a function-scoped static, whatever. + +class SkOnce { +public: + constexpr SkOnce() = default; + + template + void operator()(Fn&& fn, Args&&... args) { + auto state = fState.load(std::memory_order_acquire); + + if (state == Done) { + return; + } + + // If it looks like no one has started calling fn(), try to claim that job. + if (state == NotStarted && fState.compare_exchange_strong(state, Claimed, + std::memory_order_relaxed, + std::memory_order_relaxed)) { + // Great! We'll run fn() then notify the other threads by releasing Done into fState. + fn(std::forward(args)...); + return fState.store(Done, std::memory_order_release); + } + + // Some other thread is calling fn(). + // We'll just spin here acquiring until it releases Done into fState. + SK_POTENTIALLY_BLOCKING_REGION_BEGIN; + while (fState.load(std::memory_order_acquire) != Done) { /*spin*/ } + SK_POTENTIALLY_BLOCKING_REGION_END; + } + +private: + enum State : uint8_t { NotStarted, Claimed, Done}; + std::atomic fState{NotStarted}; +}; + +#endif // SkOnce_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkPathEnums.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkPathEnums.h new file mode 100644 index 00000000000000..642bbb3489f7e4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkPathEnums.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * This file contains private enums related to paths. See also skbug.com/10670 + */ + +#ifndef SkPathEnums_DEFINED +#define SkPathEnums_DEFINED + +enum class SkPathConvexity { + kConvex, + kConcave, + kUnknown, +}; + +enum class SkPathFirstDirection { + kCW, // == SkPathDirection::kCW + kCCW, // == SkPathDirection::kCCW + kUnknown, +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSafe32.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSafe32.h new file mode 100644 index 00000000000000..5ba4c2f9a48e23 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSafe32.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSafe32_DEFINED +#define SkSafe32_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkMath.h" + +#include + +static constexpr int32_t Sk64_pin_to_s32(int64_t x) { + return x < SK_MinS32 ? SK_MinS32 : (x > SK_MaxS32 ? SK_MaxS32 : (int32_t)x); +} + +static constexpr int32_t Sk32_sat_add(int32_t a, int32_t b) { + return Sk64_pin_to_s32((int64_t)a + (int64_t)b); +} + +static constexpr int32_t Sk32_sat_sub(int32_t a, int32_t b) { + return Sk64_pin_to_s32((int64_t)a - (int64_t)b); +} + +// To avoid UBSAN complaints about 2's compliment overflows +// +static constexpr int32_t Sk32_can_overflow_add(int32_t a, int32_t b) { + return (int32_t)((uint32_t)a + (uint32_t)b); +} +static constexpr int32_t Sk32_can_overflow_sub(int32_t a, int32_t b) { + return (int32_t)((uint32_t)a - (uint32_t)b); +} + +/** + * This is a 'safe' abs for 32-bit integers that asserts when undefined behavior would occur. + * SkTAbs (in SkTemplates.h) is a general purpose absolute-value function. + */ +static inline int32_t SkAbs32(int32_t value) { + SkASSERT(value != SK_NaN32); // The most negative int32_t can't be negated. + if (value < 0) { + value = -value; + } + return value; +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSemaphore.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSemaphore.h new file mode 100644 index 00000000000000..f78ee86625a42a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSemaphore.h @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSemaphore_DEFINED +#define SkSemaphore_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkOnce.h" +#include "include/private/base/SkThreadAnnotations.h" + +#include +#include + +class SkSemaphore { +public: + constexpr SkSemaphore(int count = 0) : fCount(count), fOSSemaphore(nullptr) {} + + // Cleanup the underlying OS semaphore. + SK_SPI ~SkSemaphore(); + + // Increment the counter n times. + // Generally it's better to call signal(n) instead of signal() n times. + void signal(int n = 1); + + // Decrement the counter by 1, + // then if the counter is < 0, sleep this thread until the counter is >= 0. + void wait(); + + // If the counter is positive, decrement it by 1 and return true, otherwise return false. + SK_SPI bool try_wait(); + +private: + // This implementation follows the general strategy of + // 'A Lightweight Semaphore with Partial Spinning' + // found here + // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/ + // That article (and entire blog) are very much worth reading. + // + // We wrap an OS-provided semaphore with a user-space atomic counter that + // lets us avoid interacting with the OS semaphore unless strictly required: + // moving the count from >=0 to <0 or vice-versa, i.e. sleeping or waking threads. + struct OSSemaphore; + + SK_SPI void osSignal(int n); + SK_SPI void osWait(); + + std::atomic fCount; + SkOnce fOSSemaphoreOnce; + OSSemaphore* fOSSemaphore; +}; + +inline void SkSemaphore::signal(int n) { + int prev = fCount.fetch_add(n, std::memory_order_release); + + // We only want to call the OS semaphore when our logical count crosses + // from <0 to >=0 (when we need to wake sleeping threads). + // + // This is easiest to think about with specific examples of prev and n. + // If n == 5 and prev == -3, there are 3 threads sleeping and we signal + // std::min(-(-3), 5) == 3 times on the OS semaphore, leaving the count at 2. + // + // If prev >= 0, no threads are waiting, std::min(-prev, n) is always <= 0, + // so we don't call the OS semaphore, leaving the count at (prev + n). + int toSignal = std::min(-prev, n); + if (toSignal > 0) { + this->osSignal(toSignal); + } +} + +inline void SkSemaphore::wait() { + // Since this fetches the value before the subtract, zero and below means that there are no + // resources left, so the thread needs to wait. + if (fCount.fetch_sub(1, std::memory_order_acquire) <= 0) { + SK_POTENTIALLY_BLOCKING_REGION_BEGIN; + this->osWait(); + SK_POTENTIALLY_BLOCKING_REGION_END; + } +} + +#endif//SkSemaphore_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSpan_impl.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSpan_impl.h new file mode 100644 index 00000000000000..5f31a651bb3757 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkSpan_impl.h @@ -0,0 +1,129 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSpan_DEFINED +#define SkSpan_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include +#include + +// Having this be an export works around IWYU churn related to +// https://github.com/include-what-you-use/include-what-you-use/issues/1121 +#include // IWYU pragma: export + +// Add macro to check the lifetime of initializer_list arguments. initializer_list has a very +// short life span, and can only be used as a parameter, and not as a variable. +#if defined(__clang__) && defined(__has_cpp_attribute) && __has_cpp_attribute(clang::lifetimebound) +#define SK_CHECK_IL_LIFETIME [[clang::lifetimebound]] +#else +#define SK_CHECK_IL_LIFETIME +#endif + +/** + * SkSpan holds a reference to contiguous data of type T along with a count. SkSpan does not own + * the data itself but is merely a reference, therefore you must take care with the lifetime of + * the underlying data. + * + * SkSpan is a count and a pointer into existing array or data type that stores its data in + * contiguous memory like std::vector. Any container that works with std::size() and std::data() + * can be used. + * + * SkSpan makes a convenient parameter for a routine to accept array like things. This allows you to + * write the routine without overloads for all different container types. + * + * Example: + * void routine(SkSpan a) { ... } + * + * std::vector v = {1, 2, 3, 4, 5}; + * + * routine(a); + * + * A word of caution when working with initializer_list, initializer_lists have a lifetime that is + * limited to the current statement. The following is correct and safe: + * + * Example: + * routine({1,2,3,4,5}); + * + * The following is undefined, and will result in erratic execution: + * + * Bad Example: + * initializer_list l = {1, 2, 3, 4, 5}; // The data behind l dies at the ;. + * routine(l); + */ +template +class SkSpan { +public: + constexpr SkSpan() : fPtr{nullptr}, fSize{0} {} + + template , bool> = true> + constexpr SkSpan(T* ptr, Integer size) : fPtr{ptr}, fSize{SkToSizeT(size)} { + SkASSERT(ptr || fSize == 0); // disallow nullptr + a nonzero size + SkASSERT(fSize < kMaxSize); + } + template >> + constexpr SkSpan(const SkSpan& that) : fPtr(std::data(that)), fSize(std::size(that)) {} + constexpr SkSpan(const SkSpan& o) = default; + template constexpr SkSpan(T(&a)[N]) : SkSpan(a, N) { } + template + constexpr SkSpan(Container& c) : SkSpan(std::data(c), std::size(c)) { } + SkSpan(std::initializer_list il SK_CHECK_IL_LIFETIME) + : SkSpan(std::data(il), std::size(il)) {} + + constexpr SkSpan& operator=(const SkSpan& that) = default; + + constexpr T& operator [] (size_t i) const { + SkASSERT(i < this->size()); + return fPtr[i]; + } + constexpr T& front() const { return fPtr[0]; } + constexpr T& back() const { return fPtr[fSize - 1]; } + constexpr T* begin() const { return fPtr; } + constexpr T* end() const { return fPtr + fSize; } + constexpr auto rbegin() const { return std::make_reverse_iterator(this->end()); } + constexpr auto rend() const { return std::make_reverse_iterator(this->begin()); } + constexpr T* data() const { return this->begin(); } + constexpr size_t size() const { return fSize; } + constexpr bool empty() const { return fSize == 0; } + constexpr size_t size_bytes() const { return fSize * sizeof(T); } + constexpr SkSpan first(size_t prefixLen) const { + SkASSERT(prefixLen <= this->size()); + return SkSpan{fPtr, prefixLen}; + } + constexpr SkSpan last(size_t postfixLen) const { + SkASSERT(postfixLen <= this->size()); + return SkSpan{fPtr + (this->size() - postfixLen), postfixLen}; + } + constexpr SkSpan subspan(size_t offset) const { + return this->subspan(offset, this->size() - offset); + } + constexpr SkSpan subspan(size_t offset, size_t count) const { + SkASSERT(offset <= this->size()); + SkASSERT(count <= this->size() - offset); + return SkSpan{fPtr + offset, count}; + } + +private: + static const constexpr size_t kMaxSize = std::numeric_limits::max() / sizeof(T); + T* fPtr; + size_t fSize; +}; + +template +SkSpan(Container&) -> + SkSpan()))>>; + +template +SkSpan(std::initializer_list) -> + SkSpan>()))>>; + +#endif // SkSpan_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTArray.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTArray.h new file mode 100644 index 00000000000000..de8e276513b2e4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTArray.h @@ -0,0 +1,694 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTArray_DEFINED +#define SkTArray_DEFINED + +#include "include/private/base/SkAlignedStorage.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkContainers.h" +#include "include/private/base/SkMalloc.h" +#include "include/private/base/SkMath.h" +#include "include/private/base/SkSpan_impl.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" // IWYU pragma: keep + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace skia_private { +/** TArray implements a typical, mostly std::vector-like array. + Each T will be default-initialized on allocation, and ~T will be called on destruction. + + MEM_MOVE controls the behavior when a T needs to be moved (e.g. when the array is resized) + - true: T will be bit-copied via memcpy. + - false: T will be moved via move-constructors. +*/ +template > class TArray { +public: + using value_type = T; + + /** + * Creates an empty array with no initial storage + */ + TArray() : fOwnMemory(true), fCapacity{0} {} + + /** + * Creates an empty array that will preallocate space for reserveCount + * elements. + */ + explicit TArray(int reserveCount) : TArray() { this->reserve_back(reserveCount); } + + /** + * Copies one array to another. The new array will be heap allocated. + */ + TArray(const TArray& that) : TArray(that.fData, that.fSize) {} + + TArray(TArray&& that) { + if (that.fOwnMemory) { + this->setData(that); + that.setData({}); + } else { + this->initData(that.fSize); + that.move(fData); + } + fSize = std::exchange(that.fSize, 0); + } + + /** + * Creates a TArray by copying contents of a standard C array. The new + * array will be heap allocated. Be careful not to use this constructor + * when you really want the (void*, int) version. + */ + TArray(const T* array, int count) { + this->initData(count); + this->copy(array); + } + + /** + * Creates a TArray by copying contents of an initializer list. + */ + TArray(std::initializer_list data) : TArray(data.begin(), data.size()) {} + + TArray& operator=(const TArray& that) { + if (this == &that) { + return *this; + } + this->clear(); + this->checkRealloc(that.size(), kExactFit); + fSize = that.fSize; + this->copy(that.fData); + return *this; + } + TArray& operator=(TArray&& that) { + if (this != &that) { + this->clear(); + if (that.fOwnMemory) { + // The storage is on the heap, so move the data pointer. + if (fOwnMemory) { + sk_free(fData); + } + + fData = std::exchange(that.fData, nullptr); + + // Can't use exchange with bitfields. + fCapacity = that.fCapacity; + that.fCapacity = 0; + + fOwnMemory = true; + } else { + // The data is stored inline in that, so move it element-by-element. + this->checkRealloc(that.size(), kExactFit); + that.move(fData); + } + fSize = std::exchange(that.fSize, 0); + } + return *this; + } + + ~TArray() { + this->destroyAll(); + if (fOwnMemory) { + sk_free(fData); + } + } + + /** + * Resets to size() = n newly constructed T objects and resets any reserve count. + */ + void reset(int n) { + SkASSERT(n >= 0); + this->clear(); + this->checkRealloc(n, kExactFit); + fSize = n; + for (int i = 0; i < this->size(); ++i) { + new (fData + i) T; + } + } + + /** + * Resets to a copy of a C array and resets any reserve count. + */ + void reset(const T* array, int count) { + SkASSERT(count >= 0); + this->clear(); + this->checkRealloc(count, kExactFit); + fSize = count; + this->copy(array); + } + + /** + * Ensures there is enough reserved space for n elements. + */ + void reserve(int n) { + SkASSERT(n >= 0); + if (n > this->size()) { + this->checkRealloc(n - this->size(), kGrowing); + } + } + + /** + * Ensures there is enough reserved space for n additional elements. The is guaranteed at least + * until the array size grows above n and subsequently shrinks below n, any version of reset() + * is called, or reserve_back() is called again. + */ + void reserve_back(int n) { + SkASSERT(n >= 0); + if (n > 0) { + this->checkRealloc(n, kExactFit); + } + } + + void removeShuffle(int n) { + SkASSERT(n < this->size()); + int newCount = fSize - 1; + fSize = newCount; + fData[n].~T(); + if (n != newCount) { + this->move(n, newCount); + } + } + + // Is the array empty. + bool empty() const { return fSize == 0; } + + /** + * Adds 1 new default-initialized T value and returns it by reference. Note + * the reference only remains valid until the next call that adds or removes + * elements. + */ + T& push_back() { + void* newT = this->push_back_raw(1); + return *new (newT) T; + } + + /** + * Version of above that uses a copy constructor to initialize the new item + */ + T& push_back(const T& t) { + void* newT = this->push_back_raw(1); + return *new (newT) T(t); + } + + /** + * Version of above that uses a move constructor to initialize the new item + */ + T& push_back(T&& t) { + void* newT = this->push_back_raw(1); + return *new (newT) T(std::move(t)); + } + + /** + * Construct a new T at the back of this array. + */ + template T& emplace_back(Args&&... args) { + void* newT = this->push_back_raw(1); + return *new (newT) T(std::forward(args)...); + } + + /** + * Allocates n more default-initialized T values, and returns the address of + * the start of that new range. Note: this address is only valid until the + * next API call made on the array that might add or remove elements. + */ + T* push_back_n(int n) { + SkASSERT(n >= 0); + T* newTs = TCast(this->push_back_raw(n)); + for (int i = 0; i < n; ++i) { + new (&newTs[i]) T; + } + return newTs; + } + + /** + * Version of above that uses a copy constructor to initialize all n items + * to the same T. + */ + T* push_back_n(int n, const T& t) { + SkASSERT(n >= 0); + T* newTs = TCast(this->push_back_raw(n)); + for (int i = 0; i < n; ++i) { + new (&newTs[i]) T(t); + } + return static_cast(newTs); + } + + /** + * Version of above that uses a copy constructor to initialize the n items + * to separate T values. + */ + T* push_back_n(int n, const T t[]) { + SkASSERT(n >= 0); + this->checkRealloc(n, kGrowing); + T* end = this->end(); + for (int i = 0; i < n; ++i) { + new (end + i) T(t[i]); + } + fSize += n; + return end; + } + + /** + * Version of above that uses the move constructor to set n items. + */ + T* move_back_n(int n, T* t) { + SkASSERT(n >= 0); + this->checkRealloc(n, kGrowing); + T* end = this->end(); + for (int i = 0; i < n; ++i) { + new (end + i) T(std::move(t[i])); + } + fSize += n; + return end; + } + + /** + * Removes the last element. Not safe to call when size() == 0. + */ + void pop_back() { + SkASSERT(fSize > 0); + --fSize; + fData[fSize].~T(); + } + + /** + * Removes the last n elements. Not safe to call when size() < n. + */ + void pop_back_n(int n) { + SkASSERT(n >= 0); + SkASSERT(this->size() >= n); + int i = fSize; + while (i-- > fSize - n) { + (*this)[i].~T(); + } + fSize -= n; + } + + /** + * Pushes or pops from the back to resize. Pushes will be default + * initialized. + */ + void resize_back(int newCount) { + SkASSERT(newCount >= 0); + + if (newCount > this->size()) { + this->push_back_n(newCount - fSize); + } else if (newCount < this->size()) { + this->pop_back_n(fSize - newCount); + } + } + + /** Swaps the contents of this array with that array. Does a pointer swap if possible, + otherwise copies the T values. */ + void swap(TArray& that) { + using std::swap; + if (this == &that) { + return; + } + if (fOwnMemory && that.fOwnMemory) { + swap(fData, that.fData); + swap(fSize, that.fSize); + + // Can't use swap because fCapacity is a bit field. + auto allocCount = fCapacity; + fCapacity = that.fCapacity; + that.fCapacity = allocCount; + } else { + // This could be more optimal... + TArray copy(std::move(that)); + that = std::move(*this); + *this = std::move(copy); + } + } + + T* begin() { + return fData; + } + const T* begin() const { + return fData; + } + + // It's safe to use fItemArray + fSize because if fItemArray is nullptr then adding 0 is + // valid and returns nullptr. See [expr.add] in the C++ standard. + T* end() { + if (fData == nullptr) { + SkASSERT(fSize == 0); + } + return fData + fSize; + } + const T* end() const { + if (fData == nullptr) { + SkASSERT(fSize == 0); + } + return fData + fSize; + } + T* data() { return fData; } + const T* data() const { return fData; } + int size() const { return fSize; } + size_t size_bytes() const { return this->bytes(fSize); } + void resize(size_t count) { this->resize_back((int)count); } + + void clear() { + this->destroyAll(); + fSize = 0; + } + + void shrink_to_fit() { + if (!fOwnMemory || fSize == fCapacity) { + return; + } + if (fSize == 0) { + sk_free(fData); + fData = nullptr; + fCapacity = 0; + } else { + SkSpan allocation = Allocate(fSize); + this->move(TCast(allocation.data())); + if (fOwnMemory) { + sk_free(fData); + } + this->setDataFromBytes(allocation); + } + } + + /** + * Get the i^th element. + */ + T& operator[] (int i) { + SkASSERT(i < this->size()); + SkASSERT(i >= 0); + return fData[i]; + } + + const T& operator[] (int i) const { + SkASSERT(i < this->size()); + SkASSERT(i >= 0); + return fData[i]; + } + + T& at(int i) { return (*this)[i]; } + const T& at(int i) const { return (*this)[i]; } + + /** + * equivalent to operator[](0) + */ + T& front() { SkASSERT(fSize > 0); return fData[0];} + + const T& front() const { SkASSERT(fSize > 0); return fData[0];} + + /** + * equivalent to operator[](size() - 1) + */ + T& back() { SkASSERT(fSize); return fData[fSize - 1];} + + const T& back() const { SkASSERT(fSize > 0); return fData[fSize - 1];} + + /** + * equivalent to operator[](size()-1-i) + */ + T& fromBack(int i) { + SkASSERT(i >= 0); + SkASSERT(i < this->size()); + return fData[fSize - i - 1]; + } + + const T& fromBack(int i) const { + SkASSERT(i >= 0); + SkASSERT(i < this->size()); + return fData[fSize - i - 1]; + } + + bool operator==(const TArray& right) const { + int leftCount = this->size(); + if (leftCount != right.size()) { + return false; + } + for (int index = 0; index < leftCount; ++index) { + if (fData[index] != right.fData[index]) { + return false; + } + } + return true; + } + + bool operator!=(const TArray& right) const { + return !(*this == right); + } + + int capacity() const { + return fCapacity; + } + +protected: + // Creates an empty array that will use the passed storage block until it is insufficiently + // large to hold the entire array. + template + TArray(SkAlignedSTStorage* storage, int size = 0) { + static_assert(InitialCapacity >= 0); + SkASSERT(size >= 0); + SkASSERT(storage->get() != nullptr); + if (size > InitialCapacity) { + this->initData(size); + } else { + this->setDataFromBytes(*storage); + fSize = size; + + // setDataFromBytes always sets fOwnMemory to true, but we are actually using static + // storage here, which shouldn't ever be freed. + fOwnMemory = false; + } + } + + // Copy a C array, using pre-allocated storage if preAllocCount >= count. Otherwise, storage + // will only be used when array shrinks to fit. + template + TArray(const T* array, int size, SkAlignedSTStorage* storage) + : TArray{storage, size} + { + this->copy(array); + } + +private: + // Growth factors for checkRealloc. + static constexpr double kExactFit = 1.0; + static constexpr double kGrowing = 1.5; + + static constexpr int kMinHeapAllocCount = 8; + static_assert(SkIsPow2(kMinHeapAllocCount), "min alloc count not power of two."); + + // Note for 32-bit machines kMaxCapacity will be <= SIZE_MAX. For 64-bit machines it will + // just be INT_MAX if the sizeof(T) < 2^32. + static constexpr int kMaxCapacity = SkToInt(std::min(SIZE_MAX / sizeof(T), (size_t)INT_MAX)); + + void setDataFromBytes(SkSpan allocation) { + T* data = TCast(allocation.data()); + // We have gotten extra bytes back from the allocation limit, pin to kMaxCapacity. It + // would seem like the SkContainerAllocator should handle the divide, but it would have + // to a full divide instruction. If done here the size is known at compile, and usually + // can be implemented by a right shift. The full divide takes ~50X longer than the shift. + size_t size = std::min(allocation.size() / sizeof(T), SkToSizeT(kMaxCapacity)); + setData(SkSpan(data, size)); + } + + void setData(SkSpan array) { + fData = array.data(); + fCapacity = SkToU32(array.size()); + fOwnMemory = true; + } + + // We disable Control-Flow Integrity sanitization (go/cfi) when casting item-array buffers. + // CFI flags this code as dangerous because we are casting `buffer` to a T* while the buffer's + // contents might still be uninitialized memory. When T has a vtable, this is especially risky + // because we could hypothetically access a virtual method on fItemArray and jump to an + // unpredictable location in memory. Of course, TArray won't actually use fItemArray in this + // way, and we don't want to construct a T before the user requests one. There's no real risk + // here, so disable CFI when doing these casts. + SK_CLANG_NO_SANITIZE("cfi") + static T* TCast(void* buffer) { + return (T*)buffer; + } + + size_t bytes(int n) const { + SkASSERT(n <= kMaxCapacity); + return SkToSizeT(n) * sizeof(T); + } + + static SkSpan Allocate(int capacity, double growthFactor = 1.0) { + return SkContainerAllocator{sizeof(T), kMaxCapacity}.allocate(capacity, growthFactor); + } + + void initData(int count) { + this->setDataFromBytes(Allocate(count)); + fSize = count; + } + + void destroyAll() { + if (!this->empty()) { + T* cursor = this->begin(); + T* const end = this->end(); + do { + cursor->~T(); + cursor++; + } while (cursor < end); + } + } + + /** In the following move and copy methods, 'dst' is assumed to be uninitialized raw storage. + * In the following move methods, 'src' is destroyed leaving behind uninitialized raw storage. + */ + void copy(const T* src) { + if constexpr (std::is_trivially_copyable_v) { + if (!this->empty() && src != nullptr) { + sk_careful_memcpy(fData, src, this->size_bytes()); + } + } else { + for (int i = 0; i < this->size(); ++i) { + new (fData + i) T(src[i]); + } + } + } + + void move(int dst, int src) { + if constexpr (MEM_MOVE) { + memcpy(static_cast(&fData[dst]), + static_cast(&fData[src]), + sizeof(T)); + } else { + new (&fData[dst]) T(std::move(fData[src])); + fData[src].~T(); + } + } + + void move(void* dst) { + if constexpr (MEM_MOVE) { + sk_careful_memcpy(dst, fData, this->bytes(fSize)); + } else { + for (int i = 0; i < this->size(); ++i) { + new (static_cast(dst) + this->bytes(i)) T(std::move(fData[i])); + fData[i].~T(); + } + } + } + + // Helper function that makes space for n objects, adjusts the count, but does not initialize + // the new objects. + void* push_back_raw(int n) { + this->checkRealloc(n, kGrowing); + void* ptr = fData + fSize; + fSize += n; + return ptr; + } + + void checkRealloc(int delta, double growthFactor) { + // This constant needs to be declared in the function where it is used to work around + // MSVC's persnickety nature about template definitions. + SkASSERT(delta >= 0); + SkASSERT(fSize >= 0); + SkASSERT(fCapacity >= 0); + + // Return if there are enough remaining allocated elements to satisfy the request. + if (this->capacity() - fSize >= delta) { + return; + } + + // Don't overflow fSize or size_t later in the memory allocation. Overflowing memory + // allocation really only applies to fSizes on 32-bit machines; on 64-bit machines this + // will probably never produce a check. Since kMaxCapacity is bounded above by INT_MAX, + // this also checks the bounds of fSize. + if (delta > kMaxCapacity - fSize) { + sk_report_container_overflow_and_die(); + } + const int newCount = fSize + delta; + + SkSpan allocation = Allocate(newCount, growthFactor); + + this->move(TCast(allocation.data())); + if (fOwnMemory) { + sk_free(fData); + } + this->setDataFromBytes(allocation); + SkASSERT(this->capacity() >= newCount); + SkASSERT(fData != nullptr); + } + + T* fData{nullptr}; + int fSize{0}; + uint32_t fOwnMemory : 1; + uint32_t fCapacity : 31; +}; + +template static inline void swap(TArray& a, TArray& b) { + a.swap(b); +} + +// Subclass of TArray that contains a pre-allocated memory block for the array. +template > +class STArray : private SkAlignedSTStorage, public TArray { + static_assert(N > 0); + using Storage = SkAlignedSTStorage; + +public: + STArray() + : Storage{} + , TArray(this) {} // Must use () to avoid confusion with initializer_list + // when T=bool because * are convertable to bool. + + STArray(const T* array, int count) + : Storage{} + , TArray{array, count, this} {} + + STArray(std::initializer_list data) + : STArray{data.begin(), SkToInt(data.size())} {} + + explicit STArray(int reserveCount) + : STArray() { this->reserve_back(reserveCount); } + + STArray(const STArray& that) + : STArray() { *this = that; } + + explicit STArray(const TArray& that) + : STArray() { *this = that; } + + STArray(STArray&& that) + : STArray() { *this = std::move(that); } + + explicit STArray(TArray&& that) + : STArray() { *this = std::move(that); } + + STArray& operator=(const STArray& that) { + TArray::operator=(that); + return *this; + } + + STArray& operator=(const TArray& that) { + TArray::operator=(that); + return *this; + } + + STArray& operator=(STArray&& that) { + TArray::operator=(std::move(that)); + return *this; + } + + STArray& operator=(TArray&& that) { + TArray::operator=(std::move(that)); + return *this; + } + + // Force the use of TArray for data() and size(). + using TArray::data; + using TArray::size; +}; +} // namespace skia_private +#endif // SkTArray_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTDArray.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTDArray.h new file mode 100644 index 00000000000000..b08d285378b101 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTDArray.h @@ -0,0 +1,236 @@ +/* + * 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 SkTDArray_DEFINED +#define SkTDArray_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include + +class SK_SPI SkTDStorage { +public: + explicit SkTDStorage(int sizeOfT); + SkTDStorage(const void* src, int size, int sizeOfT); + + // Copy + SkTDStorage(const SkTDStorage& that); + SkTDStorage& operator= (const SkTDStorage& that); + + // Move + SkTDStorage(SkTDStorage&& that); + SkTDStorage& operator= (SkTDStorage&& that); + + ~SkTDStorage(); + + void reset(); + void swap(SkTDStorage& that); + + // Size routines + bool empty() const { return fSize == 0; } + void clear() { fSize = 0; } + int size() const { return fSize; } + void resize(int newSize); + size_t size_bytes() const { return this->bytes(fSize); } + + // Capacity routines + int capacity() const { return fCapacity; } + void reserve(int newCapacity); + void shrink_to_fit(); + + void* data() { return fStorage; } + const void* data() const { return fStorage; } + + // Deletion routines + void erase(int index, int count); + // Removes the entry at 'index' and replaces it with the last array element + void removeShuffle(int index); + + // Insertion routines + void* prepend(); + + void append(); + void append(int count); + void* append(const void* src, int count); + + void* insert(int index); + void* insert(int index, int count, const void* src); + + void pop_back() { + SkASSERT(fSize > 0); + fSize--; + } + + friend bool operator==(const SkTDStorage& a, const SkTDStorage& b); + friend bool operator!=(const SkTDStorage& a, const SkTDStorage& b) { + return !(a == b); + } + +private: + size_t bytes(int n) const { return SkToSizeT(n * fSizeOfT); } + void* address(int n) { return fStorage + this->bytes(n); } + + // Adds delta to fSize. Crash if outside [0, INT_MAX] + int calculateSizeOrDie(int delta); + + // Move the tail of the array defined by the indexes tailStart and tailEnd to dstIndex. The + // elements at dstIndex are overwritten by the tail. + void moveTail(int dstIndex, int tailStart, int tailEnd); + + // Copy src into the array at dstIndex. + void copySrc(int dstIndex, const void* src, int count); + + const int fSizeOfT; + std::byte* fStorage{nullptr}; + int fCapacity{0}; // size of the allocation in fArray (#elements) + int fSize{0}; // logical number of elements (fSize <= fCapacity) +}; + +static inline void swap(SkTDStorage& a, SkTDStorage& b) { + a.swap(b); +} + +// SkTDArray implements a std::vector-like array for raw data-only objects that do not require +// construction or destruction. The constructor and destructor for T will not be called; T objects +// will always be moved via raw memcpy. Newly created T objects will contain uninitialized memory. +template class SkTDArray { +public: + SkTDArray() : fStorage{sizeof(T)} {} + SkTDArray(const T src[], int count) : fStorage{src, count, sizeof(T)} { } + SkTDArray(const std::initializer_list& list) : SkTDArray(list.begin(), list.size()) {} + + // Copy + SkTDArray(const SkTDArray& src) : SkTDArray(src.data(), src.size()) {} + SkTDArray& operator=(const SkTDArray& src) { + fStorage = src.fStorage; + return *this; + } + + // Move + SkTDArray(SkTDArray&& src) : fStorage{std::move(src.fStorage)} {} + SkTDArray& operator=(SkTDArray&& src) { + fStorage = std::move(src.fStorage); + return *this; + } + + friend bool operator==(const SkTDArray& a, const SkTDArray& b) { + return a.fStorage == b.fStorage; + } + friend bool operator!=(const SkTDArray& a, const SkTDArray& b) { return !(a == b); } + + void swap(SkTDArray& that) { + using std::swap; + swap(fStorage, that.fStorage); + } + + bool empty() const { return fStorage.empty(); } + + // Return the number of elements in the array + int size() const { return fStorage.size(); } + + // Return the total number of elements allocated. + // Note: capacity() - size() gives you the number of elements you can add without causing an + // allocation. + int capacity() const { return fStorage.capacity(); } + + // return the number of bytes in the array: count * sizeof(T) + size_t size_bytes() const { return fStorage.size_bytes(); } + + T* data() { return static_cast(fStorage.data()); } + const T* data() const { return static_cast(fStorage.data()); } + T* begin() { return this->data(); } + const T* begin() const { return this->data(); } + T* end() { return this->data() + this->size(); } + const T* end() const { return this->data() + this->size(); } + + T& operator[](int index) { + SkASSERT(index < this->size()); + return this->data()[index]; + } + const T& operator[](int index) const { + SkASSERT(index < this->size()); + return this->data()[index]; + } + + const T& back() const { + SkASSERT(this->size() > 0); + return this->data()[this->size() - 1]; + } + T& back() { + SkASSERT(this->size() > 0); + return this->data()[this->size() - 1]; + } + + void reset() { + fStorage.reset(); + } + + void clear() { + fStorage.clear(); + } + + // Sets the number of elements in the array. + // If the array does not have space for count elements, it will increase + // the storage allocated to some amount greater than that required. + // It will never shrink the storage. + void resize(int count) { + fStorage.resize(count); + } + + void reserve(int n) { + fStorage.reserve(n); + } + + T* append() { + fStorage.append(); + return this->end() - 1; + } + T* append(int count) { + fStorage.append(count); + return this->end() - count; + } + T* append(int count, const T* src) { + return static_cast(fStorage.append(src, count)); + } + + T* insert(int index) { + return static_cast(fStorage.insert(index)); + } + T* insert(int index, int count, const T* src = nullptr) { + return static_cast(fStorage.insert(index, count, src)); + } + + void remove(int index, int count = 1) { + fStorage.erase(index, count); + } + + void removeShuffle(int index) { + fStorage.removeShuffle(index); + } + + // routines to treat the array like a stack + void push_back(const T& v) { + this->append(); + this->back() = v; + } + void pop_back() { fStorage.pop_back(); } + + void shrink_to_fit() { + fStorage.shrink_to_fit(); + } + +private: + SkTDStorage fStorage; +}; + +template static inline void swap(SkTDArray& a, SkTDArray& b) { a.swap(b); } + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTFitsIn.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTFitsIn.h new file mode 100644 index 00000000000000..365748abef4837 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTFitsIn.h @@ -0,0 +1,105 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTFitsIn_DEFINED +#define SkTFitsIn_DEFINED + +#include "include/private/base/SkDebug.h" + +#include +#include +#include + +/** + * std::underlying_type is only defined for enums. For integral types, we just want the type. + */ +template +struct sk_strip_enum { + typedef T type; +}; + +template +struct sk_strip_enum::value>::type> { + typedef typename std::underlying_type::type type; +}; + + +/** + * In C++ an unsigned to signed cast where the source value cannot be represented in the destination + * type results in an implementation defined destination value. Unlike C, C++ does not allow a trap. + * This makes "(S)(D)s == s" a possibly useful test. However, there are two cases where this is + * incorrect: + * + * when testing if a value of a smaller signed type can be represented in a larger unsigned type + * (int8_t)(uint16_t)-1 == -1 => (int8_t)0xFFFF == -1 => [implementation defined] == -1 + * + * when testing if a value of a larger unsigned type can be represented in a smaller signed type + * (uint16_t)(int8_t)0xFFFF == 0xFFFF => (uint16_t)-1 == 0xFFFF => 0xFFFF == 0xFFFF => true. + * + * Consider the cases: + * u = unsigned, less digits + * U = unsigned, more digits + * s = signed, less digits + * S = signed, more digits + * v is the value we're considering. + * + * u -> U: (u)(U)v == v, trivially true + * U -> u: (U)(u)v == v, both casts well defined, test works + * s -> S: (s)(S)v == v, trivially true + * S -> s: (S)(s)v == v, first cast implementation value, second cast defined, test works + * s -> U: (s)(U)v == v, *this is bad*, the second cast results in implementation defined value + * S -> u: (S)(u)v == v, the second cast is required to prevent promotion of rhs to unsigned + * u -> S: (u)(S)v == v, trivially true + * U -> s: (U)(s)v == v, *this is bad*, + * first cast results in implementation defined value, + * second cast is defined. However, this creates false positives + * uint16_t x = 0xFFFF + * (uint16_t)(int8_t)x == x + * => (uint16_t)-1 == x + * => 0xFFFF == x + * => true + * + * So for the eight cases three are trivially true, three more are valid casts, and two are special. + * The two 'full' checks which otherwise require two comparisons are valid cast checks. + * The two remaining checks s -> U [v >= 0] and U -> s [v <= max(s)] can be done with one op. + */ + +template +static constexpr inline +typename std::enable_if<(std::is_integral::value || std::is_enum::value) && + (std::is_integral::value || std::is_enum::value), bool>::type +/*bool*/ SkTFitsIn(S src) { + // Ensure that is_signed and is_unsigned are passed the arithmetic underlyng types of enums. + using Sa = typename sk_strip_enum::type; + using Da = typename sk_strip_enum::type; + + // SkTFitsIn() is used in public headers, so needs to be written targeting at most C++11. + return + + // E.g. (int8_t)(uint8_t) int8_t(-1) == -1, but the uint8_t == 255, not -1. + (std::is_signed::value && std::is_unsigned::value && sizeof(Sa) <= sizeof(Da)) ? + (S)0 <= src : + + // E.g. (uint8_t)(int8_t) uint8_t(255) == 255, but the int8_t == -1. + (std::is_signed::value && std::is_unsigned::value && sizeof(Da) <= sizeof(Sa)) ? + src <= (S)std::numeric_limits::max() : + +#if !defined(SK_DEBUG) && !defined(__MSVC_RUNTIME_CHECKS ) + // Correct (simple) version. This trips up MSVC's /RTCc run-time checking. + (S)(D)src == src; +#else + // More complex version that's safe with /RTCc. Used in all debug builds, for coverage. + (std::is_signed::value) ? + (intmax_t)src >= (intmax_t)std::numeric_limits::min() && + (intmax_t)src <= (intmax_t)std::numeric_limits::max() : + + // std::is_unsigned ? + (uintmax_t)src <= (uintmax_t)std::numeric_limits::max(); +#endif +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTLogic.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTLogic.h new file mode 100644 index 00000000000000..26f363c94699e2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTLogic.h @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * + * This header provides some std:: features early in the skstd namespace + * and several Skia-specific additions in the sknonstd namespace. + */ + +#ifndef SkTLogic_DEFINED +#define SkTLogic_DEFINED + +#include +#include +#include "include/private/base/SkTo.h" + +// The sknonstd namespace contains things we would like to be proposed and feel std-ish. +namespace sknonstd { + +// The name 'copy' here is fraught with peril. In this case it means 'append', not 'overwrite'. +// Alternate proposed names are 'propagate', 'augment', or 'append' (and 'add', but already taken). +// std::experimental::propagate_const already exists for other purposes in TSv2. +// These also follow the pattern used by boost. +template struct copy_const { + using type = std::conditional_t::value, std::add_const_t, D>; +}; +template using copy_const_t = typename copy_const::type; + +template struct copy_volatile { + using type = std::conditional_t::value, std::add_volatile_t, D>; +}; +template using copy_volatile_t = typename copy_volatile::type; + +template struct copy_cv { + using type = copy_volatile_t, S>; +}; +template using copy_cv_t = typename copy_cv::type; + +// The name 'same' here means 'overwrite'. +// Alternate proposed names are 'replace', 'transfer', or 'qualify_from'. +// same_xxx can be written as copy_xxx, S> +template using same_const = copy_const, S>; +template using same_const_t = typename same_const::type; +template using same_volatile =copy_volatile,S>; +template using same_volatile_t = typename same_volatile::type; +template using same_cv = copy_cv, S>; +template using same_cv_t = typename same_cv::type; + +} // namespace sknonstd + +template +constexpr int SkCount(const Container& c) { return SkTo(std::size(c)); } + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTPin.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTPin.h new file mode 100644 index 00000000000000..c824c4464037e9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTPin.h @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTPin_DEFINED +#define SkTPin_DEFINED + +#include + +/** @return x pinned (clamped) between lo and hi, inclusively. + + Unlike std::clamp(), SkTPin() always returns a value between lo and hi. + If x is NaN, SkTPin() returns lo but std::clamp() returns NaN. +*/ +template +static constexpr const T& SkTPin(const T& x, const T& lo, const T& hi) { + return std::max(lo, std::min(x, hi)); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTemplates.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTemplates.h new file mode 100644 index 00000000000000..cbcf36c5943b88 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTemplates.h @@ -0,0 +1,426 @@ +/* + * 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 SkTemplates_DEFINED +#define SkTemplates_DEFINED + +#include "include/private/base/SkAlign.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMalloc.h" +#include "include/private/base/SkTLogic.h" + +#include +#include +#include +#include +#include +#include +#include + + +/** \file SkTemplates.h + + This file contains light-weight template classes for type-safe and exception-safe + resource management. +*/ + +/** + * Marks a local variable as known to be unused (to avoid warnings). + * Note that this does *not* prevent the local variable from being optimized away. + */ +template inline void sk_ignore_unused_variable(const T&) { } + +/** + * This is a general purpose absolute-value function. + * See SkAbs32 in (SkSafe32.h) for a 32-bit int specific version that asserts. + */ +template static inline T SkTAbs(T value) { + if (value < 0) { + value = -value; + } + return value; +} + +/** + * Returns a pointer to a D which comes immediately after S[count]. + */ +template inline D* SkTAfter(S* ptr, size_t count = 1) { + return reinterpret_cast(ptr + count); +} + +/** + * Returns a pointer to a D which comes byteOffset bytes after S. + */ +template inline D* SkTAddOffset(S* ptr, ptrdiff_t byteOffset) { + // The intermediate char* has the same cv-ness as D as this produces better error messages. + // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. + return reinterpret_cast(reinterpret_cast*>(ptr) + byteOffset); +} + +template struct SkOverloadedFunctionObject { + template + auto operator()(Args&&... args) const -> decltype(P(std::forward(args)...)) { + return P(std::forward(args)...); + } +}; + +template using SkFunctionObject = + SkOverloadedFunctionObject, F>; + +/** \class SkAutoTCallVProc + + Call a function when this goes out of scope. The template uses two + parameters, the object, and a function that is to be called in the destructor. + If release() is called, the object reference is set to null. If the object + reference is null when the destructor is called, we do not call the + function. +*/ +template class SkAutoTCallVProc + : public std::unique_ptr> { + using inherited = std::unique_ptr>; +public: + using inherited::inherited; + SkAutoTCallVProc(const SkAutoTCallVProc&) = delete; + SkAutoTCallVProc(SkAutoTCallVProc&& that) : inherited(std::move(that)) {} + + operator T*() const { return this->get(); } +}; + + +namespace skia_private { +/** Allocate an array of T elements, and free the array in the destructor + */ +template class AutoTArray { +public: + AutoTArray() {} + /** Allocate count number of T elements + */ + explicit AutoTArray(int count) { + SkASSERT(count >= 0); + if (count) { + fArray.reset(new T[count]); + } + SkDEBUGCODE(fCount = count;) + } + + AutoTArray(AutoTArray&& other) : fArray(std::move(other.fArray)) { + SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;) + } + AutoTArray& operator=(AutoTArray&& other) { + if (this != &other) { + fArray = std::move(other.fArray); + SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;) + } + return *this; + } + + /** Reallocates given a new count. Reallocation occurs even if new count equals old count. + */ + void reset(int count = 0) { *this = AutoTArray(count); } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray.get(); } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + SkASSERT((unsigned)index < (unsigned)fCount); + return fArray[index]; + } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fArray.get(); } + T* data() { return fArray.get(); } + +private: + std::unique_ptr fArray; + SkDEBUGCODE(int fCount = 0;) +}; + +/** Wraps AutoTArray, with room for kCountRequested elements preallocated. + */ +template class AutoSTArray { +public: + AutoSTArray(AutoSTArray&&) = delete; + AutoSTArray(const AutoSTArray&) = delete; + AutoSTArray& operator=(AutoSTArray&&) = delete; + AutoSTArray& operator=(const AutoSTArray&) = delete; + + /** Initialize with no objects */ + AutoSTArray() { + fArray = nullptr; + fCount = 0; + } + + /** Allocate count number of T elements + */ + AutoSTArray(int count) { + fArray = nullptr; + fCount = 0; + this->reset(count); + } + + ~AutoSTArray() { + this->reset(0); + } + + /** Destroys previous objects in the array and default constructs count number of objects */ + void reset(int count) { + T* start = fArray; + T* iter = start + fCount; + while (iter > start) { + (--iter)->~T(); + } + + SkASSERT(count >= 0); + if (fCount != count) { + if (fCount > kCount) { + // 'fArray' was allocated last time so free it now + SkASSERT((T*) fStorage != fArray); + sk_free(fArray); + } + + if (count > kCount) { + fArray = (T*) sk_malloc_throw(count, sizeof(T)); + } else if (count > 0) { + fArray = (T*) fStorage; + } else { + fArray = nullptr; + } + + fCount = count; + } + + iter = fArray; + T* stop = fArray + count; + while (iter < stop) { + new (iter++) T; + } + } + + /** Return the number of T elements in the array + */ + int count() const { return fCount; } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray; } + + T* begin() { return fArray; } + + const T* begin() const { return fArray; } + + T* end() { return fArray + fCount; } + + const T* end() const { return fArray + fCount; } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + SkASSERT(index < fCount); + return fArray[index]; + } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fArray; } + T* data() { return fArray; } + size_t size() const { return fCount; } + +private: +#if defined(SK_BUILD_FOR_GOOGLE3) + // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, + // but some functions have multiple large stack allocations. + static const int kMaxBytes = 4 * 1024; + static const int kCount = kCountRequested * sizeof(T) > kMaxBytes + ? kMaxBytes / sizeof(T) + : kCountRequested; +#else + static const int kCount = kCountRequested; +#endif + + int fCount; + T* fArray; + alignas(T) char fStorage[kCount * sizeof(T)]; +}; + +/** Manages an array of T elements, freeing the array in the destructor. + * Does NOT call any constructors/destructors on T (T must be POD). + */ +template ::value && + std::is_trivially_destructible::value>> +class AutoTMalloc { +public: + /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ + explicit AutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {} + + /** Allocates space for 'count' Ts. */ + explicit AutoTMalloc(size_t count) + : fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {} + + AutoTMalloc(AutoTMalloc&&) = default; + AutoTMalloc& operator=(AutoTMalloc&&) = default; + + /** Resize the memory area pointed to by the current ptr preserving contents. */ + void realloc(size_t count) { + fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr); + } + + /** Resize the memory area pointed to by the current ptr without preserving contents. */ + T* reset(size_t count = 0) { + fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr); + return this->get(); + } + + T* get() const { return fPtr.get(); } + + operator T*() { return fPtr.get(); } + + operator const T*() const { return fPtr.get(); } + + T& operator[](int index) { return fPtr.get()[index]; } + + const T& operator[](int index) const { return fPtr.get()[index]; } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fPtr.get(); } + T* data() { return fPtr.get(); } + + /** + * Transfer ownership of the ptr to the caller, setting the internal + * pointer to NULL. Note that this differs from get(), which also returns + * the pointer, but it does not transfer ownership. + */ + T* release() { return fPtr.release(); } + +private: + std::unique_ptr> fPtr; +}; + +template ::value && + std::is_trivially_destructible::value>> +class AutoSTMalloc { +public: + AutoSTMalloc() : fPtr(fTStorage) {} + + AutoSTMalloc(size_t count) { + if (count > kCount) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = nullptr; + } + } + + AutoSTMalloc(AutoSTMalloc&&) = delete; + AutoSTMalloc(const AutoSTMalloc&) = delete; + AutoSTMalloc& operator=(AutoSTMalloc&&) = delete; + AutoSTMalloc& operator=(const AutoSTMalloc&) = delete; + + ~AutoSTMalloc() { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + } + + // doesn't preserve contents + T* reset(size_t count) { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + if (count > kCount) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = nullptr; + } + return fPtr; + } + + T* get() const { return fPtr; } + + operator T*() { + return fPtr; + } + + operator const T*() const { + return fPtr; + } + + T& operator[](int index) { + return fPtr[index]; + } + + const T& operator[](int index) const { + return fPtr[index]; + } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fPtr; } + T* data() { return fPtr; } + + // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent + void realloc(size_t count) { + if (count > kCount) { + if (fPtr == fTStorage) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + memcpy((void*)fPtr, fTStorage, kCount * sizeof(T)); + } else { + fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T)); + } + } else if (count) { + if (fPtr != fTStorage) { + fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T)); + } + } else { + this->reset(0); + } + } + +private: + // Since we use uint32_t storage, we might be able to get more elements for free. + static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T); +#if defined(SK_BUILD_FOR_GOOGLE3) + // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions + // have multiple large stack allocations. + static const size_t kMaxBytes = 4 * 1024; + static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes + ? kMaxBytes / sizeof(T) + : kCountWithPadding; +#else + static const size_t kCount = kCountWithPadding; +#endif + + T* fPtr; + union { + uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2]; + T fTStorage[1]; // do NOT want to invoke T::T() + }; +}; + +using UniqueVoidPtr = std::unique_ptr>; + +} // namespace skia_private + +template +constexpr auto SkMakeArrayFromIndexSequence(C c, std::index_sequence is) +-> std::array())), sizeof...(Is)> { + return {{ c(Is)... }}; +} + +template constexpr auto SkMakeArray(C c) +-> std::array::value_type>())), N> { + return SkMakeArrayFromIndexSequence(c, std::make_index_sequence{}); +} + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkThreadAnnotations.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkThreadAnnotations.h new file mode 100644 index 00000000000000..fc2a4aacee6ff7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkThreadAnnotations.h @@ -0,0 +1,91 @@ +/* + * Copyright 2019 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadAnnotations_DEFINED +#define SkThreadAnnotations_DEFINED + +// The bulk of this code is cribbed from: +// http://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +#if defined(__clang__) && (!defined(SWIG)) +#define SK_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x)) +#else +#define SK_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op +#endif + +#define SK_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(capability(x)) + +#define SK_SCOPED_CAPABILITY \ + SK_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable) + +#define SK_GUARDED_BY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x)) + +#define SK_PT_GUARDED_BY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x)) + +#define SK_ACQUIRED_BEFORE(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__)) + +#define SK_ACQUIRED_AFTER(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__)) + +#define SK_REQUIRES(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(requires_capability(__VA_ARGS__)) + +#define SK_REQUIRES_SHARED(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(requires_shared_capability(__VA_ARGS__)) + +#define SK_ACQUIRE(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquire_capability(__VA_ARGS__)) + +#define SK_ACQUIRE_SHARED(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquire_shared_capability(__VA_ARGS__)) + +// Would be SK_RELEASE, but that is already in use as SK_DEBUG vs. SK_RELEASE. +#define SK_RELEASE_CAPABILITY(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(release_capability(__VA_ARGS__)) + +// For symmetry with SK_RELEASE_CAPABILITY. +#define SK_RELEASE_SHARED_CAPABILITY(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(release_shared_capability(__VA_ARGS__)) + +#define SK_TRY_ACQUIRE(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(try_acquire_capability(__VA_ARGS__)) + +#define SK_TRY_ACQUIRE_SHARED(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(try_acquire_shared_capability(__VA_ARGS__)) + +#define SK_EXCLUDES(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__)) + +#define SK_ASSERT_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(assert_capability(x)) + +#define SK_ASSERT_SHARED_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_capability(x)) + +#define SK_RETURN_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x)) + +#define SK_NO_THREAD_SAFETY_ANALYSIS \ + SK_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis) + +#if defined(SK_BUILD_FOR_GOOGLE3) && !defined(SK_BUILD_FOR_WASM_IN_GOOGLE3) + extern "C" { + void __google_cxa_guard_acquire_begin(void); + void __google_cxa_guard_acquire_end (void); + } + #define SK_POTENTIALLY_BLOCKING_REGION_BEGIN __google_cxa_guard_acquire_begin() + #define SK_POTENTIALLY_BLOCKING_REGION_END __google_cxa_guard_acquire_end() +#else + #define SK_POTENTIALLY_BLOCKING_REGION_BEGIN + #define SK_POTENTIALLY_BLOCKING_REGION_END +#endif + +#endif // SkThreadAnnotations_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkThreadID.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkThreadID.h new file mode 100644 index 00000000000000..18984884c96f76 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkThreadID.h @@ -0,0 +1,23 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadID_DEFINED +#define SkThreadID_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkDebug.h" + +#include + +typedef int64_t SkThreadID; + +// SkMutex.h uses SkGetThreadID in debug only code. +SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID(); + +const SkThreadID kIllegalThreadID = 0; + +#endif // SkThreadID_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTo.h new file mode 100644 index 00000000000000..51ccafeeaf7542 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTo.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkTo_DEFINED +#define SkTo_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkTFitsIn.h" + +#include +#include + +template constexpr D SkTo(S s) { + return SkASSERT(SkTFitsIn(s)), + static_cast(s); +} + +template constexpr int8_t SkToS8(S x) { return SkTo(x); } +template constexpr uint8_t SkToU8(S x) { return SkTo(x); } +template constexpr int16_t SkToS16(S x) { return SkTo(x); } +template constexpr uint16_t SkToU16(S x) { return SkTo(x); } +template constexpr int32_t SkToS32(S x) { return SkTo(x); } +template constexpr uint32_t SkToU32(S x) { return SkTo(x); } +template constexpr int64_t SkToS64(S x) { return SkTo(x); } +template constexpr uint64_t SkToU64(S x) { return SkTo(x); } +template constexpr int SkToInt(S x) { return SkTo(x); } +template constexpr unsigned SkToUInt(S x) { return SkTo(x); } +template constexpr size_t SkToSizeT(S x) { return SkTo(x); } + +/** @return false or true based on the condition +*/ +template static constexpr bool SkToBool(const T& x) { + return (bool)x; +} + +#endif // SkTo_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTypeTraits.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTypeTraits.h new file mode 100644 index 00000000000000..736f7897763d51 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/base/SkTypeTraits.h @@ -0,0 +1,33 @@ +// Copyright 2022 Google LLC +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#ifndef SkTypeTraits_DEFINED +#define SkTypeTraits_DEFINED + +#include +#include + +// Trait for identifying types which are relocatable via memcpy, for container optimizations. +template +struct sk_has_trivially_relocatable_member : std::false_type {}; + +// Types can declare themselves trivially relocatable with a public +// using sk_is_trivially_relocatable = std::true_type; +template +struct sk_has_trivially_relocatable_member> + : T::sk_is_trivially_relocatable {}; + +// By default, all trivially copyable types are trivially relocatable. +template +struct sk_is_trivially_relocatable + : std::disjunction, sk_has_trivially_relocatable_member>{}; + +// Here be some dragons: while technically not guaranteed, we count on all sane unique_ptr +// implementations to be trivially relocatable. +template +struct sk_is_trivially_relocatable> : std::true_type {}; + +template +inline constexpr bool sk_is_trivially_relocatable_v = sk_is_trivially_relocatable::value; + +#endif // SkTypeTraits_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/GrSlug.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/GrSlug.h new file mode 100644 index 00000000000000..56841c5b993faa --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/GrSlug.h @@ -0,0 +1,16 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSlug_DEFINED +#define GrSlug_DEFINED + +#include "include/private/chromium/Slug.h" + +// TODO: Update Chrome to use sktext::gpu classes and remove these +using GrSlug = sktext::gpu::Slug; + +#endif // GrSlug_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/GrVkSecondaryCBDrawContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/GrVkSecondaryCBDrawContext.h new file mode 100644 index 00000000000000..51ed8a804defe5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/GrVkSecondaryCBDrawContext.h @@ -0,0 +1,130 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkSecondaryCBDrawContext_DEFINED +#define GrVkSecondaryCBDrawContext_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" + +#include + +class GrBackendSemaphore; +class GrRecordingContext; +struct GrVkDrawableInfo; +namespace skgpu::ganesh { +class Device; +} +class SkCanvas; +class SkDeferredDisplayList; +struct SkImageInfo; +class SkSurfaceCharacterization; +class SkSurfaceProps; + +/** + * This class is a private header that is intended to only be used inside of Chromium. This requires + * Chromium to burrow in and include this specifically since it is not part of skia's public include + * directory. + */ + +/** + * This class is used to draw into an external Vulkan secondary command buffer that is imported + * by the client. The secondary command buffer that gets imported must already have had begin called + * on it with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT. Thus any draws to the imported + * command buffer cannot require changing the render pass. This requirement means that certain types + * of draws will not be supported when using a GrVkSecondaryCBDrawContext. This includes: + * Draws that require a dst copy for blending will be dropped + * Text draws will be dropped (these may require intermediate uploads of text data) + * Read and Write pixels will not work + * Any other draw that requires a copy will fail (this includes using backdrop filter with save + * layer). + * Stenciling is also disabled, but that should not restrict any actual draws from working. + * + * While using a GrVkSecondaryCBDrawContext, the client can also draw into normal SkSurfaces and + * then draw those SkSufaces (as SkImages) into the GrVkSecondaryCBDrawContext. If any of the + * previously mentioned unsupported draws are needed by the client, they can draw them into an + * offscreen surface, and then draw that into the GrVkSecondaryCBDrawContext. + * + * After all drawing to the GrVkSecondaryCBDrawContext has been done, the client must call flush() + * on the GrVkSecondaryCBDrawContext to actually fill in the secondary VkCommandBuffer with the + * draws. + * + * Additionally, the client must keep the GrVkSecondaryCBDrawContext alive until the secondary + * VkCommandBuffer has been submitted and all work finished on the GPU. Before deleting the + * GrVkSecondaryCBDrawContext, the client must call releaseResources() so that Skia can cleanup + * any internal objects that were created for the draws into the secondary command buffer. + */ +class SK_SPI GrVkSecondaryCBDrawContext : public SkRefCnt { +public: + static sk_sp Make(GrRecordingContext*, + const SkImageInfo&, + const GrVkDrawableInfo&, + const SkSurfaceProps* props); + + ~GrVkSecondaryCBDrawContext() override; + + SkCanvas* getCanvas(); + + // Records all the draws to the imported secondary command buffer and sets any dependent + // offscreen draws to the GPU. + void flush(); + + /** Inserts a list of GPU semaphores that Skia will have the driver wait on before executing + commands for this secondary CB. The wait semaphores will get added to the VkCommandBuffer + owned by this GrContext when flush() is called, and not the command buffer which the + Secondary CB is from. This will guarantee that the driver waits on the semaphores before + the secondary command buffer gets executed. If this call returns false, then the GPU + back end will not wait on any passed in semaphores, and the client will still own the + semaphores, regardless of the value of deleteSemaphoresAfterWait. + + If deleteSemaphoresAfterWait is false then Skia will not delete the semaphores. In this case + it is the client's responsibility to not destroy or attempt to reuse the semaphores until it + knows that Skia has finished waiting on them. This can be done by using finishedProcs + on flush calls. + + @param numSemaphores size of waitSemaphores array + @param waitSemaphores array of semaphore containers + @paramm deleteSemaphoresAfterWait who owns and should delete the semaphores + @return true if GPU is waiting on semaphores + */ + bool wait(int numSemaphores, + const GrBackendSemaphore waitSemaphores[], + bool deleteSemaphoresAfterWait = true); + + // This call will release all resources held by the draw context. The client must call + // releaseResources() before deleting the drawing context. However, the resources also include + // any Vulkan resources that were created and used for draws. Therefore the client must only + // call releaseResources() after submitting the secondary command buffer, and waiting for it to + // finish on the GPU. If it is called earlier then some vulkan objects may be deleted while they + // are still in use by the GPU. + void releaseResources(); + + const SkSurfaceProps& props() const { return fProps; } + + // TODO: Fill out these calls to support DDL + bool characterize(SkSurfaceCharacterization* characterization) const; + +#ifndef SK_DDL_IS_UNIQUE_POINTER + bool draw(sk_sp deferredDisplayList); +#else + bool draw(const SkDeferredDisplayList* deferredDisplayList); +#endif + + bool isCompatible(const SkSurfaceCharacterization& characterization) const; + +private: + explicit GrVkSecondaryCBDrawContext(sk_sp, const SkSurfaceProps*); + + sk_sp fDevice; + std::unique_ptr fCachedCanvas; + const SkSurfaceProps fProps; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/SkChromeRemoteGlyphCache.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/SkChromeRemoteGlyphCache.h new file mode 100644 index 00000000000000..962d183b2d9799 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/SkChromeRemoteGlyphCache.h @@ -0,0 +1,148 @@ +/* + * Copyright 2021 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkChromeRemoteGlyphCache_DEFINED +#define SkChromeRemoteGlyphCache_DEFINED + +#include +#include + +#include "include/core/SkData.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/utils/SkNoDrawCanvas.h" + +struct SkPackedGlyphID; +class SkAutoDescriptor; +class SkStrikeCache; +class SkStrikeClientImpl; +class SkStrikeServer; +class SkStrikeServerImpl; +namespace sktext::gpu { class Slug; } + +using SkDiscardableHandleId = uint32_t; +// This class is not thread-safe. +class SkStrikeServer { +public: + // An interface used by the server to create handles for pinning SkStrike + // entries on the remote client. + class DiscardableHandleManager { + public: + SK_SPI virtual ~DiscardableHandleManager() = default; + + // Creates a new *locked* handle and returns a unique ID that can be used to identify + // it on the remote client. + SK_SPI virtual SkDiscardableHandleId createHandle() = 0; + + // Returns true if the handle could be successfully locked. The server can + // assume it will remain locked until the next set of serialized entries is + // pulled from the SkStrikeServer. + // If returns false, the cache entry mapped to the handle has been deleted + // on the client. Any subsequent attempts to lock the same handle are not + // allowed. + SK_SPI virtual bool lockHandle(SkDiscardableHandleId) = 0; + + // Returns true if a handle has been deleted on the remote client. It is + // invalid to use a handle id again with this manager once this returns true. + SK_SPI virtual bool isHandleDeleted(SkDiscardableHandleId) = 0; + }; + + SK_SPI explicit SkStrikeServer(DiscardableHandleManager* discardableHandleManager); + SK_SPI ~SkStrikeServer(); + + // Create an analysis SkCanvas used to populate the SkStrikeServer with ops + // which will be serialized and rendered using the SkStrikeClient. + SK_API std::unique_ptr makeAnalysisCanvas(int width, int height, + const SkSurfaceProps& props, + sk_sp colorSpace, + bool DFTSupport, + bool DFTPerspSupport = true); + + // Serializes the strike data captured using a canvas returned by ::makeAnalysisCanvas. Any + // handles locked using the DiscardableHandleManager will be assumed to be + // unlocked after this call. + SK_SPI void writeStrikeData(std::vector* memory); + + // Testing helpers + void setMaxEntriesInDescriptorMapForTesting(size_t count); + size_t remoteStrikeMapSizeForTesting() const; + +private: + SkStrikeServerImpl* impl(); + + std::unique_ptr fImpl; +}; + +class SkStrikeClient { +public: + // This enum is used in histogram reporting in chromium. Please don't re-order the list of + // entries, and consider it to be append-only. + enum CacheMissType : uint32_t { + // Hard failures where no fallback could be found. + kFontMetrics = 0, + kGlyphMetrics = 1, + kGlyphImage = 2, + kGlyphPath = 3, + + // (DEPRECATED) The original glyph could not be found and a fallback was used. + kGlyphMetricsFallback = 4, + kGlyphPathFallback = 5, + + kGlyphDrawable = 6, + kLast = kGlyphDrawable + }; + + // An interface to delete handles that may be pinned by the remote server. + class DiscardableHandleManager : public SkRefCnt { + public: + ~DiscardableHandleManager() override = default; + + // Returns true if the handle was unlocked and can be safely deleted. Once + // successful, subsequent attempts to delete the same handle are invalid. + virtual bool deleteHandle(SkDiscardableHandleId) = 0; + + virtual void assertHandleValid(SkDiscardableHandleId) {} + + virtual void notifyCacheMiss(CacheMissType type, int fontSize) = 0; + + struct ReadFailureData { + size_t memorySize; + size_t bytesRead; + uint64_t typefaceSize; + uint64_t strikeCount; + uint64_t glyphImagesCount; + uint64_t glyphPathsCount; + }; + virtual void notifyReadFailure(const ReadFailureData& data) {} + }; + + SK_SPI explicit SkStrikeClient(sk_sp, + bool isLogging = true, + SkStrikeCache* strikeCache = nullptr); + SK_SPI ~SkStrikeClient(); + + // Deserializes the strike data from a SkStrikeServer. All messages generated + // from a server when serializing the ops must be deserialized before the op + // is rasterized. + // Returns false if the data is invalid. + SK_SPI bool readStrikeData(const volatile void* memory, size_t memorySize); + + // Given a descriptor re-write the Rec mapping the typefaceID from the renderer to the + // corresponding typefaceID on the GPU. + SK_SPI bool translateTypefaceID(SkAutoDescriptor* descriptor) const; + + // Testing helpers + sk_sp retrieveTypefaceUsingServerIDForTest(SkTypefaceID) const; + + // Given a buffer, unflatten into a slug making sure to do the typefaceID translation from + // renderer to GPU. Returns nullptr if there was a problem. + sk_sp deserializeSlugForTest(const void* data, size_t size) const; + +private: + std::unique_ptr fImpl; +}; +#endif // SkChromeRemoteGlyphCache_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/SkDiscardableMemory.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/SkDiscardableMemory.h new file mode 100644 index 00000000000000..ade4d71aa74973 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/SkDiscardableMemory.h @@ -0,0 +1,70 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDiscardableMemory_DEFINED +#define SkDiscardableMemory_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +/** + * Interface for discardable memory. Implementation is provided by the + * embedder. + */ +class SK_SPI SkDiscardableMemory { +public: + /** + * Factory method that creates, initializes and locks an SkDiscardableMemory + * object. If either of these steps fails, a nullptr pointer will be returned. + */ + static SkDiscardableMemory* Create(size_t bytes); + + /** + * Factory class that creates, initializes and locks an SkDiscardableMemory + * object. If either of these steps fails, a nullptr pointer will be returned. + */ + class Factory : public SkRefCnt { + public: + virtual SkDiscardableMemory* create(size_t bytes) = 0; + private: + using INHERITED = SkRefCnt; + }; + + /** Must not be called while locked. + */ + virtual ~SkDiscardableMemory() {} + + /** + * Locks the memory, prevent it from being discarded. Once locked. you may + * obtain a pointer to that memory using the data() method. + * + * lock() may return false, indicating that the underlying memory was + * discarded and that the lock failed. + * + * Nested calls to lock are not allowed. + */ + virtual bool SK_WARN_UNUSED_RESULT lock() = 0; + + /** + * Returns the current pointer for the discardable memory. This call is ONLY + * valid when the discardable memory object is locked. + */ + virtual void* data() = 0; + + /** + * Unlock the memory so that it can be purged by the system. Must be called + * after every successful lock call. + */ + virtual void unlock() = 0; + +protected: + SkDiscardableMemory() = default; + SkDiscardableMemory(const SkDiscardableMemory&) = delete; + SkDiscardableMemory& operator=(const SkDiscardableMemory&) = delete; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/Slug.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/Slug.h new file mode 100644 index 00000000000000..6775af0fc6966d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/chromium/Slug.h @@ -0,0 +1,67 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef sktext_gpu_Slug_DEFINED +#define sktext_gpu_Slug_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" + +class SkCanvas; +class SkMatrix; +class SkPaint; +class SkTextBlob; +class SkReadBuffer; +class SkStrikeClient; +class SkWriteBuffer; + +namespace sktext::gpu { +// Slug encapsulates an SkTextBlob at a specific origin, using a specific paint. It can be +// manipulated using matrix and clip changes to the canvas. If the canvas is transformed, then +// the Slug will also transform with smaller glyphs using bi-linear interpolation to render. You +// can think of a Slug as making a rubber stamp out of a SkTextBlob. +class SK_API Slug : public SkRefCnt { +public: + // Return nullptr if the blob would not draw. This is not because of clipping, but because of + // some paint optimization. The Slug is captured as if drawn using drawTextBlob. + static sk_sp ConvertBlob( + SkCanvas* canvas, const SkTextBlob& blob, SkPoint origin, const SkPaint& paint); + + // Serialize the slug. + sk_sp serialize() const; + size_t serialize(void* buffer, size_t size) const; + + // Set the client parameter to the appropriate SkStrikeClient when typeface ID translation + // is needed. + static sk_sp Deserialize( + const void* data, size_t size, const SkStrikeClient* client = nullptr); + static sk_sp MakeFromBuffer(SkReadBuffer& buffer); + + + // Draw the Slug obeying the canvas's mapping and clipping. + void draw(SkCanvas* canvas) const; + + virtual SkRect sourceBounds() const = 0; + virtual SkRect sourceBoundsWithOrigin () const = 0; + + // The paint passed into ConvertBlob; this paint is used instead of the paint resulting from + // the call to aboutToDraw because when we call draw(), the initial paint is needed to call + // aboutToDraw again to get the layer right. + virtual const SkPaint& initialPaint() const = 0; + + virtual void doFlatten(SkWriteBuffer&) const = 0; + + uint32_t uniqueID() const { return fUniqueID; } + +private: + static uint32_t NextUniqueID(); + const uint32_t fUniqueID{NextUniqueID()}; +}; +} // namespace sktext::gpu + +#endif // sktext_gpu_Slug_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrContext_Base.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrContext_Base.h new file mode 100644 index 00000000000000..ba7172e005ae55 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrContext_Base.h @@ -0,0 +1,100 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContext_Base_DEFINED +#define GrContext_Base_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrBackendSurface.h" +#include "include/gpu/GrContextOptions.h" +#include "include/gpu/GrTypes.h" + +class GrBaseContextPriv; +class GrCaps; +class GrContextThreadSafeProxy; +class GrDirectContext; +class GrImageContext; +class GrRecordingContext; +enum class SkTextureCompressionType; + +class GrContext_Base : public SkRefCnt { +public: + ~GrContext_Base() override; + + /* + * Safely downcast to a GrDirectContext. + */ + virtual GrDirectContext* asDirectContext() { return nullptr; } + + /* + * The 3D API backing this context + */ + SK_API GrBackendApi backend() const; + + /* + * Retrieve the default GrBackendFormat for a given SkColorType and renderability. + * It is guaranteed that this backend format will be the one used by the GrContext + * SkColorType and SkSurfaceCharacterization-based createBackendTexture methods. + * + * The caller should check that the returned format is valid. + */ + SK_API GrBackendFormat defaultBackendFormat(SkColorType, GrRenderable) const; + + SK_API GrBackendFormat compressedBackendFormat(SkTextureCompressionType) const; + + /** + * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA + * rendering is supported for the color type. 0 is returned if rendering to this color type + * is not supported at all. + */ + SK_API int maxSurfaceSampleCountForColorType(SkColorType colorType) const; + + // TODO: When the public version is gone, rename to refThreadSafeProxy and add raw ptr ver. + sk_sp threadSafeProxy(); + + // Provides access to functions that aren't part of the public API. + GrBaseContextPriv priv(); + const GrBaseContextPriv priv() const; // NOLINT(readability-const-return-type) + +protected: + friend class GrBaseContextPriv; // for hidden functions + + GrContext_Base(sk_sp); + + virtual bool init(); + + /** + * An identifier for this context. The id is used by all compatible contexts. For example, + * if SkImages are created on one thread using an image creation context, then fed into a + * DDL Recorder on second thread (which has a recording context) and finally replayed on + * a third thread with a direct context, then all three contexts will report the same id. + * It is an error for an image to be used with contexts that report different ids. + */ + uint32_t contextID() const; + + bool matches(GrContext_Base* candidate) const { + return candidate && candidate->contextID() == this->contextID(); + } + + /* + * The options in effect for this context + */ + const GrContextOptions& options() const; + + const GrCaps* caps() const; + sk_sp refCaps() const; + + virtual GrImageContext* asImageContext() { return nullptr; } + virtual GrRecordingContext* asRecordingContext() { return nullptr; } + + sk_sp fThreadSafeProxy; + +private: + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrD3DTypesMinimal.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrD3DTypesMinimal.h new file mode 100644 index 00000000000000..26b75344760eec --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrD3DTypesMinimal.h @@ -0,0 +1,74 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DTypesMinimal_DEFINED +#define GrD3DTypesMinimal_DEFINED + +// Minimal definitions of Direct3D types, without including d3d12.h + +#include "include/core/SkRefCnt.h" + +#include + +#include "include/gpu/GrTypes.h" + +struct ID3D12Resource; +class GrD3DResourceState; +typedef int GrD3DResourceStateEnum; +struct GrD3DSurfaceInfo; +struct GrD3DTextureResourceInfo; +struct GrD3DTextureResourceSpec; +struct GrD3DFenceInfo; + +// This struct is to used to store the the actual information about the Direct3D backend image on +// GrBackendTexture and GrBackendRenderTarget. When a client calls getD3DTextureInfo on a +// GrBackendTexture/RenderTarget, we use the GrD3DBackendSurfaceInfo to create a snapshot +// GrD3DTextureResourceInfo object. Internally, this uses a ref count GrD3DResourceState object to +// track the current D3D12_RESOURCE_STATES which can be shared with an internal GrD3DTextureResource +// so that state updates can be seen by all users of the texture. +struct GrD3DBackendSurfaceInfo { + GrD3DBackendSurfaceInfo(const GrD3DTextureResourceInfo& info, GrD3DResourceState* state); + + void cleanup(); + + GrD3DBackendSurfaceInfo& operator=(const GrD3DBackendSurfaceInfo&) = delete; + + // Assigns the passed in GrD3DBackendSurfaceInfo to this object. if isValid is true we will also + // attempt to unref the old fLayout on this object. + void assign(const GrD3DBackendSurfaceInfo&, bool isValid); + + void setResourceState(GrD3DResourceStateEnum state); + + sk_sp getGrD3DResourceState() const; + + GrD3DTextureResourceInfo snapTextureResourceInfo() const; + + bool isProtected() const; +#if GR_TEST_UTILS + bool operator==(const GrD3DBackendSurfaceInfo& that) const; +#endif + +private: + GrD3DTextureResourceInfo* fTextureResourceInfo; + GrD3DResourceState* fResourceState; +}; + +struct GrD3DTextureResourceSpecHolder { +public: + GrD3DTextureResourceSpecHolder(const GrD3DSurfaceInfo&); + + void cleanup(); + + GrD3DSurfaceInfo getSurfaceInfo(uint32_t sampleCount, + uint32_t levelCount, + skgpu::Protected isProtected) const; + +private: + GrD3DTextureResourceSpec* fSpec; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrDawnTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrDawnTypesPriv.h new file mode 100644 index 00000000000000..ffcdc0eaaf49ea --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrDawnTypesPriv.h @@ -0,0 +1,26 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDawnTypesPriv_DEFINED +#define GrDawnTypesPriv_DEFINED + +#include "include/gpu/dawn/GrDawnTypes.h" + +struct GrDawnTextureSpec { + GrDawnTextureSpec() {} + GrDawnTextureSpec(const GrDawnSurfaceInfo& info) : fFormat(info.fFormat) {} + + wgpu::TextureFormat fFormat; +}; + +GrDawnSurfaceInfo GrDawnTextureSpecToSurfaceInfo(const GrDawnTextureSpec& dawnSpec, + uint32_t sampleCount, + uint32_t levelCount, + skgpu::Protected isProtected); + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrGLTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrGLTypesPriv.h new file mode 100644 index 00000000000000..7db777487aeccd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrGLTypesPriv.h @@ -0,0 +1,108 @@ +/* + * Copyright 2019 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkRefCnt.h" +#include "include/gpu/gl/GrGLTypes.h" + +#ifndef GrGLTypesPriv_DEFINED +#define GrGLTypesPriv_DEFINED + +static constexpr int kGrGLColorFormatCount = static_cast(GrGLFormat::kLastColorFormat) + 1; + +class GrGLTextureParameters : public SkNVRefCnt { +public: + // We currently consider texture parameters invalid on all textures + // GrContext::resetContext(). We use this type to track whether instances of + // GrGLTextureParameters were updated before or after the most recent resetContext(). At 10 + // resets / frame and 60fps a 64bit timestamp will overflow in about a billion years. + // TODO: Require clients to use GrBackendTexture::glTextureParametersModified() to invalidate + // texture parameters and get rid of timestamp checking. + using ResetTimestamp = uint64_t; + + // This initializes the params to have an expired timestamp. They'll be considered invalid the + // first time the texture is used unless set() is called. + GrGLTextureParameters() = default; + + // This is texture parameter state that is overridden when a non-zero sampler object is bound. + struct SamplerOverriddenState { + SamplerOverriddenState(); + void invalidate(); + + GrGLenum fMinFilter; + GrGLenum fMagFilter; + GrGLenum fWrapS; + GrGLenum fWrapT; + GrGLfloat fMinLOD; + GrGLfloat fMaxLOD; + GrGLfloat fMaxAniso; + // We always want the border color to be transparent black, so no need to store 4 floats. + // Just track if it's been invalidated and no longer the default + bool fBorderColorInvalid; + }; + + // Texture parameter state that is not overridden by a bound sampler object. + struct NonsamplerState { + NonsamplerState(); + void invalidate(); + + GrGLint fBaseMipMapLevel; + GrGLint fMaxMipmapLevel; + bool fSwizzleIsRGBA; + }; + + void invalidate(); + + ResetTimestamp resetTimestamp() const { return fResetTimestamp; } + const SamplerOverriddenState& samplerOverriddenState() const { return fSamplerOverriddenState; } + const NonsamplerState& nonsamplerState() const { return fNonsamplerState; } + + // SamplerOverriddenState is optional because we don't track it when we're using sampler + // objects. + void set(const SamplerOverriddenState* samplerState, + const NonsamplerState& nonsamplerState, + ResetTimestamp currTimestamp); + +private: + static constexpr ResetTimestamp kExpiredTimestamp = 0; + + SamplerOverriddenState fSamplerOverriddenState; + NonsamplerState fNonsamplerState; + ResetTimestamp fResetTimestamp = kExpiredTimestamp; +}; + +class GrGLBackendTextureInfo { +public: + GrGLBackendTextureInfo(const GrGLTextureInfo& info, GrGLTextureParameters* params) + : fInfo(info), fParams(params) {} + GrGLBackendTextureInfo(const GrGLBackendTextureInfo&) = delete; + GrGLBackendTextureInfo& operator=(const GrGLBackendTextureInfo&) = delete; + const GrGLTextureInfo& info() const { return fInfo; } + GrGLTextureParameters* parameters() const { return fParams; } + sk_sp refParameters() const { return sk_ref_sp(fParams); } + + void cleanup(); + void assign(const GrGLBackendTextureInfo&, bool thisIsValid); + +private: + GrGLTextureInfo fInfo; + GrGLTextureParameters* fParams; +}; + +struct GrGLTextureSpec { + GrGLTextureSpec() : fTarget(0), fFormat(0) {} + GrGLTextureSpec(const GrGLSurfaceInfo& info) : fTarget(info.fTarget), fFormat(info.fFormat) {} + + GrGLenum fTarget; + GrGLenum fFormat; +}; + +GrGLSurfaceInfo GrGLTextureSpecToSurfaceInfo(const GrGLTextureSpec& glSpec, + uint32_t sampleCount, + uint32_t levelCount, + skgpu::Protected isProtected); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrImageContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrImageContext.h new file mode 100644 index 00000000000000..72fdd4433d0653 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrImageContext.h @@ -0,0 +1,55 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrImageContext_DEFINED +#define GrImageContext_DEFINED + +#include "include/private/base/SingleOwner.h" +#include "include/private/gpu/ganesh/GrContext_Base.h" + +class GrImageContextPriv; + +// This is now just a view on a ThreadSafeProxy, that SkImages can attempt to +// downcast to a GrDirectContext as a backdoor to some operations. Once we remove the backdoors, +// this goes away and SkImages just hold ThreadSafeProxies. +class GrImageContext : public GrContext_Base { +public: + ~GrImageContext() override; + + // Provides access to functions that aren't part of the public API. + GrImageContextPriv priv(); + const GrImageContextPriv priv() const; // NOLINT(readability-const-return-type) + +protected: + friend class GrImageContextPriv; // for hidden functions + + GrImageContext(sk_sp); + + SK_API virtual void abandonContext(); + SK_API virtual bool abandoned(); + + /** This is only useful for debug purposes */ + skgpu::SingleOwner* singleOwner() const { return &fSingleOwner; } + + GrImageContext* asImageContext() override { return this; } + +private: + // When making promise images, we currently need a placeholder GrImageContext instance to give + // to the SkImage that has no real power, just a wrapper around the ThreadSafeProxy. + // TODO: De-power SkImage to ThreadSafeProxy or at least figure out a way to share one instance. + static sk_sp MakeForPromiseImage(sk_sp); + + // In debug builds we guard against improper thread handling + // This guard is passed to the GrDrawingManager and, from there to all the + // GrSurfaceDrawContexts. It is also passed to the GrResourceProvider and SkGpuDevice. + // TODO: Move this down to GrRecordingContext. + mutable skgpu::SingleOwner fSingleOwner; + + using INHERITED = GrContext_Base; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrMockTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrMockTypesPriv.h new file mode 100644 index 00000000000000..59a608dcfca0dd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrMockTypesPriv.h @@ -0,0 +1,32 @@ +/* + * Copyright 2021 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrMockTypesPriv_DEFINED +#define GrMockTypesPriv_DEFINED + +#include "include/core/SkTextureCompressionType.h" +#include "include/gpu/mock/GrMockTypes.h" + +struct GrMockTextureSpec { + GrMockTextureSpec() + : fColorType(GrColorType::kUnknown) + , fCompressionType(SkTextureCompressionType::kNone) {} + GrMockTextureSpec(const GrMockSurfaceInfo& info) + : fColorType(info.fColorType) + , fCompressionType(info.fCompressionType) {} + + GrColorType fColorType = GrColorType::kUnknown; + SkTextureCompressionType fCompressionType = SkTextureCompressionType::kNone; +}; + +GrMockSurfaceInfo GrMockTextureSpecToSurfaceInfo(const GrMockTextureSpec& mockSpec, + uint32_t sampleCount, + uint32_t levelCount, + GrProtected isProtected); + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrMtlTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrMtlTypesPriv.h new file mode 100644 index 00000000000000..ef65848b5e15ae --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrMtlTypesPriv.h @@ -0,0 +1,75 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrMtlTypesPriv_DEFINED +#define GrMtlTypesPriv_DEFINED + +#include "include/gpu/GrTypes.h" +#include "include/gpu/mtl/GrMtlTypes.h" + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ + +#include + +#if defined(SK_BUILD_FOR_MAC) +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 +#define GR_METAL_SDK_VERSION 230 +#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 +#define GR_METAL_SDK_VERSION 220 +#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 +#define GR_METAL_SDK_VERSION 210 +#else +#error Must use at least 10.14 SDK to build Metal backend for MacOS +#endif +#else +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 || __TV_OS_VERSION_MAX_ALLOWED >= 140000 +#define GR_METAL_SDK_VERSION 230 +#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 || __TV_OS_VERSION_MAX_ALLOWED >= 130000 +#define GR_METAL_SDK_VERSION 220 +#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000 || __TV_OS_VERSION_MAX_ALLOWED >= 120000 +#define GR_METAL_SDK_VERSION 210 +#else +#error Must use at least 12.00 SDK to build Metal backend for iOS +#endif +#endif + +#if __has_feature(objc_arc) && __has_attribute(objc_externally_retained) +#define GR_NORETAIN __attribute__((objc_externally_retained)) +#define GR_NORETAIN_BEGIN \ + _Pragma("clang attribute push (__attribute__((objc_externally_retained)), apply_to=any(function,objc_method))") +#define GR_NORETAIN_END _Pragma("clang attribute pop") +#else +#define GR_NORETAIN +#define GR_NORETAIN_BEGIN +#define GR_NORETAIN_END +#endif + +struct GrMtlTextureSpec { + GrMtlTextureSpec() + : fFormat(0) + , fUsage(0) + , fStorageMode(0) {} + GrMtlTextureSpec(const GrMtlSurfaceInfo& info) + : fFormat(info.fFormat) + , fUsage(info.fUsage) + , fStorageMode(info.fStorageMode) {} + + GrMTLPixelFormat fFormat; + GrMTLTextureUsage fUsage; + GrMTLStorageMode fStorageMode; +}; + +GrMtlSurfaceInfo GrMtlTextureSpecToSurfaceInfo(const GrMtlTextureSpec& mtlSpec, + uint32_t sampleCount, + uint32_t levelCount, + skgpu::Protected isProtected); + +#endif // __APPLE__ + +#endif // GrMtlTypesPriv_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrTypesPriv.h new file mode 100644 index 00000000000000..84e2346348503a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrTypesPriv.h @@ -0,0 +1,1011 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTypesPriv_DEFINED +#define GrTypesPriv_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPath.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTextureCompressionType.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkMacros.h" +#include "include/private/base/SkTypeTraits.h" + +#include + +class GrBackendFormat; +class GrCaps; +class GrSurfaceProxy; + +/** + * divide, rounding up + */ + +static inline constexpr size_t GrSizeDivRoundUp(size_t x, size_t y) { return (x + (y - 1)) / y; } + +/** + * Geometric primitives used for drawing. + */ +enum class GrPrimitiveType : uint8_t { + kTriangles, + kTriangleStrip, + kPoints, + kLines, // 1 pix wide only + kLineStrip, // 1 pix wide only +}; +static constexpr int kNumGrPrimitiveTypes = (int)GrPrimitiveType::kLineStrip + 1; + +static constexpr bool GrIsPrimTypeLines(GrPrimitiveType type) { + return GrPrimitiveType::kLines == type || GrPrimitiveType::kLineStrip == type; +} + +enum class GrPrimitiveRestart : bool { + kNo = false, + kYes = true +}; + +/** + * Should a created surface be texturable? + */ +enum class GrTexturable : bool { + kNo = false, + kYes = true +}; + +// A DDL recorder has its own proxy provider and proxy cache. This enum indicates if +// a given proxy provider is one of these special ones. +enum class GrDDLProvider : bool { + kNo = false, + kYes = true +}; + +/** Ownership rules for external GPU resources imported into Skia. */ +enum GrWrapOwnership { + /** Skia will assume the client will keep the resource alive and Skia will not free it. */ + kBorrow_GrWrapOwnership, + + /** Skia will assume ownership of the resource and free it. */ + kAdopt_GrWrapOwnership, +}; + +enum class GrWrapCacheable : bool { + /** + * The wrapped resource will be removed from the cache as soon as it becomes purgeable. It may + * still be assigned and found by a unique key, but the presence of the key will not be used to + * keep the resource alive when it has no references. + */ + kNo = false, + /** + * The wrapped resource is allowed to remain in the GrResourceCache when it has no references + * but has a unique key. Such resources should only be given unique keys when it is known that + * the key will eventually be removed from the resource or invalidated via the message bus. + */ + kYes = true +}; + +enum class GrBudgetedType : uint8_t { + /** The resource is budgeted and is subject to purging under budget pressure. */ + kBudgeted, + /** + * The resource is unbudgeted and is purged as soon as it has no refs regardless of whether + * it has a unique or scratch key. + */ + kUnbudgetedUncacheable, + /** + * The resource is unbudgeted and is allowed to remain in the cache with no refs if it + * has a unique key. Scratch keys are ignored. + */ + kUnbudgetedCacheable, +}; + +enum class GrScissorTest : bool { + kDisabled = false, + kEnabled = true +}; + +/* + * Used to say whether texture is backed by memory. + */ +enum class GrMemoryless : bool { + /** + * The texture will be allocated normally and will affect memory budgets. + */ + kNo = false, + /** + * The texture will be not use GPU memory and will not affect memory budgets. + */ + kYes = true +}; + +struct GrMipLevel { + const void* fPixels = nullptr; + size_t fRowBytes = 0; + // This may be used to keep fPixels from being freed while a GrMipLevel exists. + sk_sp fOptionalStorage; + + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + + using sk_is_trivially_relocatable = std::true_type; +}; + +enum class GrSemaphoreWrapType { + kWillSignal, + kWillWait, +}; + +/** + * This enum is used to specify the load operation to be used when an OpsTask/GrOpsRenderPass + * begins execution. + */ +enum class GrLoadOp { + kLoad, + kClear, + kDiscard, +}; + +/** + * This enum is used to specify the store operation to be used when an OpsTask/GrOpsRenderPass + * ends execution. + */ +enum class GrStoreOp { + kStore, + kDiscard, +}; + +/** + * Used to control antialiasing in draw calls. + */ +enum class GrAA : bool { + kNo = false, + kYes = true +}; + +enum class GrFillRule : bool { + kNonzero, + kEvenOdd +}; + +inline GrFillRule GrFillRuleForPathFillType(SkPathFillType fillType) { + switch (fillType) { + case SkPathFillType::kWinding: + case SkPathFillType::kInverseWinding: + return GrFillRule::kNonzero; + case SkPathFillType::kEvenOdd: + case SkPathFillType::kInverseEvenOdd: + return GrFillRule::kEvenOdd; + } + SkUNREACHABLE; +} + +inline GrFillRule GrFillRuleForSkPath(const SkPath& path) { + return GrFillRuleForPathFillType(path.getFillType()); +} + +/** This enum indicates the type of antialiasing to be performed. */ +enum class GrAAType : unsigned { + /** No antialiasing */ + kNone, + /** Use fragment shader code to blend with a fractional pixel coverage. */ + kCoverage, + /** Use normal MSAA. */ + kMSAA, + + kLast = kMSAA +}; +static const int kGrAATypeCount = static_cast(GrAAType::kLast) + 1; + +static constexpr bool GrAATypeIsHW(GrAAType type) { + switch (type) { + case GrAAType::kNone: + return false; + case GrAAType::kCoverage: + return false; + case GrAAType::kMSAA: + return true; + } + SkUNREACHABLE; +} + +/** + * Some pixel configs are inherently clamped to [0,1], some are allowed to go outside that range, + * and some are FP but manually clamped in the XP. + */ +enum class GrClampType { + kAuto, // Normalized, fixed-point configs + kManual, // Clamped FP configs + kNone, // Normal (unclamped) FP configs +}; + +/** + * A number of rectangle/quadrilateral drawing APIs can control anti-aliasing on a per edge basis. + * These masks specify which edges are AA'ed. The intent for this is to support tiling with seamless + * boundaries, where the inner edges are non-AA and the outer edges are AA. Regular rectangle draws + * simply use kAll or kNone depending on if they want anti-aliasing or not. + * + * In APIs that support per-edge AA, GrQuadAAFlags is the only AA-control parameter that is + * provided (compared to the typical GrAA parameter). kNone is equivalent to GrAA::kNo, and any + * other set of edge flags would require GrAA::kYes (with rendering output dependent on how that + * maps to GrAAType for a given SurfaceDrawContext). + * + * These values are identical to SkCanvas::QuadAAFlags. + */ +enum class GrQuadAAFlags { + kLeft = 0b0001, + kTop = 0b0010, + kRight = 0b0100, + kBottom = 0b1000, + + kNone = 0b0000, + kAll = 0b1111, +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrQuadAAFlags) + +static inline GrQuadAAFlags SkToGrQuadAAFlags(unsigned flags) { + return static_cast(flags); +} + +/** + * The type of texture. Backends other than GL currently only use the 2D value but the type must + * still be known at the API-neutral layer as it used to determine whether MIP maps, renderability, + * and sampling parameters are legal for proxies that will be instantiated with wrapped textures. + */ +enum class GrTextureType { + kNone, + k2D, + /* Rectangle uses unnormalized texture coordinates. */ + kRectangle, + kExternal +}; + +enum GrShaderType { + kVertex_GrShaderType, + kFragment_GrShaderType, + + kLastkFragment_GrShaderType = kFragment_GrShaderType +}; +static const int kGrShaderTypeCount = kLastkFragment_GrShaderType + 1; + +enum GrShaderFlags { + kNone_GrShaderFlags = 0, + kVertex_GrShaderFlag = 1 << 0, + kFragment_GrShaderFlag = 1 << 1 +}; +SK_MAKE_BITFIELD_OPS(GrShaderFlags) + +/** Rectangle and external textures only support the clamp wrap mode and do not support + * MIP maps. + */ +static inline bool GrTextureTypeHasRestrictedSampling(GrTextureType type) { + switch (type) { + case GrTextureType::k2D: + return false; + case GrTextureType::kRectangle: + return true; + case GrTextureType::kExternal: + return true; + default: + SK_ABORT("Unexpected texture type"); + } +} + +////////////////////////////////////////////////////////////////////////////// + +/** + * Types used to describe format of vertices in arrays. + */ +enum GrVertexAttribType { + kFloat_GrVertexAttribType = 0, + kFloat2_GrVertexAttribType, + kFloat3_GrVertexAttribType, + kFloat4_GrVertexAttribType, + kHalf_GrVertexAttribType, + kHalf2_GrVertexAttribType, + kHalf4_GrVertexAttribType, + + kInt2_GrVertexAttribType, // vector of 2 32-bit ints + kInt3_GrVertexAttribType, // vector of 3 32-bit ints + kInt4_GrVertexAttribType, // vector of 4 32-bit ints + + + kByte_GrVertexAttribType, // signed byte + kByte2_GrVertexAttribType, // vector of 2 8-bit signed bytes + kByte4_GrVertexAttribType, // vector of 4 8-bit signed bytes + kUByte_GrVertexAttribType, // unsigned byte + kUByte2_GrVertexAttribType, // vector of 2 8-bit unsigned bytes + kUByte4_GrVertexAttribType, // vector of 4 8-bit unsigned bytes + + kUByte_norm_GrVertexAttribType, // unsigned byte, e.g. coverage, 0 -> 0.0f, 255 -> 1.0f. + kUByte4_norm_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors, 0 -> 0.0f, + // 255 -> 1.0f. + + kShort2_GrVertexAttribType, // vector of 2 16-bit shorts. + kShort4_GrVertexAttribType, // vector of 4 16-bit shorts. + + kUShort2_GrVertexAttribType, // vector of 2 unsigned shorts. 0 -> 0, 65535 -> 65535. + kUShort2_norm_GrVertexAttribType, // vector of 2 unsigned shorts. 0 -> 0.0f, 65535 -> 1.0f. + + kInt_GrVertexAttribType, + kUInt_GrVertexAttribType, + + kUShort_norm_GrVertexAttribType, + + kUShort4_norm_GrVertexAttribType, // vector of 4 unsigned shorts. 0 -> 0.0f, 65535 -> 1.0f. + + kLast_GrVertexAttribType = kUShort4_norm_GrVertexAttribType +}; +static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; + +////////////////////////////////////////////////////////////////////////////// + +/** + * We have coverage effects that clip rendering to the edge of some geometric primitive. + * This enum specifies how that clipping is performed. Not all factories that take a + * GrClipEdgeType will succeed with all values and it is up to the caller to verify success. + */ +enum class GrClipEdgeType { + kFillBW, + kFillAA, + kInverseFillBW, + kInverseFillAA, + + kLast = kInverseFillAA +}; +static const int kGrClipEdgeTypeCnt = (int) GrClipEdgeType::kLast + 1; + +static constexpr bool GrClipEdgeTypeIsFill(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kFillAA == edgeType || GrClipEdgeType::kFillBW == edgeType); +} + +static constexpr bool GrClipEdgeTypeIsInverseFill(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kInverseFillAA == edgeType || + GrClipEdgeType::kInverseFillBW == edgeType); +} + +static constexpr bool GrClipEdgeTypeIsAA(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kFillBW != edgeType && + GrClipEdgeType::kInverseFillBW != edgeType); +} + +static inline GrClipEdgeType GrInvertClipEdgeType(const GrClipEdgeType edgeType) { + switch (edgeType) { + case GrClipEdgeType::kFillBW: + return GrClipEdgeType::kInverseFillBW; + case GrClipEdgeType::kFillAA: + return GrClipEdgeType::kInverseFillAA; + case GrClipEdgeType::kInverseFillBW: + return GrClipEdgeType::kFillBW; + case GrClipEdgeType::kInverseFillAA: + return GrClipEdgeType::kFillAA; + } + SkUNREACHABLE; +} + +/** + * Indicates the type of pending IO operations that can be recorded for gpu resources. + */ +enum GrIOType { + kRead_GrIOType, + kWrite_GrIOType, + kRW_GrIOType +}; + +/** + * Indicates the type of data that a GPU buffer will be used for. + */ +enum class GrGpuBufferType { + kVertex, + kIndex, + kDrawIndirect, + kXferCpuToGpu, + kXferGpuToCpu, + kUniform, +}; +static const constexpr int kGrGpuBufferTypeCount = static_cast(GrGpuBufferType::kUniform) + 1; + +/** + * Provides a performance hint regarding the frequency at which a data store will be accessed. + */ +enum GrAccessPattern { + /** Data store will be respecified repeatedly and used many times. */ + kDynamic_GrAccessPattern, + /** Data store will be specified once and used many times. (Thus disqualified from caching.) */ + kStatic_GrAccessPattern, + /** Data store will be specified once and used at most a few times. (Also can't be cached.) */ + kStream_GrAccessPattern, + + kLast_GrAccessPattern = kStream_GrAccessPattern +}; + +// Flags shared between the GrSurface & GrSurfaceProxy class hierarchies +enum class GrInternalSurfaceFlags { + kNone = 0, + + // Texture-level + + // Means the pixels in the texture are read-only. Cannot also be a GrRenderTarget[Proxy]. + kReadOnly = 1 << 0, + + // RT-level + + // This flag is for use with GL only. It tells us that the internal render target wraps FBO 0. + kGLRTFBOIDIs0 = 1 << 1, + + // This means the render target is multisampled, and internally holds a non-msaa texture for + // resolving into. The render target resolves itself by blitting into this internal texture. + // (asTexture() might or might not return the internal texture, but if it does, we always + // resolve the render target before accessing this texture's data.) + kRequiresManualMSAAResolve = 1 << 2, + + // This means the pixels in the render target are write-only. This is used for Dawn and Metal + // swap chain targets which can be rendered to, but not read or copied. + kFramebufferOnly = 1 << 3, + + // This is a Vulkan only flag. If set the surface can be used as an input attachment in a + // shader. This is used for doing in shader blending where we want to sample from the same + // image we are drawing to. + kVkRTSupportsInputAttachment = 1 << 4, +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags) + +// 'GR_MAKE_BITFIELD_CLASS_OPS' defines the & operator on GrInternalSurfaceFlags to return bool. +// We want to find the bitwise & with these masks, so we declare them as ints. +constexpr static int kGrInternalTextureFlagsMask = static_cast( + GrInternalSurfaceFlags::kReadOnly); + +// We don't include kVkRTSupportsInputAttachment in this mask since we check it manually. We don't +// require that both the surface and proxy have matching values for this flag. Instead we require +// if the proxy has it set then the surface must also have it set. All other flags listed here must +// match on the proxy and surface. +// TODO: Add back kFramebufferOnly flag here once we update SkSurfaceCharacterization to take it +// as a flag. skbug.com/10672 +constexpr static int kGrInternalRenderTargetFlagsMask = static_cast( + GrInternalSurfaceFlags::kGLRTFBOIDIs0 | + GrInternalSurfaceFlags::kRequiresManualMSAAResolve/* | + GrInternalSurfaceFlags::kFramebufferOnly*/); + +constexpr static int kGrInternalTextureRenderTargetFlagsMask = + kGrInternalTextureFlagsMask | kGrInternalRenderTargetFlagsMask; + +#ifdef SK_DEBUG +// Takes a pointer to a GrCaps, and will suppress prints if required +#define GrCapsDebugf(caps, ...) if (!(caps)->suppressPrints()) SkDebugf(__VA_ARGS__) +#else +#define GrCapsDebugf(caps, ...) do {} while (0) +#endif + +/** + * Specifies if the holder owns the backend, OpenGL or Vulkan, object. + */ +enum class GrBackendObjectOwnership : bool { + /** Holder does not destroy the backend object. */ + kBorrowed = false, + /** Holder destroys the backend object. */ + kOwned = true +}; + +/* + * Object for CPU-GPU synchronization + */ +typedef uint64_t GrFence; + +/** + * Used to include or exclude specific GPU path renderers for testing purposes. + */ +enum class GpuPathRenderers { + kNone = 0, // Always use software masks and/or DefaultPathRenderer. + kDashLine = 1 << 0, + kAtlas = 1 << 1, + kTessellation = 1 << 2, + kCoverageCounting = 1 << 3, + kAAHairline = 1 << 4, + kAAConvex = 1 << 5, + kAALinearizing = 1 << 6, + kSmall = 1 << 7, + kTriangulating = 1 << 8, + kDefault = ((1 << 9) - 1) // All path renderers. +}; + +/** + * Used to describe the current state of Mips on a GrTexture + */ +enum class GrMipmapStatus { + kNotAllocated, // Mips have not been allocated + kDirty, // Mips are allocated but the full mip tree does not have valid data + kValid, // All levels fully allocated and have valid data in them +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GpuPathRenderers) + +/** + * Like SkColorType this describes a layout of pixel data in CPU memory. It specifies the channels, + * their type, and width. This exists so that the GPU backend can have private types that have no + * analog in the public facing SkColorType enum and omit types not implemented in the GPU backend. + * It does not refer to a texture format and the mapping to texture formats may be many-to-many. + * It does not specify the sRGB encoding of the stored values. The components are listed in order of + * where they appear in memory. In other words the first component listed is in the low bits and + * the last component in the high bits. + */ +enum class GrColorType { + kUnknown, + kAlpha_8, + kBGR_565, + kABGR_4444, // This name differs from SkColorType. kARGB_4444_SkColorType is misnamed. + kRGBA_8888, + kRGBA_8888_SRGB, + kRGB_888x, + kRG_88, + kBGRA_8888, + kRGBA_1010102, + kBGRA_1010102, + kGray_8, + kGrayAlpha_88, + kAlpha_F16, + kRGBA_F16, + kRGBA_F16_Clamped, + kRGBA_F32, + + kAlpha_16, + kRG_1616, + kRG_F16, + kRGBA_16161616, + + // Unusual types that come up after reading back in cases where we are reassigning the meaning + // of a texture format's channels to use for a particular color format but have to read back the + // data to a full RGBA quadruple. (e.g. using a R8 texture format as A8 color type but the API + // only supports reading to RGBA8.) None of these have SkColorType equivalents. + kAlpha_8xxx, + kAlpha_F32xxx, + kGray_8xxx, + kR_8xxx, + + // Types used to initialize backend textures. + kRGB_888, + kR_8, + kR_16, + kR_F16, + kGray_F16, + kBGRA_4444, + kARGB_4444, + + kLast = kARGB_4444 +}; + +static const int kGrColorTypeCnt = static_cast(GrColorType::kLast) + 1; + +static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return kUnknown_SkColorType; + case GrColorType::kAlpha_8: return kAlpha_8_SkColorType; + case GrColorType::kBGR_565: return kRGB_565_SkColorType; + case GrColorType::kABGR_4444: return kARGB_4444_SkColorType; + case GrColorType::kRGBA_8888: return kRGBA_8888_SkColorType; + case GrColorType::kRGBA_8888_SRGB: return kSRGBA_8888_SkColorType; + case GrColorType::kRGB_888x: return kRGB_888x_SkColorType; + case GrColorType::kRG_88: return kR8G8_unorm_SkColorType; + case GrColorType::kBGRA_8888: return kBGRA_8888_SkColorType; + case GrColorType::kRGBA_1010102: return kRGBA_1010102_SkColorType; + case GrColorType::kBGRA_1010102: return kBGRA_1010102_SkColorType; + case GrColorType::kGray_8: return kGray_8_SkColorType; + case GrColorType::kGrayAlpha_88: return kUnknown_SkColorType; + case GrColorType::kAlpha_F16: return kA16_float_SkColorType; + case GrColorType::kRGBA_F16: return kRGBA_F16_SkColorType; + case GrColorType::kRGBA_F16_Clamped: return kRGBA_F16Norm_SkColorType; + case GrColorType::kRGBA_F32: return kRGBA_F32_SkColorType; + case GrColorType::kAlpha_8xxx: return kUnknown_SkColorType; + case GrColorType::kAlpha_F32xxx: return kUnknown_SkColorType; + case GrColorType::kGray_8xxx: return kUnknown_SkColorType; + case GrColorType::kR_8xxx: return kUnknown_SkColorType; + case GrColorType::kAlpha_16: return kA16_unorm_SkColorType; + case GrColorType::kRG_1616: return kR16G16_unorm_SkColorType; + case GrColorType::kRGBA_16161616: return kR16G16B16A16_unorm_SkColorType; + case GrColorType::kRG_F16: return kR16G16_float_SkColorType; + case GrColorType::kRGB_888: return kUnknown_SkColorType; + case GrColorType::kR_8: return kR8_unorm_SkColorType; + case GrColorType::kR_16: return kUnknown_SkColorType; + case GrColorType::kR_F16: return kUnknown_SkColorType; + case GrColorType::kGray_F16: return kUnknown_SkColorType; + case GrColorType::kARGB_4444: return kUnknown_SkColorType; + case GrColorType::kBGRA_4444: return kUnknown_SkColorType; + } + SkUNREACHABLE; +} + +static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct) { + switch (ct) { + case kUnknown_SkColorType: return GrColorType::kUnknown; + case kAlpha_8_SkColorType: return GrColorType::kAlpha_8; + case kRGB_565_SkColorType: return GrColorType::kBGR_565; + case kARGB_4444_SkColorType: return GrColorType::kABGR_4444; + case kRGBA_8888_SkColorType: return GrColorType::kRGBA_8888; + case kSRGBA_8888_SkColorType: return GrColorType::kRGBA_8888_SRGB; + case kRGB_888x_SkColorType: return GrColorType::kRGB_888x; + case kBGRA_8888_SkColorType: return GrColorType::kBGRA_8888; + case kGray_8_SkColorType: return GrColorType::kGray_8; + case kRGBA_F16Norm_SkColorType: return GrColorType::kRGBA_F16_Clamped; + case kRGBA_F16_SkColorType: return GrColorType::kRGBA_F16; + case kRGBA_1010102_SkColorType: return GrColorType::kRGBA_1010102; + case kRGB_101010x_SkColorType: return GrColorType::kUnknown; + case kBGRA_1010102_SkColorType: return GrColorType::kBGRA_1010102; + case kBGR_101010x_SkColorType: return GrColorType::kUnknown; + case kBGR_101010x_XR_SkColorType: return GrColorType::kUnknown; + case kRGBA_F32_SkColorType: return GrColorType::kRGBA_F32; + case kR8G8_unorm_SkColorType: return GrColorType::kRG_88; + case kA16_unorm_SkColorType: return GrColorType::kAlpha_16; + case kR16G16_unorm_SkColorType: return GrColorType::kRG_1616; + case kA16_float_SkColorType: return GrColorType::kAlpha_F16; + case kR16G16_float_SkColorType: return GrColorType::kRG_F16; + case kR16G16B16A16_unorm_SkColorType: return GrColorType::kRGBA_16161616; + case kR8_unorm_SkColorType: return GrColorType::kR_8; + } + SkUNREACHABLE; +} + +static constexpr uint32_t GrColorTypeChannelFlags(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return 0; + case GrColorType::kAlpha_8: return kAlpha_SkColorChannelFlag; + case GrColorType::kBGR_565: return kRGB_SkColorChannelFlags; + case GrColorType::kABGR_4444: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_8888: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_8888_SRGB: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGB_888x: return kRGB_SkColorChannelFlags; + case GrColorType::kRG_88: return kRG_SkColorChannelFlags; + case GrColorType::kBGRA_8888: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_1010102: return kRGBA_SkColorChannelFlags; + case GrColorType::kBGRA_1010102: return kRGBA_SkColorChannelFlags; + case GrColorType::kGray_8: return kGray_SkColorChannelFlag; + case GrColorType::kGrayAlpha_88: return kGrayAlpha_SkColorChannelFlags; + case GrColorType::kAlpha_F16: return kAlpha_SkColorChannelFlag; + case GrColorType::kRGBA_F16: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_F16_Clamped: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_F32: return kRGBA_SkColorChannelFlags; + case GrColorType::kAlpha_8xxx: return kAlpha_SkColorChannelFlag; + case GrColorType::kAlpha_F32xxx: return kAlpha_SkColorChannelFlag; + case GrColorType::kGray_8xxx: return kGray_SkColorChannelFlag; + case GrColorType::kR_8xxx: return kRed_SkColorChannelFlag; + case GrColorType::kAlpha_16: return kAlpha_SkColorChannelFlag; + case GrColorType::kRG_1616: return kRG_SkColorChannelFlags; + case GrColorType::kRGBA_16161616: return kRGBA_SkColorChannelFlags; + case GrColorType::kRG_F16: return kRG_SkColorChannelFlags; + case GrColorType::kRGB_888: return kRGB_SkColorChannelFlags; + case GrColorType::kR_8: return kRed_SkColorChannelFlag; + case GrColorType::kR_16: return kRed_SkColorChannelFlag; + case GrColorType::kR_F16: return kRed_SkColorChannelFlag; + case GrColorType::kGray_F16: return kGray_SkColorChannelFlag; + case GrColorType::kARGB_4444: return kRGBA_SkColorChannelFlags; + case GrColorType::kBGRA_4444: return kRGBA_SkColorChannelFlags; + } + SkUNREACHABLE; +} + +/** + * Describes the encoding of channel data in a GrColorType. + */ +enum class GrColorTypeEncoding { + kUnorm, + kSRGBUnorm, + // kSnorm, + kFloat, + // kSint + // kUint +}; + +/** + * Describes a GrColorType by how many bits are used for each color component and how they are + * encoded. Currently all the non-zero channels share a single GrColorTypeEncoding. This could be + * expanded to store separate encodings and to indicate which bits belong to which components. + */ +class GrColorFormatDesc { +public: + static constexpr GrColorFormatDesc MakeRGBA(int rgba, GrColorTypeEncoding e) { + return {rgba, rgba, rgba, rgba, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRGBA(int rgb, int a, GrColorTypeEncoding e) { + return {rgb, rgb, rgb, a, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRGB(int rgb, GrColorTypeEncoding e) { + return {rgb, rgb, rgb, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRGB(int r, int g, int b, GrColorTypeEncoding e) { + return {r, g, b, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeAlpha(int a, GrColorTypeEncoding e) { + return {0, 0, 0, a, 0, e}; + } + + static constexpr GrColorFormatDesc MakeR(int r, GrColorTypeEncoding e) { + return {r, 0, 0, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRG(int rg, GrColorTypeEncoding e) { + return {rg, rg, 0, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeGray(int grayBits, GrColorTypeEncoding e) { + return {0, 0, 0, 0, grayBits, e}; + } + + static constexpr GrColorFormatDesc MakeGrayAlpha(int grayAlpha, GrColorTypeEncoding e) { + return {0, 0, 0, 0, grayAlpha, e}; + } + + static constexpr GrColorFormatDesc MakeInvalid() { return {}; } + + constexpr int r() const { return fRBits; } + constexpr int g() const { return fGBits; } + constexpr int b() const { return fBBits; } + constexpr int a() const { return fABits; } + constexpr int operator[](int c) const { + switch (c) { + case 0: return this->r(); + case 1: return this->g(); + case 2: return this->b(); + case 3: return this->a(); + } + SkUNREACHABLE; + } + + constexpr int gray() const { return fGrayBits; } + + constexpr GrColorTypeEncoding encoding() const { return fEncoding; } + +private: + int fRBits = 0; + int fGBits = 0; + int fBBits = 0; + int fABits = 0; + int fGrayBits = 0; + GrColorTypeEncoding fEncoding = GrColorTypeEncoding::kUnorm; + + constexpr GrColorFormatDesc() = default; + + constexpr GrColorFormatDesc(int r, int g, int b, int a, int gray, GrColorTypeEncoding encoding) + : fRBits(r), fGBits(g), fBBits(b), fABits(a), fGrayBits(gray), fEncoding(encoding) { + SkASSERT(r >= 0 && g >= 0 && b >= 0 && a >= 0 && gray >= 0); + SkASSERT(!gray || (!r && !g && !b)); + SkASSERT(r || g || b || a || gray); + } +}; + +static constexpr GrColorFormatDesc GrGetColorTypeDesc(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: + return GrColorFormatDesc::MakeInvalid(); + case GrColorType::kAlpha_8: + return GrColorFormatDesc::MakeAlpha(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGR_565: + return GrColorFormatDesc::MakeRGB(5, 6, 5, GrColorTypeEncoding::kUnorm); + case GrColorType::kABGR_4444: + return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_8888: + return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_8888_SRGB: + return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kSRGBUnorm); + case GrColorType::kRGB_888x: + return GrColorFormatDesc::MakeRGB(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kRG_88: + return GrColorFormatDesc::MakeRG(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGRA_8888: + return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_1010102: + return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGRA_1010102: + return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm); + case GrColorType::kGray_8: + return GrColorFormatDesc::MakeGray(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kGrayAlpha_88: + return GrColorFormatDesc::MakeGrayAlpha(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kAlpha_F16: + return GrColorFormatDesc::MakeAlpha(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGBA_F16: + return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGBA_F16_Clamped: + return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGBA_F32: + return GrColorFormatDesc::MakeRGBA(32, GrColorTypeEncoding::kFloat); + case GrColorType::kAlpha_8xxx: + return GrColorFormatDesc::MakeAlpha(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kAlpha_F32xxx: + return GrColorFormatDesc::MakeAlpha(32, GrColorTypeEncoding::kFloat); + case GrColorType::kGray_8xxx: + return GrColorFormatDesc::MakeGray(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_8xxx: + return GrColorFormatDesc::MakeR(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kAlpha_16: + return GrColorFormatDesc::MakeAlpha(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kRG_1616: + return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_16161616: + return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kRG_F16: + return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGB_888: + return GrColorFormatDesc::MakeRGB(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_8: + return GrColorFormatDesc::MakeR(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_16: + return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_F16: + return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kFloat); + case GrColorType::kGray_F16: + return GrColorFormatDesc::MakeGray(16, GrColorTypeEncoding::kFloat); + case GrColorType::kARGB_4444: + return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGRA_4444: + return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); + } + SkUNREACHABLE; +} + +static constexpr GrClampType GrColorTypeClampType(GrColorType colorType) { + if (GrGetColorTypeDesc(colorType).encoding() == GrColorTypeEncoding::kUnorm || + GrGetColorTypeDesc(colorType).encoding() == GrColorTypeEncoding::kSRGBUnorm) { + return GrClampType::kAuto; + } + return GrColorType::kRGBA_F16_Clamped == colorType ? GrClampType::kManual : GrClampType::kNone; +} + +// Consider a color type "wider" than n if it has more than n bits for any its representable +// channels. +static constexpr bool GrColorTypeIsWiderThan(GrColorType colorType, int n) { + SkASSERT(n > 0); + auto desc = GrGetColorTypeDesc(colorType); + return (desc.r() && desc.r() > n )|| + (desc.g() && desc.g() > n) || + (desc.b() && desc.b() > n) || + (desc.a() && desc.a() > n) || + (desc.gray() && desc.gray() > n); +} + +static constexpr bool GrColorTypeIsAlphaOnly(GrColorType ct) { + return GrColorTypeChannelFlags(ct) == kAlpha_SkColorChannelFlag; +} + +static constexpr bool GrColorTypeHasAlpha(GrColorType ct) { + return GrColorTypeChannelFlags(ct) & kAlpha_SkColorChannelFlag; +} + +static constexpr size_t GrColorTypeBytesPerPixel(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return 0; + case GrColorType::kAlpha_8: return 1; + case GrColorType::kBGR_565: return 2; + case GrColorType::kABGR_4444: return 2; + case GrColorType::kRGBA_8888: return 4; + case GrColorType::kRGBA_8888_SRGB: return 4; + case GrColorType::kRGB_888x: return 4; + case GrColorType::kRG_88: return 2; + case GrColorType::kBGRA_8888: return 4; + case GrColorType::kRGBA_1010102: return 4; + case GrColorType::kBGRA_1010102: return 4; + case GrColorType::kGray_8: return 1; + case GrColorType::kGrayAlpha_88: return 2; + case GrColorType::kAlpha_F16: return 2; + case GrColorType::kRGBA_F16: return 8; + case GrColorType::kRGBA_F16_Clamped: return 8; + case GrColorType::kRGBA_F32: return 16; + case GrColorType::kAlpha_8xxx: return 4; + case GrColorType::kAlpha_F32xxx: return 16; + case GrColorType::kGray_8xxx: return 4; + case GrColorType::kR_8xxx: return 4; + case GrColorType::kAlpha_16: return 2; + case GrColorType::kRG_1616: return 4; + case GrColorType::kRGBA_16161616: return 8; + case GrColorType::kRG_F16: return 4; + case GrColorType::kRGB_888: return 3; + case GrColorType::kR_8: return 1; + case GrColorType::kR_16: return 2; + case GrColorType::kR_F16: return 2; + case GrColorType::kGray_F16: return 2; + case GrColorType::kARGB_4444: return 2; + case GrColorType::kBGRA_4444: return 2; + } + SkUNREACHABLE; +} + +// In general we try to not mix CompressionType and ColorType, but currently SkImage still requires +// an SkColorType even for CompressedTypes so we need some conversion. +static constexpr SkColorType GrCompressionTypeToSkColorType(SkTextureCompressionType compression) { + switch (compression) { + case SkTextureCompressionType::kNone: return kUnknown_SkColorType; + case SkTextureCompressionType::kETC2_RGB8_UNORM: return kRGB_888x_SkColorType; + case SkTextureCompressionType::kBC1_RGB8_UNORM: return kRGB_888x_SkColorType; + case SkTextureCompressionType::kBC1_RGBA8_UNORM: return kRGBA_8888_SkColorType; + } + + SkUNREACHABLE; +} + +enum class GrDstSampleFlags { + kNone = 0, + kRequiresTextureBarrier = 1 << 0, + kAsInputAttachment = 1 << 1, +}; +GR_MAKE_BITFIELD_CLASS_OPS(GrDstSampleFlags) + +using GrVisitProxyFunc = std::function; + +#if defined(SK_DEBUG) || GR_TEST_UTILS || defined(SK_ENABLE_DUMP_GPU) +static constexpr const char* GrBackendApiToStr(GrBackendApi api) { + switch (api) { + case GrBackendApi::kOpenGL: return "OpenGL"; + case GrBackendApi::kVulkan: return "Vulkan"; + case GrBackendApi::kMetal: return "Metal"; + case GrBackendApi::kDirect3D: return "Direct3D"; + case GrBackendApi::kDawn: return "Dawn"; + case GrBackendApi::kMock: return "Mock"; + } + SkUNREACHABLE; +} + +static constexpr const char* GrColorTypeToStr(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return "kUnknown"; + case GrColorType::kAlpha_8: return "kAlpha_8"; + case GrColorType::kBGR_565: return "kRGB_565"; + case GrColorType::kABGR_4444: return "kABGR_4444"; + case GrColorType::kRGBA_8888: return "kRGBA_8888"; + case GrColorType::kRGBA_8888_SRGB: return "kRGBA_8888_SRGB"; + case GrColorType::kRGB_888x: return "kRGB_888x"; + case GrColorType::kRG_88: return "kRG_88"; + case GrColorType::kBGRA_8888: return "kBGRA_8888"; + case GrColorType::kRGBA_1010102: return "kRGBA_1010102"; + case GrColorType::kBGRA_1010102: return "kBGRA_1010102"; + case GrColorType::kGray_8: return "kGray_8"; + case GrColorType::kGrayAlpha_88: return "kGrayAlpha_88"; + case GrColorType::kAlpha_F16: return "kAlpha_F16"; + case GrColorType::kRGBA_F16: return "kRGBA_F16"; + case GrColorType::kRGBA_F16_Clamped: return "kRGBA_F16_Clamped"; + case GrColorType::kRGBA_F32: return "kRGBA_F32"; + case GrColorType::kAlpha_8xxx: return "kAlpha_8xxx"; + case GrColorType::kAlpha_F32xxx: return "kAlpha_F32xxx"; + case GrColorType::kGray_8xxx: return "kGray_8xxx"; + case GrColorType::kR_8xxx: return "kR_8xxx"; + case GrColorType::kAlpha_16: return "kAlpha_16"; + case GrColorType::kRG_1616: return "kRG_1616"; + case GrColorType::kRGBA_16161616: return "kRGBA_16161616"; + case GrColorType::kRG_F16: return "kRG_F16"; + case GrColorType::kRGB_888: return "kRGB_888"; + case GrColorType::kR_8: return "kR_8"; + case GrColorType::kR_16: return "kR_16"; + case GrColorType::kR_F16: return "kR_F16"; + case GrColorType::kGray_F16: return "kGray_F16"; + case GrColorType::kARGB_4444: return "kARGB_4444"; + case GrColorType::kBGRA_4444: return "kBGRA_4444"; + } + SkUNREACHABLE; +} + +static constexpr const char* GrCompressionTypeToStr(SkTextureCompressionType compression) { + switch (compression) { + case SkTextureCompressionType::kNone: return "kNone"; + case SkTextureCompressionType::kETC2_RGB8_UNORM: return "kETC2_RGB8_UNORM"; + case SkTextureCompressionType::kBC1_RGB8_UNORM: return "kBC1_RGB8_UNORM"; + case SkTextureCompressionType::kBC1_RGBA8_UNORM: return "kBC1_RGBA8_UNORM"; + } + SkUNREACHABLE; +} + +static constexpr const char* GrSurfaceOriginToStr(GrSurfaceOrigin origin) { + switch (origin) { + case kTopLeft_GrSurfaceOrigin: return "kTopLeft"; + case kBottomLeft_GrSurfaceOrigin: return "kBottomLeft"; + } + SkUNREACHABLE; +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrVkTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrVkTypesPriv.h new file mode 100644 index 00000000000000..f300a7139632be --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/ganesh/GrVkTypesPriv.h @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkTypesPriv_DEFINED +#define GrVkTypesPriv_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/vk/GrVkTypes.h" + +namespace skgpu { +class MutableTextureStateRef; +} + + +// This struct is to used to store the the actual information about the vulkan backend image on the +// GrBackendTexture and GrBackendRenderTarget. When a client calls getVkImageInfo on a +// GrBackendTexture/RenderTarget, we use the GrVkBackendSurfaceInfo to create a snapshot +// GrVkImgeInfo object. Internally, this uses a ref count GrVkImageLayout object to track the +// current VkImageLayout which can be shared with an internal GrVkImage so that layout updates can +// be seen by all users of the image. +struct GrVkBackendSurfaceInfo { + GrVkBackendSurfaceInfo(GrVkImageInfo info) : fImageInfo(info) {} + + void cleanup(); + + GrVkBackendSurfaceInfo& operator=(const GrVkBackendSurfaceInfo&) = delete; + + // Assigns the passed in GrVkBackendSurfaceInfo to this object. if isValid is true we will also + // attempt to unref the old fLayout on this object. + void assign(const GrVkBackendSurfaceInfo&, bool isValid); + + GrVkImageInfo snapImageInfo(const skgpu::MutableTextureStateRef*) const; + + bool isProtected() const { return fImageInfo.fProtected == skgpu::Protected::kYes; } +#if GR_TEST_UTILS + bool operator==(const GrVkBackendSurfaceInfo& that) const; +#endif + +private: + GrVkImageInfo fImageInfo; +}; + +struct GrVkImageSpec { + GrVkImageSpec() + : fImageTiling(VK_IMAGE_TILING_OPTIMAL) + , fFormat(VK_FORMAT_UNDEFINED) + , fImageUsageFlags(0) + , fSharingMode(VK_SHARING_MODE_EXCLUSIVE) {} + + GrVkImageSpec(const GrVkSurfaceInfo& info) + : fImageTiling(info.fImageTiling) + , fFormat(info.fFormat) + , fImageUsageFlags(info.fImageUsageFlags) + , fYcbcrConversionInfo(info.fYcbcrConversionInfo) + , fSharingMode(info.fSharingMode) {} + + VkImageTiling fImageTiling; + VkFormat fFormat; + VkImageUsageFlags fImageUsageFlags; + GrVkYcbcrConversionInfo fYcbcrConversionInfo; + VkSharingMode fSharingMode; +}; + +GrVkSurfaceInfo GrVkImageSpecToSurfaceInfo(const GrVkImageSpec& vkSpec, + uint32_t sampleCount, + uint32_t levelCount, + skgpu::Protected isProtected); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/DawnTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/DawnTypesPriv.h new file mode 100644 index 00000000000000..bbf401c95e48df --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/DawnTypesPriv.h @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_DawnTypesPriv_DEFINED +#define skgpu_graphite_DawnTypesPriv_DEFINED + +#include "include/gpu/graphite/dawn/DawnTypes.h" + +namespace skgpu::graphite { + +struct DawnTextureSpec { + DawnTextureSpec() + : fFormat(wgpu::TextureFormat::Undefined) + , fUsage(wgpu::TextureUsage::None) {} + DawnTextureSpec(const DawnTextureInfo& info) + : fFormat(info.fFormat) + , fUsage(info.fUsage) {} + + bool operator==(const DawnTextureSpec& that) const { + return fUsage == that.fUsage && + fFormat == that.fFormat; + } + + wgpu::TextureFormat fFormat; + wgpu::TextureUsage fUsage; +}; + +DawnTextureInfo DawnTextureSpecToTextureInfo(const DawnTextureSpec& dawnSpec, + uint32_t sampleCount, + Mipmapped mipmapped); + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_DawnTypesPriv_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/MtlGraphiteTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/MtlGraphiteTypesPriv.h new file mode 100644 index 00000000000000..bf26aa2a78ad30 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/MtlGraphiteTypesPriv.h @@ -0,0 +1,74 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_MtlGraphiteTypesPriv_DEFINED +#define skgpu_graphite_MtlGraphiteTypesPriv_DEFINED + +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/gpu/graphite/mtl/MtlGraphiteTypes.h" + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ + +#include + +// We're using the MSL version as shorthand for the Metal SDK version here +#if defined(SK_BUILD_FOR_MAC) +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 +#define GR_METAL_SDK_VERSION 230 +#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 120000 +#define GR_METAL_SDK_VERSION 240 +#else +#error Must use at least 11.00 SDK to build Metal backend for MacOS +#endif +#else +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 || __TV_OS_VERSION_MAX_ALLOWED >= 140000 +#define GR_METAL_SDK_VERSION 230 +#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 || __TV_OS_VERSION_MAX_ALLOWED >= 150000 +#define GR_METAL_SDK_VERSION 240 +#else +#error Must use at least 14.00 SDK to build Metal backend for iOS +#endif +#endif + +#endif // __APPLE__ + +namespace skgpu::graphite { + +struct MtlTextureSpec { + MtlTextureSpec() + : fFormat(0) + , fUsage(0) + , fStorageMode(0) + , fFramebufferOnly(false) {} + MtlTextureSpec(const MtlTextureInfo& info) + : fFormat(info.fFormat) + , fUsage(info.fUsage) + , fStorageMode(info.fStorageMode) + , fFramebufferOnly(info.fFramebufferOnly) {} + + bool operator==(const MtlTextureSpec& that) const { + return fFormat == that.fFormat && + fUsage == that.fUsage && + fStorageMode == that.fStorageMode && + fFramebufferOnly == that.fFramebufferOnly; + } + + MtlPixelFormat fFormat; + MtlTextureUsage fUsage; + MtlStorageMode fStorageMode; + bool fFramebufferOnly; +}; + +MtlTextureInfo MtlTextureSpecToTextureInfo(const MtlTextureSpec& mtlSpec, + uint32_t sampleCount, + Mipmapped mipmapped); + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_MtlGraphiteTypesPriv_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/VulkanGraphiteTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/VulkanGraphiteTypesPriv.h new file mode 100644 index 00000000000000..b4304e3ae89883 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/graphite/VulkanGraphiteTypesPriv.h @@ -0,0 +1,55 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_VulkanGraphiteTypesPriv_DEFINED +#define skgpu_graphite_VulkanGraphiteTypesPriv_DEFINED + +#include "include/gpu/graphite/vk/VulkanGraphiteTypes.h" + +namespace skgpu::graphite { + +struct VulkanTextureSpec { + VulkanTextureSpec() + : fFlags(0) + , fFormat(VK_FORMAT_UNDEFINED) + , fImageTiling(VK_IMAGE_TILING_OPTIMAL) + , fImageUsageFlags(0) + , fSharingMode(VK_SHARING_MODE_EXCLUSIVE) + , fAspectMask(VK_IMAGE_ASPECT_COLOR_BIT) {} + VulkanTextureSpec(const VulkanTextureInfo& info) + : fFlags(info.fFlags) + , fFormat(info.fFormat) + , fImageTiling(info.fImageTiling) + , fImageUsageFlags(info.fImageUsageFlags) + , fSharingMode(info.fSharingMode) + , fAspectMask(info.fAspectMask) {} + + bool operator==(const VulkanTextureSpec& that) const { + return fFlags == that.fFlags && + fFormat == that.fFormat && + fImageTiling == that.fImageTiling && + fImageUsageFlags == that.fImageUsageFlags && + fSharingMode == that.fSharingMode && + fAspectMask == that.fAspectMask; + } + + VkImageCreateFlags fFlags; + VkFormat fFormat; + VkImageTiling fImageTiling; + VkImageUsageFlags fImageUsageFlags; + VkSharingMode fSharingMode; + VkImageAspectFlags fAspectMask; + // GrVkYcbcrConversionInfo fYcbcrConversionInfo; +}; + +VulkanTextureInfo VulkanTextureSpecToTextureInfo(const VulkanTextureSpec& vkSpec, + uint32_t sampleCount, + Mipmapped mipmapped); + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_VulkanGraphiteTypesPriv_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/vk/SkiaVulkan.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/vk/SkiaVulkan.h new file mode 100644 index 00000000000000..ca4bcf108bf459 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/vk/SkiaVulkan.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkiaVulkan_DEFINED +#define SkiaVulkan_DEFINED + +#include "include/core/SkTypes.h" + +// IWYU pragma: begin_exports + +#if SKIA_IMPLEMENTATION || !defined(SK_VULKAN) +#include "include/third_party/vulkan/vulkan/vulkan_core.h" +#else +// For google3 builds we don't set SKIA_IMPLEMENTATION so we need to make sure that the vulkan +// headers stay up to date for our needs +#include +#endif + +#ifdef SK_BUILD_FOR_ANDROID +// This is needed to get android extensions for external memory +#if SKIA_IMPLEMENTATION || !defined(SK_VULKAN) +#include "include/third_party/vulkan/vulkan/vulkan_android.h" +#else +// For google3 builds we don't set SKIA_IMPLEMENTATION so we need to make sure that the vulkan +// headers stay up to date for our needs +#include +#endif +#endif + +// IWYU pragma: end_exports + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/vk/VulkanTypesPriv.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/vk/VulkanTypesPriv.h new file mode 100644 index 00000000000000..e99869ca1a0c6f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/private/gpu/vk/VulkanTypesPriv.h @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_VulkanTypesPriv_DEFINED +#define skgpu_VulkanTypesPriv_DEFINED + +#include "include/gpu/vk/VulkanTypes.h" + +#include + +namespace skgpu { + +class VulkanMutableTextureState { +public: + VulkanMutableTextureState(VkImageLayout layout, uint32_t queueFamilyIndex) + : fLayout(layout) + , fQueueFamilyIndex(queueFamilyIndex) {} + + VulkanMutableTextureState& operator=(const VulkanMutableTextureState& that) { + fLayout = that.getImageLayout(); + fQueueFamilyIndex = that.getQueueFamilyIndex(); + return *this; + } + + void setImageLayout(VkImageLayout layout) { + // Defaulting to use std::memory_order_seq_cst + fLayout.store(layout); + } + + VkImageLayout getImageLayout() const { + // Defaulting to use std::memory_order_seq_cst + return fLayout.load(); + } + + void setQueueFamilyIndex(uint32_t queueFamilyIndex) { + // Defaulting to use std::memory_order_seq_cst + fQueueFamilyIndex.store(queueFamilyIndex); + } + + uint32_t getQueueFamilyIndex() const { + // Defaulting to use std::memory_order_seq_cst + return fQueueFamilyIndex.load(); + } + +private: + std::atomic fLayout; + std::atomic fQueueFamilyIndex; +}; + +} // namespace skgpu + +#endif // skgpu_VulkanGraphiteTypesPriv_DEFINED + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/sksl/SkSLDebugTrace.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/sksl/SkSLDebugTrace.h new file mode 100644 index 00000000000000..9c5eafbc94ed57 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/sksl/SkSLDebugTrace.h @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Google LLC. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_DEBUG_TRACE +#define SKSL_DEBUG_TRACE + +#include "include/core/SkRefCnt.h" + +class SkWStream; + +namespace SkSL { + +class DebugTrace : public SkRefCnt { +public: + /** Serializes a debug trace to JSON which can be parsed by our debugger. */ + virtual void writeTrace(SkWStream* w) const = 0; + + /** Generates a human-readable dump of the debug trace. */ + virtual void dump(SkWStream* o) const = 0; +}; + +} // namespace SkSL + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/sksl/SkSLVersion.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/sksl/SkSLVersion.h new file mode 100644 index 00000000000000..ad059d580ef899 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/sksl/SkSLVersion.h @@ -0,0 +1,27 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSLVersion_DEFINED +#define SkSLVersion_DEFINED + +namespace SkSL { + +enum class Version { + /** + * Desktop GLSL 1.10, GLSL ES 1.00, WebGL 1.0 + */ + k100, + + /** + * Desktop GLSL 3.30, GLSL ES 3.00, WebGL 2.0 + */ + k300, +}; + +} // namespace SkSL + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/svg/SkSVGCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/svg/SkSVGCanvas.h new file mode 100644 index 00000000000000..d4c38ea01773a7 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/svg/SkSVGCanvas.h @@ -0,0 +1,42 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGCanvas_DEFINED +#define SkSVGCanvas_DEFINED + +#include "include/core/SkTypes.h" + +#include +#include + +class SkCanvas; +class SkWStream; +struct SkRect; + +class SK_API SkSVGCanvas { +public: + enum { + kConvertTextToPaths_Flag = 0x01, // emit text as s + kNoPrettyXML_Flag = 0x02, // suppress newlines and tabs in output + kRelativePathEncoding_Flag = 0x04, // use relative commands for path encoding + }; + + /** + * Returns a new canvas that will generate SVG commands from its draw calls, and send + * them to the provided stream. Ownership of the stream is not transfered, and it must + * remain valid for the lifetime of the returned canvas. + * + * The canvas may buffer some drawing calls, so the output is not guaranteed to be valid + * or complete until the canvas instance is deleted. + * + * The 'bounds' parameter defines an initial SVG viewport (viewBox attribute on the root + * SVG element). + */ + static std::unique_ptr Make(const SkRect& bounds, SkWStream*, uint32_t flags = 0); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vk_platform.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vk_platform.h new file mode 100644 index 00000000000000..18b913abc6ad9e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vk_platform.h @@ -0,0 +1,84 @@ +// +// File: vk_platform.h +// +/* +** Copyright 2014-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + + +#ifndef VK_PLATFORM_H_ +#define VK_PLATFORM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* +*************************************************************************************************** +* Platform-specific directives and type declarations +*************************************************************************************************** +*/ + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that Vulkan clients call Vulkan commands + * with the same calling conventions that the Vulkan implementation expects. + * + * VKAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * VKAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); + * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); + */ +#if defined(_WIN32) + // On Windows, Vulkan commands use the stdcall convention + #define VKAPI_ATTR + #define VKAPI_CALL __stdcall + #define VKAPI_PTR VKAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 + #error "Vulkan isn't supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) + // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" + // calling convention, i.e. float parameters are passed in registers. This + // is true even if the rest of the application passes floats on the stack, + // as it does by default when compiling for the armeabi-v7a NDK ABI. + #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) + #define VKAPI_CALL + #define VKAPI_PTR VKAPI_ATTR +#else + // On other platforms, use the default calling convention + #define VKAPI_ATTR + #define VKAPI_CALL + #define VKAPI_PTR +#endif + +#if !defined(VK_NO_STDDEF_H) + #include +#endif // !defined(VK_NO_STDDEF_H) + +#if !defined(VK_NO_STDINT_H) + #if defined(_MSC_VER) && (_MSC_VER < 1600) + typedef signed __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef signed __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + #else + #include + #endif +#endif // !defined(VK_NO_STDINT_H) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan.h new file mode 100644 index 00000000000000..b187c9c178b6ca --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan.h @@ -0,0 +1,93 @@ +#ifndef VULKAN_H_ +#define VULKAN_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +#include "vk_platform.h" +#include "vulkan_core.h" + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +#include "vulkan_android.h" +#endif + +#ifdef VK_USE_PLATFORM_FUCHSIA +#include +#include "vulkan_fuchsia.h" +#endif + +#ifdef VK_USE_PLATFORM_IOS_MVK +#include "vulkan_ios.h" +#endif + + +#ifdef VK_USE_PLATFORM_MACOS_MVK +#include "vulkan_macos.h" +#endif + +#ifdef VK_USE_PLATFORM_METAL_EXT +#include "vulkan_metal.h" +#endif + +#ifdef VK_USE_PLATFORM_VI_NN +#include "vulkan_vi.h" +#endif + + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include +#include "vulkan_wayland.h" +#endif + + +#ifdef VK_USE_PLATFORM_WIN32_KHR +#include +#include "vulkan_win32.h" +#endif + + +#ifdef VK_USE_PLATFORM_XCB_KHR +#include +#include "vulkan_xcb.h" +#endif + + +#ifdef VK_USE_PLATFORM_XLIB_KHR +#include +#include "vulkan_xlib.h" +#endif + + +#ifdef VK_USE_PLATFORM_DIRECTFB_EXT +#include +#include "vulkan_directfb.h" +#endif + + +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT +#include +#include +#include "vulkan_xlib_xrandr.h" +#endif + + +#ifdef VK_USE_PLATFORM_GGP +#include +#include "vulkan_ggp.h" +#endif + + +#ifdef VK_USE_PLATFORM_SCREEN_QNX +#include +#include "vulkan_screen.h" +#endif + + +#ifdef VK_ENABLE_BETA_EXTENSIONS +#include "vulkan_beta.h" +#endif + +#endif // VULKAN_H_ diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_android.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_android.h new file mode 100644 index 00000000000000..2160e3e7c602ff --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_android.h @@ -0,0 +1,112 @@ +#ifndef VULKAN_ANDROID_H_ +#define VULKAN_ANDROID_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_KHR_android_surface 1 +struct ANativeWindow; +#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 +#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + struct ANativeWindow* window; +} VkAndroidSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( + VkInstance instance, + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +#define VK_ANDROID_external_memory_android_hardware_buffer 1 +struct AHardwareBuffer; +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" +typedef struct VkAndroidHardwareBufferUsageANDROID { + VkStructureType sType; + void* pNext; + uint64_t androidHardwareBufferUsage; +} VkAndroidHardwareBufferUsageANDROID; + +typedef struct VkAndroidHardwareBufferPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkAndroidHardwareBufferPropertiesANDROID; + +typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatPropertiesANDROID; + +typedef struct VkImportAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + struct AHardwareBuffer* buffer; +} VkImportAndroidHardwareBufferInfoANDROID; + +typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkMemoryGetAndroidHardwareBufferInfoANDROID; + +typedef struct VkExternalFormatANDROID { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatANDROID; + +typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID( + VkDevice device, + const struct AHardwareBuffer* buffer, + VkAndroidHardwareBufferPropertiesANDROID* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( + VkDevice device, + const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, + struct AHardwareBuffer** pBuffer); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_core.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_core.h new file mode 100644 index 00000000000000..3b4fe629ce746f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_core.h @@ -0,0 +1,12620 @@ +#ifndef VULKAN_CORE_H_ +#define VULKAN_CORE_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_VERSION_1_0 1 +#include "vk_platform.h" + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#ifndef VK_USE_64_BIT_PTR_DEFINES + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_USE_64_BIT_PTR_DEFINES 1 + #else + #define VK_USE_64_BIT_PTR_DEFINES 0 + #endif +#endif + + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #if __cplusplus >= 201103L || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) + #define VK_NULL_HANDLE nullptr + #else + #define VK_NULL_HANDLE ((void*)0) + #endif + #else + #define VK_NULL_HANDLE 0ULL + #endif +#endif +#ifndef VK_NULL_HANDLE + #define VK_NULL_HANDLE 0 +#endif + + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; + #else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + #endif +#endif + +// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. +#define VK_MAKE_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) + +// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 + +#define VK_MAKE_API_VERSION(variant, major, minor, patch) \ + ((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) + +// Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 + +// Version of this file +#define VK_HEADER_VERSION 176 + +// Complete version of this file +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 2, VK_HEADER_VERSION) + +// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) + +// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) + +// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) + +#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29) +#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU) +#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) +#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +typedef uint32_t VkBool32; +typedef uint64_t VkDeviceAddress; +typedef uint64_t VkDeviceSize; +typedef uint32_t VkFlags; +typedef uint32_t VkSampleMask; +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkPhysicalDevice) +VK_DEFINE_HANDLE(VkDevice) +VK_DEFINE_HANDLE(VkQueue) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +VK_DEFINE_HANDLE(VkCommandBuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) +#define VK_ATTACHMENT_UNUSED (~0U) +#define VK_FALSE 0U +#define VK_LOD_CLAMP_NONE 1000.0F +#define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_REMAINING_ARRAY_LAYERS (~0U) +#define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_SUBPASS_EXTERNAL (~0U) +#define VK_TRUE 1U +#define VK_WHOLE_SIZE (~0ULL) +#define VK_MAX_MEMORY_TYPES 32U +#define VK_MAX_MEMORY_HEAPS 16U +#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256U +#define VK_UUID_SIZE 16U +#define VK_MAX_EXTENSION_NAME_SIZE 256U +#define VK_MAX_DESCRIPTION_SIZE 256U + +typedef enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_FRAGMENTED_POOL = -12, + VK_ERROR_UNKNOWN = -13, + VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, + VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, + VK_ERROR_FRAGMENTATION = -1000161000, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, + VK_ERROR_NOT_PERMITTED_EXT = -1000174001, + VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, + VK_THREAD_IDLE_KHR = 1000268000, + VK_THREAD_DONE_KHR = 1000268001, + VK_OPERATION_DEFERRED_KHR = 1000268002, + VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, + VK_PIPELINE_COMPILE_REQUIRED_EXT = 1000297000, + VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, + VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, + VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, + VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED_EXT, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +} VkResult; + +typedef enum VkStructureType { + VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, + VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, + VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, + VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, + VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, + VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, + VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, + VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2 = 1000109000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2 = 1000109001, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2 = 1000109002, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2 = 1000109003, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2 = 1000109004, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO = 1000109005, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO = 1000109006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO = 1000207002, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO = 1000207004, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO = 1000207005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, + VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, + VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, + VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, + VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, + VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, + VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, + VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR = 1000023000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR = 1000023001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_KHR = 1000023002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_GET_MEMORY_PROPERTIES_KHR = 1000023003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_BIND_MEMORY_KHR = 1000023004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR = 1000023005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR = 1000023006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR = 1000023007, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR = 1000023008, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR = 1000023009, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR = 1000023010, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_KHR = 1000023011, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000023012, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR = 1000023013, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR = 1000023014, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR = 1000023015, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR = 1000024000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR = 1000299000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR = 1000299001, +#endif + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, + VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT = 1000038001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT = 1000038006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT = 1000038007, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT = 1000038008, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT = 1000040000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT = 1000040001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT = 1000040003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT = 1000040004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040006, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040007, +#endif + VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, + VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, + VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = 1000066000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, + VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000, + VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, + VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002, + VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, + VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, + VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, + VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, + VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, + VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, + VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, + VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, + VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, + VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, + VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, + VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, + VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, + VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, + VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, + VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, + VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, + VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, + VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, + VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, + VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, + VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, + VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003, + VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, + VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, + VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, + VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, + VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, + VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, + VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, + VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, + VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, + VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, +#endif + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, + VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, + VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, + VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, + VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, + VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, + VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT = 1000187000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT = 1000187001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187003, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT = 1000187004, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187005, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187006, +#endif + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, + VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = 1000203000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, + VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, + VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, + VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL = 1000210002, + VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, + VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, + VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, + VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, + VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = 1000215000, + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = 1000225000, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = 1000225001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = 1000225002, + VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, + VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, + VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR = 1000239000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = 1000245000, + VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, + VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, + VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, + VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, + VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, + VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, + VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, + VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, + VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, + VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, + VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, + VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, + VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = 1000295002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = 1000297000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, + VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = 1000314000, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = 1000314001, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = 1000314002, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = 1000314003, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = 1000314004, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = 1000314005, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = 1000314006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = 1000314007, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = 1000325000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, + VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = 1000335000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = 1000337000, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = 1000337001, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = 1000337002, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = 1000337003, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = 1000337004, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = 1000337005, + VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = 1000337006, + VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = 1000337007, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = 1000337008, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = 1000337009, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = 1000337010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, + VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, + VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, + VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, + VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, + VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, + VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, + VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, + VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, + VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, + VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, + VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, + VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, + VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, + VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, + VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, + VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, + VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, + VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, + VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, + VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, + VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, + VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, + VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkStructureType; + +typedef enum VkImageLayout { + VK_IMAGE_LAYOUT_UNDEFINED = 0, + VK_IMAGE_LAYOUT_GENERAL = 1, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, + VK_IMAGE_LAYOUT_PREINITIALIZED = 8, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL = 1000241000, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR = 1000024000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR = 1000024001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR = 1000024002, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR = 1000299000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR = 1000299001, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR = 1000299002, +#endif + VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, + VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, + VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = 1000314000, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = 1000314001, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF +} VkImageLayout; + +typedef enum VkObjectType { + VK_OBJECT_TYPE_UNKNOWN = 0, + VK_OBJECT_TYPE_INSTANCE = 1, + VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, + VK_OBJECT_TYPE_DEVICE = 3, + VK_OBJECT_TYPE_QUEUE = 4, + VK_OBJECT_TYPE_SEMAPHORE = 5, + VK_OBJECT_TYPE_COMMAND_BUFFER = 6, + VK_OBJECT_TYPE_FENCE = 7, + VK_OBJECT_TYPE_DEVICE_MEMORY = 8, + VK_OBJECT_TYPE_BUFFER = 9, + VK_OBJECT_TYPE_IMAGE = 10, + VK_OBJECT_TYPE_EVENT = 11, + VK_OBJECT_TYPE_QUERY_POOL = 12, + VK_OBJECT_TYPE_BUFFER_VIEW = 13, + VK_OBJECT_TYPE_IMAGE_VIEW = 14, + VK_OBJECT_TYPE_SHADER_MODULE = 15, + VK_OBJECT_TYPE_PIPELINE_CACHE = 16, + VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, + VK_OBJECT_TYPE_RENDER_PASS = 18, + VK_OBJECT_TYPE_PIPELINE = 19, + VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, + VK_OBJECT_TYPE_SAMPLER = 21, + VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, + VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, + VK_OBJECT_TYPE_FRAMEBUFFER = 24, + VK_OBJECT_TYPE_COMMAND_POOL = 25, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, + VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, + VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, + VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, + VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_OBJECT_TYPE_VIDEO_SESSION_KHR = 1000023000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR = 1000023001, +#endif + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, + VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = 1000295000, + VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, + VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, + VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkObjectType; + +typedef enum VkVendorId { + VK_VENDOR_ID_VIV = 0x10001, + VK_VENDOR_ID_VSI = 0x10002, + VK_VENDOR_ID_KAZAN = 0x10003, + VK_VENDOR_ID_CODEPLAY = 0x10004, + VK_VENDOR_ID_MESA = 0x10005, + VK_VENDOR_ID_POCL = 0x10006, + VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF +} VkVendorId; + +typedef enum VkPipelineCacheHeaderVersion { + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheHeaderVersion; + +typedef enum VkSystemAllocationScope { + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF +} VkSystemAllocationScope; + +typedef enum VkInternalAllocationType { + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkInternalAllocationType; + +typedef enum VkFormat { + VK_FORMAT_UNDEFINED = 0, + VK_FORMAT_R4G4_UNORM_PACK8 = 1, + VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, + VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, + VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, + VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, + VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, + VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, + VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, + VK_FORMAT_R8_UNORM = 9, + VK_FORMAT_R8_SNORM = 10, + VK_FORMAT_R8_USCALED = 11, + VK_FORMAT_R8_SSCALED = 12, + VK_FORMAT_R8_UINT = 13, + VK_FORMAT_R8_SINT = 14, + VK_FORMAT_R8_SRGB = 15, + VK_FORMAT_R8G8_UNORM = 16, + VK_FORMAT_R8G8_SNORM = 17, + VK_FORMAT_R8G8_USCALED = 18, + VK_FORMAT_R8G8_SSCALED = 19, + VK_FORMAT_R8G8_UINT = 20, + VK_FORMAT_R8G8_SINT = 21, + VK_FORMAT_R8G8_SRGB = 22, + VK_FORMAT_R8G8B8_UNORM = 23, + VK_FORMAT_R8G8B8_SNORM = 24, + VK_FORMAT_R8G8B8_USCALED = 25, + VK_FORMAT_R8G8B8_SSCALED = 26, + VK_FORMAT_R8G8B8_UINT = 27, + VK_FORMAT_R8G8B8_SINT = 28, + VK_FORMAT_R8G8B8_SRGB = 29, + VK_FORMAT_B8G8R8_UNORM = 30, + VK_FORMAT_B8G8R8_SNORM = 31, + VK_FORMAT_B8G8R8_USCALED = 32, + VK_FORMAT_B8G8R8_SSCALED = 33, + VK_FORMAT_B8G8R8_UINT = 34, + VK_FORMAT_B8G8R8_SINT = 35, + VK_FORMAT_B8G8R8_SRGB = 36, + VK_FORMAT_R8G8B8A8_UNORM = 37, + VK_FORMAT_R8G8B8A8_SNORM = 38, + VK_FORMAT_R8G8B8A8_USCALED = 39, + VK_FORMAT_R8G8B8A8_SSCALED = 40, + VK_FORMAT_R8G8B8A8_UINT = 41, + VK_FORMAT_R8G8B8A8_SINT = 42, + VK_FORMAT_R8G8B8A8_SRGB = 43, + VK_FORMAT_B8G8R8A8_UNORM = 44, + VK_FORMAT_B8G8R8A8_SNORM = 45, + VK_FORMAT_B8G8R8A8_USCALED = 46, + VK_FORMAT_B8G8R8A8_SSCALED = 47, + VK_FORMAT_B8G8R8A8_UINT = 48, + VK_FORMAT_B8G8R8A8_SINT = 49, + VK_FORMAT_B8G8R8A8_SRGB = 50, + VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, + VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, + VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, + VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, + VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, + VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, + VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, + VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, + VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, + VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, + VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, + VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, + VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, + VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, + VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, + VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, + VK_FORMAT_R16_UNORM = 70, + VK_FORMAT_R16_SNORM = 71, + VK_FORMAT_R16_USCALED = 72, + VK_FORMAT_R16_SSCALED = 73, + VK_FORMAT_R16_UINT = 74, + VK_FORMAT_R16_SINT = 75, + VK_FORMAT_R16_SFLOAT = 76, + VK_FORMAT_R16G16_UNORM = 77, + VK_FORMAT_R16G16_SNORM = 78, + VK_FORMAT_R16G16_USCALED = 79, + VK_FORMAT_R16G16_SSCALED = 80, + VK_FORMAT_R16G16_UINT = 81, + VK_FORMAT_R16G16_SINT = 82, + VK_FORMAT_R16G16_SFLOAT = 83, + VK_FORMAT_R16G16B16_UNORM = 84, + VK_FORMAT_R16G16B16_SNORM = 85, + VK_FORMAT_R16G16B16_USCALED = 86, + VK_FORMAT_R16G16B16_SSCALED = 87, + VK_FORMAT_R16G16B16_UINT = 88, + VK_FORMAT_R16G16B16_SINT = 89, + VK_FORMAT_R16G16B16_SFLOAT = 90, + VK_FORMAT_R16G16B16A16_UNORM = 91, + VK_FORMAT_R16G16B16A16_SNORM = 92, + VK_FORMAT_R16G16B16A16_USCALED = 93, + VK_FORMAT_R16G16B16A16_SSCALED = 94, + VK_FORMAT_R16G16B16A16_UINT = 95, + VK_FORMAT_R16G16B16A16_SINT = 96, + VK_FORMAT_R16G16B16A16_SFLOAT = 97, + VK_FORMAT_R32_UINT = 98, + VK_FORMAT_R32_SINT = 99, + VK_FORMAT_R32_SFLOAT = 100, + VK_FORMAT_R32G32_UINT = 101, + VK_FORMAT_R32G32_SINT = 102, + VK_FORMAT_R32G32_SFLOAT = 103, + VK_FORMAT_R32G32B32_UINT = 104, + VK_FORMAT_R32G32B32_SINT = 105, + VK_FORMAT_R32G32B32_SFLOAT = 106, + VK_FORMAT_R32G32B32A32_UINT = 107, + VK_FORMAT_R32G32B32A32_SINT = 108, + VK_FORMAT_R32G32B32A32_SFLOAT = 109, + VK_FORMAT_R64_UINT = 110, + VK_FORMAT_R64_SINT = 111, + VK_FORMAT_R64_SFLOAT = 112, + VK_FORMAT_R64G64_UINT = 113, + VK_FORMAT_R64G64_SINT = 114, + VK_FORMAT_R64G64_SFLOAT = 115, + VK_FORMAT_R64G64B64_UINT = 116, + VK_FORMAT_R64G64B64_SINT = 117, + VK_FORMAT_R64G64B64_SFLOAT = 118, + VK_FORMAT_R64G64B64A64_UINT = 119, + VK_FORMAT_R64G64B64A64_SINT = 120, + VK_FORMAT_R64G64B64A64_SFLOAT = 121, + VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, + VK_FORMAT_D16_UNORM = 124, + VK_FORMAT_X8_D24_UNORM_PACK32 = 125, + VK_FORMAT_D32_SFLOAT = 126, + VK_FORMAT_S8_UINT = 127, + VK_FORMAT_D16_UNORM_S8_UINT = 128, + VK_FORMAT_D24_UNORM_S8_UINT = 129, + VK_FORMAT_D32_SFLOAT_S8_UINT = 130, + VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, + VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, + VK_FORMAT_BC2_UNORM_BLOCK = 135, + VK_FORMAT_BC2_SRGB_BLOCK = 136, + VK_FORMAT_BC3_UNORM_BLOCK = 137, + VK_FORMAT_BC3_SRGB_BLOCK = 138, + VK_FORMAT_BC4_UNORM_BLOCK = 139, + VK_FORMAT_BC4_SNORM_BLOCK = 140, + VK_FORMAT_BC5_UNORM_BLOCK = 141, + VK_FORMAT_BC5_SNORM_BLOCK = 142, + VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, + VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, + VK_FORMAT_BC7_UNORM_BLOCK = 145, + VK_FORMAT_BC7_SRGB_BLOCK = 146, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, + VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, + VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, + VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, + VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, + VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, + VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, + VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, + VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001, + VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, + VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, + VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM, + VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF +} VkFormat; + +typedef enum VkImageTiling { + VK_IMAGE_TILING_OPTIMAL = 0, + VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF +} VkImageTiling; + +typedef enum VkImageType { + VK_IMAGE_TYPE_1D = 0, + VK_IMAGE_TYPE_2D = 1, + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageType; + +typedef enum VkPhysicalDeviceType { + VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, + VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, + VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkPhysicalDeviceType; + +typedef enum VkQueryType { + VK_QUERY_TYPE_OCCLUSION = 0, + VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, + VK_QUERY_TYPE_TIMESTAMP = 2, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR = 1000023000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR = 1000299000, +#endif + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, + VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000150000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, + VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkQueryType; + +typedef enum VkSharingMode { + VK_SHARING_MODE_EXCLUSIVE = 0, + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSharingMode; + +typedef enum VkComponentSwizzle { + VK_COMPONENT_SWIZZLE_IDENTITY = 0, + VK_COMPONENT_SWIZZLE_ZERO = 1, + VK_COMPONENT_SWIZZLE_ONE = 2, + VK_COMPONENT_SWIZZLE_R = 3, + VK_COMPONENT_SWIZZLE_G = 4, + VK_COMPONENT_SWIZZLE_B = 5, + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF +} VkComponentSwizzle; + +typedef enum VkImageViewType { + VK_IMAGE_VIEW_TYPE_1D = 0, + VK_IMAGE_VIEW_TYPE_2D = 1, + VK_IMAGE_VIEW_TYPE_3D = 2, + VK_IMAGE_VIEW_TYPE_CUBE = 3, + VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, + VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkImageViewType; + +typedef enum VkBlendFactor { + VK_BLEND_FACTOR_ZERO = 0, + VK_BLEND_FACTOR_ONE = 1, + VK_BLEND_FACTOR_SRC_COLOR = 2, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, + VK_BLEND_FACTOR_DST_COLOR = 4, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, + VK_BLEND_FACTOR_SRC_ALPHA = 6, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, + VK_BLEND_FACTOR_DST_ALPHA = 8, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, + VK_BLEND_FACTOR_CONSTANT_COLOR = 10, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, + VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, + VK_BLEND_FACTOR_SRC1_COLOR = 15, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, + VK_BLEND_FACTOR_SRC1_ALPHA = 17, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF +} VkBlendFactor; + +typedef enum VkBlendOp { + VK_BLEND_OP_ADD = 0, + VK_BLEND_OP_SUBTRACT = 1, + VK_BLEND_OP_REVERSE_SUBTRACT = 2, + VK_BLEND_OP_MIN = 3, + VK_BLEND_OP_MAX = 4, + VK_BLEND_OP_ZERO_EXT = 1000148000, + VK_BLEND_OP_SRC_EXT = 1000148001, + VK_BLEND_OP_DST_EXT = 1000148002, + VK_BLEND_OP_SRC_OVER_EXT = 1000148003, + VK_BLEND_OP_DST_OVER_EXT = 1000148004, + VK_BLEND_OP_SRC_IN_EXT = 1000148005, + VK_BLEND_OP_DST_IN_EXT = 1000148006, + VK_BLEND_OP_SRC_OUT_EXT = 1000148007, + VK_BLEND_OP_DST_OUT_EXT = 1000148008, + VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, + VK_BLEND_OP_DST_ATOP_EXT = 1000148010, + VK_BLEND_OP_XOR_EXT = 1000148011, + VK_BLEND_OP_MULTIPLY_EXT = 1000148012, + VK_BLEND_OP_SCREEN_EXT = 1000148013, + VK_BLEND_OP_OVERLAY_EXT = 1000148014, + VK_BLEND_OP_DARKEN_EXT = 1000148015, + VK_BLEND_OP_LIGHTEN_EXT = 1000148016, + VK_BLEND_OP_COLORDODGE_EXT = 1000148017, + VK_BLEND_OP_COLORBURN_EXT = 1000148018, + VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, + VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, + VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, + VK_BLEND_OP_EXCLUSION_EXT = 1000148022, + VK_BLEND_OP_INVERT_EXT = 1000148023, + VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, + VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, + VK_BLEND_OP_LINEARBURN_EXT = 1000148026, + VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, + VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, + VK_BLEND_OP_PINLIGHT_EXT = 1000148029, + VK_BLEND_OP_HARDMIX_EXT = 1000148030, + VK_BLEND_OP_HSL_HUE_EXT = 1000148031, + VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, + VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, + VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, + VK_BLEND_OP_PLUS_EXT = 1000148035, + VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, + VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, + VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, + VK_BLEND_OP_MINUS_EXT = 1000148039, + VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, + VK_BLEND_OP_CONTRAST_EXT = 1000148041, + VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, + VK_BLEND_OP_RED_EXT = 1000148043, + VK_BLEND_OP_GREEN_EXT = 1000148044, + VK_BLEND_OP_BLUE_EXT = 1000148045, + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF +} VkBlendOp; + +typedef enum VkCompareOp { + VK_COMPARE_OP_NEVER = 0, + VK_COMPARE_OP_LESS = 1, + VK_COMPARE_OP_EQUAL = 2, + VK_COMPARE_OP_LESS_OR_EQUAL = 3, + VK_COMPARE_OP_GREATER = 4, + VK_COMPARE_OP_NOT_EQUAL = 5, + VK_COMPARE_OP_GREATER_OR_EQUAL = 6, + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF +} VkCompareOp; + +typedef enum VkDynamicState { + VK_DYNAMIC_STATE_VIEWPORT = 0, + VK_DYNAMIC_STATE_SCISSOR = 1, + VK_DYNAMIC_STATE_LINE_WIDTH = 2, + VK_DYNAMIC_STATE_DEPTH_BIAS = 3, + VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, + VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, + VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, + VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR = 1000347000, + VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, + VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, + VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, + VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, + VK_DYNAMIC_STATE_CULL_MODE_EXT = 1000267000, + VK_DYNAMIC_STATE_FRONT_FACE_EXT = 1000267001, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = 1000267002, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = 1000267003, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = 1000267004, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = 1000267005, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = 1000267006, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = 1000267007, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = 1000267008, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = 1000267009, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = 1000267010, + VK_DYNAMIC_STATE_STENCIL_OP_EXT = 1000267011, + VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, + VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = 1000377001, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = 1000377002, + VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = 1000377004, + VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF +} VkDynamicState; + +typedef enum VkFrontFace { + VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF +} VkFrontFace; + +typedef enum VkVertexInputRate { + VK_VERTEX_INPUT_RATE_VERTEX = 0, + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF +} VkVertexInputRate; + +typedef enum VkPrimitiveTopology { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF +} VkPrimitiveTopology; + +typedef enum VkPolygonMode { + VK_POLYGON_MODE_FILL = 0, + VK_POLYGON_MODE_LINE = 1, + VK_POLYGON_MODE_POINT = 2, + VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF +} VkPolygonMode; + +typedef enum VkStencilOp { + VK_STENCIL_OP_KEEP = 0, + VK_STENCIL_OP_ZERO = 1, + VK_STENCIL_OP_REPLACE = 2, + VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, + VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, + VK_STENCIL_OP_INVERT = 5, + VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF +} VkStencilOp; + +typedef enum VkLogicOp { + VK_LOGIC_OP_CLEAR = 0, + VK_LOGIC_OP_AND = 1, + VK_LOGIC_OP_AND_REVERSE = 2, + VK_LOGIC_OP_COPY = 3, + VK_LOGIC_OP_AND_INVERTED = 4, + VK_LOGIC_OP_NO_OP = 5, + VK_LOGIC_OP_XOR = 6, + VK_LOGIC_OP_OR = 7, + VK_LOGIC_OP_NOR = 8, + VK_LOGIC_OP_EQUIVALENT = 9, + VK_LOGIC_OP_INVERT = 10, + VK_LOGIC_OP_OR_REVERSE = 11, + VK_LOGIC_OP_COPY_INVERTED = 12, + VK_LOGIC_OP_OR_INVERTED = 13, + VK_LOGIC_OP_NAND = 14, + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF +} VkLogicOp; + +typedef enum VkBorderColor { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, + VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, + VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, + VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, + VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF +} VkBorderColor; + +typedef enum VkFilter { + VK_FILTER_NEAREST = 0, + VK_FILTER_LINEAR = 1, + VK_FILTER_CUBIC_IMG = 1000015000, + VK_FILTER_CUBIC_EXT = VK_FILTER_CUBIC_IMG, + VK_FILTER_MAX_ENUM = 0x7FFFFFFF +} VkFilter; + +typedef enum VkSamplerAddressMode { + VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerAddressMode; + +typedef enum VkSamplerMipmapMode { + VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerMipmapMode; + +typedef enum VkDescriptorType { + VK_DESCRIPTOR_TYPE_SAMPLER = 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = 1000351000, + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorType; + +typedef enum VkAttachmentLoadOp { + VK_ATTACHMENT_LOAD_OP_LOAD = 0, + VK_ATTACHMENT_LOAD_OP_CLEAR = 1, + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentLoadOp; + +typedef enum VkAttachmentStoreOp { + VK_ATTACHMENT_STORE_OP_STORE = 0, + VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, + VK_ATTACHMENT_STORE_OP_NONE_QCOM = 1000301000, + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentStoreOp; + +typedef enum VkPipelineBindPoint { + VK_PIPELINE_BIND_POINT_GRAPHICS = 0, + VK_PIPELINE_BIND_POINT_COMPUTE = 1, + VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF +} VkPipelineBindPoint; + +typedef enum VkCommandBufferLevel { + VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferLevel; + +typedef enum VkIndexType { + VK_INDEX_TYPE_UINT16 = 0, + VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_NONE_KHR = 1000165000, + VK_INDEX_TYPE_UINT8_EXT = 1000265000, + VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkIndexType; + +typedef enum VkSubpassContents { + VK_SUBPASS_CONTENTS_INLINE = 0, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassContents; + +typedef enum VkAccessFlagBits { + VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, + VK_ACCESS_INDEX_READ_BIT = 0x00000002, + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, + VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, + VK_ACCESS_SHADER_READ_BIT = 0x00000020, + VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, + VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, + VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, + VK_ACCESS_HOST_READ_BIT = 0x00002000, + VK_ACCESS_HOST_WRITE_BIT = 0x00004000, + VK_ACCESS_MEMORY_READ_BIT = 0x00008000, + VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, + VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, + VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000, + VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, + VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000, + VK_ACCESS_NONE_KHR = 0, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, + VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAccessFlagBits; +typedef VkFlags VkAccessFlags; + +typedef enum VkImageAspectFlagBits { + VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, + VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, + VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, + VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, + VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, + VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, + VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, + VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, + VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, + VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageAspectFlagBits; +typedef VkFlags VkImageAspectFlags; + +typedef enum VkFormatFeatureFlagBits { + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, + VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, + VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, + VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, + VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, + VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, + VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, + VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR = 0x08000000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000, +#endif + VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000, + VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, + VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT, + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, + VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFormatFeatureFlagBits; +typedef VkFlags VkFormatFeatureFlags; + +typedef enum VkImageCreateFlagBits { + VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, + VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, + VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, + VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, + VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, + VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, + VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, + VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, + VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, + VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, + VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, + VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageCreateFlagBits; +typedef VkFlags VkImageCreateFlags; + +typedef enum VkSampleCountFlagBits { + VK_SAMPLE_COUNT_1_BIT = 0x00000001, + VK_SAMPLE_COUNT_2_BIT = 0x00000002, + VK_SAMPLE_COUNT_4_BIT = 0x00000004, + VK_SAMPLE_COUNT_8_BIT = 0x00000008, + VK_SAMPLE_COUNT_16_BIT = 0x00000010, + VK_SAMPLE_COUNT_32_BIT = 0x00000020, + VK_SAMPLE_COUNT_64_BIT = 0x00000040, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSampleCountFlagBits; +typedef VkFlags VkSampleCountFlags; + +typedef enum VkImageUsageFlagBits { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, + VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00000400, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00000800, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR = 0x00001000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00002000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00004000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000, +#endif + VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00000100, + VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, + VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageUsageFlagBits; +typedef VkFlags VkImageUsageFlags; +typedef VkFlags VkInstanceCreateFlags; + +typedef enum VkMemoryHeapFlagBits { + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryHeapFlagBits; +typedef VkFlags VkMemoryHeapFlags; + +typedef enum VkMemoryPropertyFlagBits { + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, + VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, + VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 0x00000040, + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 0x00000080, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryPropertyFlagBits; +typedef VkFlags VkMemoryPropertyFlags; + +typedef enum VkQueueFlagBits { + VK_QUEUE_GRAPHICS_BIT = 0x00000001, + VK_QUEUE_COMPUTE_BIT = 0x00000002, + VK_QUEUE_TRANSFER_BIT = 0x00000004, + VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, + VK_QUEUE_PROTECTED_BIT = 0x00000010, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUEUE_VIDEO_DECODE_BIT_KHR = 0x00000020, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUEUE_VIDEO_ENCODE_BIT_KHR = 0x00000040, +#endif + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueueFlagBits; +typedef VkFlags VkQueueFlags; +typedef VkFlags VkDeviceCreateFlags; + +typedef enum VkDeviceQueueCreateFlagBits { + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, + VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDeviceQueueCreateFlagBits; +typedef VkFlags VkDeviceQueueCreateFlags; + +typedef enum VkPipelineStageFlagBits { + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, + VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, + VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, + VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, + VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 0x00200000, + VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, + VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 0x00020000, + VK_PIPELINE_STAGE_NONE_KHR = 0, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineStageFlagBits; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkMemoryMapFlags; + +typedef enum VkSparseMemoryBindFlagBits { + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseMemoryBindFlagBits; +typedef VkFlags VkSparseMemoryBindFlags; + +typedef enum VkSparseImageFormatFlagBits { + VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, + VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSparseImageFormatFlagBits; +typedef VkFlags VkSparseImageFormatFlags; + +typedef enum VkFenceCreateFlagBits { + VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceCreateFlagBits; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; + +typedef enum VkEventCreateFlagBits { + VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = 0x00000001, + VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkEventCreateFlagBits; +typedef VkFlags VkEventCreateFlags; + +typedef enum VkQueryPipelineStatisticFlagBits { + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, + VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, + VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryPipelineStatisticFlagBits; +typedef VkFlags VkQueryPipelineStatisticFlags; +typedef VkFlags VkQueryPoolCreateFlags; + +typedef enum VkQueryResultFlagBits { + VK_QUERY_RESULT_64_BIT = 0x00000001, + VK_QUERY_RESULT_WAIT_BIT = 0x00000002, + VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, + VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_QUERY_RESULT_WITH_STATUS_BIT_KHR = 0x00000010, +#endif + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryResultFlagBits; +typedef VkFlags VkQueryResultFlags; + +typedef enum VkBufferCreateFlagBits { + VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, + VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, + VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, + VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000010, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferCreateFlagBits; +typedef VkFlags VkBufferCreateFlags; + +typedef enum VkBufferUsageFlagBits { + VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, + VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT = 0x00020000, +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00002000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00004000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000, +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000, +#endif + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, + VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000, + VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkBufferUsageFlagBits; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferViewCreateFlags; + +typedef enum VkImageViewCreateFlagBits { + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 0x00000002, + VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkImageViewCreateFlagBits; +typedef VkFlags VkImageViewCreateFlags; + +typedef enum VkShaderModuleCreateFlagBits { + VK_SHADER_MODULE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkShaderModuleCreateFlagBits; +typedef VkFlags VkShaderModuleCreateFlags; + +typedef enum VkPipelineCacheCreateFlagBits { + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = 0x00000001, + VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCacheCreateFlagBits; +typedef VkFlags VkPipelineCacheCreateFlags; + +typedef enum VkColorComponentFlagBits { + VK_COLOR_COMPONENT_R_BIT = 0x00000001, + VK_COLOR_COMPONENT_G_BIT = 0x00000002, + VK_COLOR_COMPONENT_B_BIT = 0x00000004, + VK_COLOR_COMPONENT_A_BIT = 0x00000008, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkColorComponentFlagBits; +typedef VkFlags VkColorComponentFlags; + +typedef enum VkPipelineCreateFlagBits { + VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, + VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, + VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, + VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 0x00000010, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000, + VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000, + VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000, + VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 0x00080000, + VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, + VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 0x00000040, + VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080, + VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000, + VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = 0x00000100, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = 0x00000200, + VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, + VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreateFlagBits; +typedef VkFlags VkPipelineCreateFlags; + +typedef enum VkPipelineShaderStageCreateFlagBits { + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 0x00000001, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 0x00000002, + VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineShaderStageCreateFlagBits; +typedef VkFlags VkPipelineShaderStageCreateFlags; + +typedef enum VkShaderStageFlagBits { + VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, + VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, + VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, + VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, + VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, + VK_SHADER_STAGE_ALL = 0x7FFFFFFF, + VK_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, + VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, + VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080, + VK_SHADER_STAGE_RAYGEN_BIT_NV = VK_SHADER_STAGE_RAYGEN_BIT_KHR, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = VK_SHADER_STAGE_ANY_HIT_BIT_KHR, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, + VK_SHADER_STAGE_MISS_BIT_NV = VK_SHADER_STAGE_MISS_BIT_KHR, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, + VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkShaderStageFlagBits; + +typedef enum VkCullModeFlagBits { + VK_CULL_MODE_NONE = 0, + VK_CULL_MODE_FRONT_BIT = 0x00000001, + VK_CULL_MODE_BACK_BIT = 0x00000002, + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCullModeFlagBits; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkShaderStageFlags; + +typedef enum VkSamplerCreateFlagBits { + VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, + VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, + VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSamplerCreateFlagBits; +typedef VkFlags VkSamplerCreateFlags; + +typedef enum VkDescriptorPoolCreateFlagBits { + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = 0x00000004, + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorPoolCreateFlagBits; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; + +typedef enum VkDescriptorSetLayoutCreateFlagBits { + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = 0x00000004, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorSetLayoutCreateFlagBits; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; + +typedef enum VkAttachmentDescriptionFlagBits { + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkAttachmentDescriptionFlagBits; +typedef VkFlags VkAttachmentDescriptionFlags; + +typedef enum VkDependencyFlagBits { + VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, + VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, + VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, + VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDependencyFlagBits; +typedef VkFlags VkDependencyFlags; + +typedef enum VkFramebufferCreateFlagBits { + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 0x00000001, + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, + VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFramebufferCreateFlagBits; +typedef VkFlags VkFramebufferCreateFlags; + +typedef enum VkRenderPassCreateFlagBits { + VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 0x00000002, + VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderPassCreateFlagBits; +typedef VkFlags VkRenderPassCreateFlags; + +typedef enum VkSubpassDescriptionFlagBits { + VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, + VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, + VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 0x00000004, + VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 0x00000008, + VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubpassDescriptionFlagBits; +typedef VkFlags VkSubpassDescriptionFlags; + +typedef enum VkCommandPoolCreateFlagBits { + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolCreateFlagBits; +typedef VkFlags VkCommandPoolCreateFlags; + +typedef enum VkCommandPoolResetFlagBits { + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandPoolResetFlagBits; +typedef VkFlags VkCommandPoolResetFlags; + +typedef enum VkCommandBufferUsageFlagBits { + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferUsageFlagBits; +typedef VkFlags VkCommandBufferUsageFlags; + +typedef enum VkQueryControlFlagBits { + VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkQueryControlFlagBits; +typedef VkFlags VkQueryControlFlags; + +typedef enum VkCommandBufferResetFlagBits { + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkCommandBufferResetFlagBits; +typedef VkFlags VkCommandBufferResetFlags; + +typedef enum VkStencilFaceFlagBits { + VK_STENCIL_FACE_FRONT_BIT = 0x00000001, + VK_STENCIL_FACE_BACK_BIT = 0x00000002, + VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003, + VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkStencilFaceFlagBits; +typedef VkFlags VkStencilFaceFlags; +typedef struct VkExtent2D { + uint32_t width; + uint32_t height; +} VkExtent2D; + +typedef struct VkExtent3D { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkExtent3D; + +typedef struct VkOffset2D { + int32_t x; + int32_t y; +} VkOffset2D; + +typedef struct VkOffset3D { + int32_t x; + int32_t y; + int32_t z; +} VkOffset3D; + +typedef struct VkRect2D { + VkOffset2D offset; + VkExtent2D extent; +} VkRect2D; + +typedef struct VkBaseInStructure { + VkStructureType sType; + const struct VkBaseInStructure* pNext; +} VkBaseInStructure; + +typedef struct VkBaseOutStructure { + VkStructureType sType; + struct VkBaseOutStructure* pNext; +} VkBaseOutStructure; + +typedef struct VkBufferMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; + +typedef struct VkDispatchIndirectCommand { + uint32_t x; + uint32_t y; + uint32_t z; +} VkDispatchIndirectCommand; + +typedef struct VkDrawIndexedIndirectCommand { + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +} VkDrawIndexedIndirectCommand; + +typedef struct VkDrawIndirectCommand { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +} VkDrawIndirectCommand; + +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; + +typedef struct VkImageMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; + +typedef struct VkMemoryBarrier { + VkStructureType sType; + const void* pNext; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; + +typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + +typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + +typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + +typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); +typedef struct VkAllocationCallbacks { + void* pUserData; + PFN_vkAllocationFunction pfnAllocation; + PFN_vkReallocationFunction pfnReallocation; + PFN_vkFreeFunction pfnFree; + PFN_vkInternalAllocationNotification pfnInternalAllocation; + PFN_vkInternalFreeNotification pfnInternalFree; +} VkAllocationCallbacks; + +typedef struct VkApplicationInfo { + VkStructureType sType; + const void* pNext; + const char* pApplicationName; + uint32_t applicationVersion; + const char* pEngineName; + uint32_t engineVersion; + uint32_t apiVersion; +} VkApplicationInfo; + +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkInstanceCreateInfo { + VkStructureType sType; + const void* pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo* pApplicationInfo; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount[3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize[3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions[2]; + float viewportBoundsRange[2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange[2]; + float lineWidthRange[2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkPhysicalDeviceMemoryProperties { + uint32_t memoryTypeCount; + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; + uint32_t memoryHeapCount; + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryProperties; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceProperties { + uint32_t apiVersion; + uint32_t driverVersion; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceType deviceType; + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t pipelineCacheUUID[VK_UUID_SIZE]; + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceSparseProperties sparseProperties; +} VkPhysicalDeviceProperties; + +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkDeviceQueueCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float* pQueuePriorities; +} VkDeviceQueueCreateInfo; + +typedef struct VkDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceCreateFlags flags; + uint32_t queueCreateInfoCount; + const VkDeviceQueueCreateInfo* pQueueCreateInfos; + uint32_t enabledLayerCount; + const char* const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char* const* ppEnabledExtensionNames; + const VkPhysicalDeviceFeatures* pEnabledFeatures; +} VkDeviceCreateInfo; + +typedef struct VkExtensionProperties { + char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; +} VkExtensionProperties; + +typedef struct VkLayerProperties { + char layerName[VK_MAX_EXTENSION_NAME_SIZE]; + uint32_t specVersion; + uint32_t implementationVersion; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkLayerProperties; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + const VkPipelineStageFlags* pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer* pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkMappedMemoryRange { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; + +typedef struct VkMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; + +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; + +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseBufferMemoryBindInfo; + +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind* pBinds; +} VkSparseImageOpaqueMemoryBindInfo; + +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; + +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; + +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind* pBinds; +} VkSparseImageMemoryBindInfo; + +typedef struct VkBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo* pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo* pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore* pSignalSemaphores; +} VkBindSparseInfo; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void* pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkBufferCreateInfo; + +typedef struct VkBufferViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; + +typedef struct VkImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; + +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkComponentMapping { + VkComponentSwizzle r; + VkComponentSwizzle g; + VkComponentSwizzle b; + VkComponentSwizzle a; +} VkComponentMapping; + +typedef struct VkImageViewCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void* pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t* pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void* pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; + +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char* pName; + const VkSpecializationInfo* pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkVertexInputBindingDescription { + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; +} VkVertexInputBindingDescription; + +typedef struct VkVertexInputAttributeDescription { + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription* pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkViewport { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} VkViewport; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport* pViewports; + uint32_t scissorCount; + const VkRect2D* pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask* pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkStencilOpState { + VkStencilOp failOp; + VkStencilOp passOp; + VkStencilOp depthFailOp; + VkCompareOp compareOp; + uint32_t compareMask; + uint32_t writeMask; + uint32_t reference; +} VkStencilOpState; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState* pAttachments; + float blendConstants[4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState* pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; + const VkPipelineViewportStateCreateInfo* pViewportState; + const VkPipelineRasterizationStateCreateInfo* pRasterizationState; + const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout* pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange* pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkCopyDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; +} VkCopyDescriptorSet; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkDescriptorImageInfo { + VkSampler sampler; + VkImageView imageView; + VkImageLayout imageLayout; +} VkDescriptorImageInfo; + +typedef struct VkDescriptorPoolSize { + VkDescriptorType type; + uint32_t descriptorCount; +} VkDescriptorPoolSize; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize* pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkDescriptorSetAllocateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorPool descriptorPool; + uint32_t descriptorSetCount; + const VkDescriptorSetLayout* pSetLayouts; +} VkDescriptorSetAllocateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler* pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding* pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkWriteDescriptorSet { + VkStructureType sType; + const void* pNext; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo* pImageInfo; + const VkDescriptorBufferInfo* pBufferInfo; + const VkBufferView* pTexelBufferView; +} VkWriteDescriptorSet; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription; + +typedef struct VkAttachmentReference { + uint32_t attachment; + VkImageLayout layout; +} VkAttachmentReference; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView* pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference* pColorAttachments; + const VkAttachmentReference* pResolveAttachments; + const VkAttachmentReference* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency* pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferAllocateInfo { + VkStructureType sType; + const void* pNext; + VkCommandPool commandPool; + VkCommandBufferLevel level; + uint32_t commandBufferCount; +} VkCommandBufferAllocateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo* pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; + +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef union VkClearColorValue { + float float32[4]; + int32_t int32[4]; + uint32_t uint32[4]; +} VkClearColorValue; + +typedef struct VkClearDepthStencilValue { + float depth; + uint32_t stencil; +} VkClearDepthStencilValue; + +typedef union VkClearValue { + VkClearColorValue color; + VkClearDepthStencilValue depthStencil; +} VkClearValue; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkClearRect { + VkRect2D rect; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkClearRect; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit; + +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue* pClearValues; +} VkRenderPassBeginInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); +typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); +typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); +typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); +typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); +typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); +typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); +typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); +typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); +typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); +typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); +typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); +typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); +typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); +typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); +typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); +typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); +typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); +typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); +typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); +typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); +typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); +typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); +typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); +typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); +typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); +typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); +typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( + const VkInstanceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkInstance* pInstance); + +VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( + VkInstance instance, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( + VkInstance instance, + uint32_t* pPhysicalDeviceCount, + VkPhysicalDevice* pPhysicalDevices); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkImageFormatProperties* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties* pMemoryProperties); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( + VkInstance instance, + const char* pName); + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( + VkDevice device, + const char* pName); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( + VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDevice* pDevice); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( + VkDevice device, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( + VkPhysicalDevice physicalDevice, + const char* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkLayerProperties* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( + VkDevice device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( + VkQueue queue); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( + VkDevice device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMemory); + +VKAPI_ATTR void VKAPI_CALL vkFreeMemory( + VkDevice device, + VkDeviceMemory memory, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData); + +VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( + VkDevice device, + VkDeviceMemory memory); + +VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( + VkDevice device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange* pMemoryRanges); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize* pCommittedMemoryInBytes); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( + VkDevice device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( + VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( + VkDevice device, + VkBuffer buffer, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( + VkDevice device, + VkImage image, + VkMemoryRequirements* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( + VkQueue queue, + uint32_t bindInfoCount, + const VkBindSparseInfo* pBindInfo, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( + VkDevice device, + const VkFenceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFence( + VkDevice device, + VkFence fence, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( + VkDevice device, + VkFence fence); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( + VkDevice device, + uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( + VkDevice device, + const VkSemaphoreCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSemaphore* pSemaphore); + +VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( + VkDevice device, + VkSemaphore semaphore, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( + VkDevice device, + const VkEventCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkEvent* pEvent); + +VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( + VkDevice device, + VkEvent event, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( + VkDevice device, + VkEvent event); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( + VkDevice device, + const VkQueryPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkQueryPool* pQueryPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( + VkDevice device, + VkQueryPool queryPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void* pData, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( + VkDevice device, + const VkBufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBuffer* pBuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( + VkDevice device, + VkBuffer buffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( + VkDevice device, + const VkBufferViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkBufferView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( + VkDevice device, + VkBufferView bufferView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( + VkDevice device, + const VkImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImage* pImage); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImage( + VkDevice device, + VkImage image, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( + VkDevice device, + VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( + VkDevice device, + const VkImageViewCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkImageView* pView); + +VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( + VkDevice device, + VkImageView imageView, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( + VkDevice device, + const VkShaderModuleCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkShaderModule* pShaderModule); + +VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( + VkDevice device, + VkShaderModule shaderModule, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( + VkDevice device, + const VkPipelineCacheCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineCache* pPipelineCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( + VkDevice device, + VkPipelineCache pipelineCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( + VkDevice device, + VkPipelineCache pipelineCache, + size_t* pDataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( + VkDevice device, + VkPipelineCache dstCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkGraphicsPipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkComputePipelineCreateInfo* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( + VkDevice device, + VkPipeline pipeline, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( + VkDevice device, + const VkPipelineLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineLayout* pPipelineLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( + VkDevice device, + VkPipelineLayout pipelineLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( + VkDevice device, + const VkSamplerCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSampler* pSampler); + +VKAPI_ATTR void VKAPI_CALL vkDestroySampler( + VkDevice device, + VkSampler sampler, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorSetLayout* pSetLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( + VkDevice device, + VkDescriptorSetLayout descriptorSetLayout, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( + VkDevice device, + const VkDescriptorPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorPool* pDescriptorPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( + VkDevice device, + const VkDescriptorSetAllocateInfo* pAllocateInfo, + VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( + VkDevice device, + VkDescriptorPool descriptorPool, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( + VkDevice device, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet* pDescriptorCopies); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( + VkDevice device, + const VkFramebufferCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFramebuffer* pFramebuffer); + +VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( + VkDevice device, + VkFramebuffer framebuffer, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( + VkDevice device, + const VkRenderPassCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( + VkDevice device, + VkRenderPass renderPass, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( + VkDevice device, + VkRenderPass renderPass, + VkExtent2D* pGranularity); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( + VkDevice device, + const VkCommandPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCommandPool* pCommandPool); + +VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( + VkDevice device, + VkCommandPool commandPool, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolResetFlags flags); + +VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( + VkDevice device, + const VkCommandBufferAllocateInfo* pAllocateInfo, + VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( + VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); + +VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo* pBeginInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( + VkCommandBuffer commandBuffer, + VkCommandBufferResetFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( + VkCommandBuffer commandBuffer, + uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( + VkCommandBuffer commandBuffer, + float lineWidth); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( + VkCommandBuffer commandBuffer, + float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( + VkCommandBuffer commandBuffer, + const float blendConstants[4]); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( + VkCommandBuffer commandBuffer, + float minDepthBounds, + float maxDepthBounds); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t compareMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t writeMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t reference); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t* pDynamicOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdDraw( + VkCommandBuffer commandBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( + VkCommandBuffer commandBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( + VkCommandBuffer commandBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( + VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( + VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( + VkCommandBuffer commandBuffer, + VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue* pDepthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges); + +VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkClearAttachment* pAttachments, + uint32_t rectCount, + const VkClearRect* pRects); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( + VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( + VkCommandBuffer commandBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( + VkCommandBuffer commandBuffer, + VkSubpassContents contents); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( + VkCommandBuffer commandBuffer, + uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers); +#endif + + +#define VK_VERSION_1_1 1 +// Vulkan 1.1 version number +#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)// Patch version should always be set to 0 + +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) +#define VK_MAX_DEVICE_GROUP_SIZE 32U +#define VK_LUID_SIZE 8U +#define VK_QUEUE_FAMILY_EXTERNAL (~1U) + +typedef enum VkPointClippingBehavior { + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, + VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPointClippingBehavior; + +typedef enum VkTessellationDomainOrigin { + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, + VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF +} VkTessellationDomainOrigin; + +typedef enum VkSamplerYcbcrModelConversion { + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrModelConversion; + +typedef enum VkSamplerYcbcrRange { + VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, + VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, + VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerYcbcrRange; + +typedef enum VkChromaLocation { + VK_CHROMA_LOCATION_COSITED_EVEN = 0, + VK_CHROMA_LOCATION_MIDPOINT = 1, + VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, + VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, + VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF +} VkChromaLocation; + +typedef enum VkDescriptorUpdateTemplateType { + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorUpdateTemplateType; + +typedef enum VkSubgroupFeatureFlagBits { + VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, + VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, + VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, + VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, + VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, + VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, + VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, + VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubgroupFeatureFlagBits; +typedef VkFlags VkSubgroupFeatureFlags; + +typedef enum VkPeerMemoryFeatureFlagBits { + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, + VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, + VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPeerMemoryFeatureFlagBits; +typedef VkFlags VkPeerMemoryFeatureFlags; + +typedef enum VkMemoryAllocateFlagBits { + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 0x00000002, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000004, + VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryAllocateFlagBits; +typedef VkFlags VkMemoryAllocateFlags; +typedef VkFlags VkCommandPoolTrimFlags; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; + +typedef enum VkExternalMemoryHandleTypeFlagBits { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA = 0x00000800, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBits; +typedef VkFlags VkExternalMemoryHandleTypeFlags; + +typedef enum VkExternalMemoryFeatureFlagBits { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBits; +typedef VkFlags VkExternalMemoryFeatureFlags; + +typedef enum VkExternalFenceHandleTypeFlagBits { + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceHandleTypeFlagBits; +typedef VkFlags VkExternalFenceHandleTypeFlags; + +typedef enum VkExternalFenceFeatureFlagBits { + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalFenceFeatureFlagBits; +typedef VkFlags VkExternalFenceFeatureFlags; + +typedef enum VkFenceImportFlagBits { + VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkFenceImportFlagBits; +typedef VkFlags VkFenceImportFlags; + +typedef enum VkSemaphoreImportFlagBits { + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreImportFlagBits; +typedef VkFlags VkSemaphoreImportFlags; + +typedef enum VkExternalSemaphoreHandleTypeFlagBits { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA = 0x00000080, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreHandleTypeFlagBits; +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; + +typedef enum VkExternalSemaphoreFeatureFlagBits { + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkExternalSemaphoreFeatureFlagBits; +typedef VkFlags VkExternalSemaphoreFeatureFlags; +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void* pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; + +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; + +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; + +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; + +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void* pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; + +typedef struct VkMemoryDedicatedAllocateInfo { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkMemoryDedicatedAllocateInfo; + +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void* pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; + +typedef struct VkDeviceGroupRenderPassBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; + uint32_t deviceRenderAreaCount; + const VkRect2D* pDeviceRenderAreas; +} VkDeviceGroupRenderPassBeginInfo; + +typedef struct VkDeviceGroupCommandBufferBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceMask; +} VkDeviceGroupCommandBufferBeginInfo; + +typedef struct VkDeviceGroupSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const uint32_t* pWaitSemaphoreDeviceIndices; + uint32_t commandBufferCount; + const uint32_t* pCommandBufferDeviceMasks; + uint32_t signalSemaphoreCount; + const uint32_t* pSignalSemaphoreDeviceIndices; +} VkDeviceGroupSubmitInfo; + +typedef struct VkDeviceGroupBindSparseInfo { + VkStructureType sType; + const void* pNext; + uint32_t resourceDeviceIndex; + uint32_t memoryDeviceIndex; +} VkDeviceGroupBindSparseInfo; + +typedef struct VkBindBufferMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindBufferMemoryDeviceGroupInfo; + +typedef struct VkBindImageMemoryDeviceGroupInfo { + VkStructureType sType; + const void* pNext; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; + uint32_t splitInstanceBindRegionCount; + const VkRect2D* pSplitInstanceBindRegions; +} VkBindImageMemoryDeviceGroupInfo; + +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void* pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; + +typedef struct VkDeviceGroupDeviceCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t physicalDeviceCount; + const VkPhysicalDevice* pPhysicalDevices; +} VkDeviceGroupDeviceCreateInfo; + +typedef struct VkBufferMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferMemoryRequirementsInfo2; + +typedef struct VkImageMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageMemoryRequirementsInfo2; + +typedef struct VkImageSparseMemoryRequirementsInfo2 { + VkStructureType sType; + const void* pNext; + VkImage image; +} VkImageSparseMemoryRequirementsInfo2; + +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; + +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void* pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceProperties properties; +} VkPhysicalDeviceProperties2; + +typedef struct VkFormatProperties2 { + VkStructureType sType; + void* pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; + +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; + +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; + +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void* pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; + +typedef struct VkPhysicalDeviceMemoryProperties2 { + VkStructureType sType; + void* pNext; + VkPhysicalDeviceMemoryProperties memoryProperties; +} VkPhysicalDeviceMemoryProperties2; + +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void* pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; + +typedef struct VkPhysicalDevicePointClippingProperties { + VkStructureType sType; + void* pNext; + VkPointClippingBehavior pointClippingBehavior; +} VkPhysicalDevicePointClippingProperties; + +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference* pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; + +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; + +typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { + VkStructureType sType; + const void* pNext; + VkTessellationDomainOrigin domainOrigin; +} VkPipelineTessellationDomainOriginStateCreateInfo; + +typedef struct VkRenderPassMultiviewCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t subpassCount; + const uint32_t* pViewMasks; + uint32_t dependencyCount; + const int32_t* pViewOffsets; + uint32_t correlationMaskCount; + const uint32_t* pCorrelationMasks; +} VkRenderPassMultiviewCreateInfo; + +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void* pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; + +typedef struct VkPhysicalDeviceMultiviewProperties { + VkStructureType sType; + void* pNext; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; +} VkPhysicalDeviceMultiviewProperties; + +typedef struct VkPhysicalDeviceVariablePointersFeatures { + VkStructureType sType; + void* pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointersFeatures; + +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void* pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void* pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; + +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void* pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; + +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void* pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; + +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void* pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; + +typedef struct VkSamplerYcbcrConversionInfo { + VkStructureType sType; + const void* pNext; + VkSamplerYcbcrConversion conversion; +} VkSamplerYcbcrConversionInfo; + +typedef struct VkBindImagePlaneMemoryInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkBindImagePlaneMemoryInfo; + +typedef struct VkImagePlaneMemoryRequirementsInfo { + VkStructureType sType; + const void* pNext; + VkImageAspectFlagBits planeAspect; +} VkImagePlaneMemoryRequirementsInfo; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void* pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + +typedef struct VkSamplerYcbcrConversionImageFormatProperties { + VkStructureType sType; + void* pNext; + uint32_t combinedImageSamplerDescriptorCount; +} VkSamplerYcbcrConversionImageFormatProperties; + +typedef struct VkDescriptorUpdateTemplateEntry { + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + size_t offset; + size_t stride; +} VkDescriptorUpdateTemplateEntry; + +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + const void* pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; + +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; + +typedef struct VkPhysicalDeviceExternalImageFormatInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalImageFormatInfo; + +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; + +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void* pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; + +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void* pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; + +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; + +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; + +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; + +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; + +typedef struct VkPhysicalDeviceExternalFenceInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalFenceInfo; + +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void* pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; + +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; + +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; + +typedef struct VkPhysicalDeviceExternalSemaphoreInfo { + VkStructureType sType; + const void* pNext; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalSemaphoreInfo; + +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void* pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; + +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void* pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; + +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void* pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParametersFeatures; + +typedef VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion); +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion( + uint32_t* pApiVersion); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2( + VkDevice device, + const VkDeviceQueueInfo2* pQueueInfo, + VkQueue* pQueue); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); + +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); +#endif + + +#define VK_VERSION_1_2 1 +// Vulkan 1.2 version number +#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)// Patch version should always be set to 0 + +#define VK_MAX_DRIVER_NAME_SIZE 256U +#define VK_MAX_DRIVER_INFO_SIZE 256U + +typedef enum VkDriverId { + VK_DRIVER_ID_AMD_PROPRIETARY = 1, + VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, + VK_DRIVER_ID_MESA_RADV = 3, + VK_DRIVER_ID_NVIDIA_PROPRIETARY = 4, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS = 5, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA = 6, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY = 7, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY = 8, + VK_DRIVER_ID_ARM_PROPRIETARY = 9, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER = 10, + VK_DRIVER_ID_GGP_PROPRIETARY = 11, + VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, + VK_DRIVER_ID_MESA_LLVMPIPE = 13, + VK_DRIVER_ID_MOLTENVK = 14, + VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, + VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, + VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, + VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, + VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = VK_DRIVER_ID_NVIDIA_PROPRIETARY, + VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, + VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, + VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = VK_DRIVER_ID_IMAGINATION_PROPRIETARY, + VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, + VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, + VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, + VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, + VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF +} VkDriverId; + +typedef enum VkShaderFloatControlsIndependence { + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY = 0, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL = 1, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF +} VkShaderFloatControlsIndependence; + +typedef enum VkSamplerReductionMode { + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0, + VK_SAMPLER_REDUCTION_MODE_MIN = 1, + VK_SAMPLER_REDUCTION_MODE_MAX = 2, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, + VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, + VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, + VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkSamplerReductionMode; + +typedef enum VkSemaphoreType { + VK_SEMAPHORE_TYPE_BINARY = 0, + VK_SEMAPHORE_TYPE_TIMELINE = 1, + VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, + VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, + VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreType; + +typedef enum VkResolveModeFlagBits { + VK_RESOLVE_MODE_NONE = 0, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 0x00000001, + VK_RESOLVE_MODE_AVERAGE_BIT = 0x00000002, + VK_RESOLVE_MODE_MIN_BIT = 0x00000004, + VK_RESOLVE_MODE_MAX_BIT = 0x00000008, + VK_RESOLVE_MODE_NONE_KHR = VK_RESOLVE_MODE_NONE, + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, + VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, + VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, + VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkResolveModeFlagBits; +typedef VkFlags VkResolveModeFlags; + +typedef enum VkDescriptorBindingFlagBits { + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008, + VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkDescriptorBindingFlagBits; +typedef VkFlags VkDescriptorBindingFlags; + +typedef enum VkSemaphoreWaitFlagBits { + VK_SEMAPHORE_WAIT_ANY_BIT = 0x00000001, + VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, + VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSemaphoreWaitFlagBits; +typedef VkFlags VkSemaphoreWaitFlags; +typedef struct VkPhysicalDeviceVulkan11Features { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; + +typedef struct VkPhysicalDeviceVulkan11Properties { + VkStructureType sType; + void* pNext; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceLUID[VK_LUID_SIZE]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; + uint32_t subgroupSize; + VkShaderStageFlags subgroupSupportedStages; + VkSubgroupFeatureFlags subgroupSupportedOperations; + VkBool32 subgroupQuadOperationsInAllStages; + VkPointClippingBehavior pointClippingBehavior; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; + VkBool32 protectedNoFault; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceVulkan11Properties; + +typedef struct VkPhysicalDeviceVulkan12Features { + VkStructureType sType; + void* pNext; + VkBool32 samplerMirrorClampToEdge; + VkBool32 drawIndirectCount; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; + VkBool32 descriptorIndexing; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; + VkBool32 samplerFilterMinmax; + VkBool32 scalarBlockLayout; + VkBool32 imagelessFramebuffer; + VkBool32 uniformBufferStandardLayout; + VkBool32 shaderSubgroupExtendedTypes; + VkBool32 separateDepthStencilLayouts; + VkBool32 hostQueryReset; + VkBool32 timelineSemaphore; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; + VkBool32 shaderOutputViewportIndex; + VkBool32 shaderOutputLayer; + VkBool32 subgroupBroadcastDynamicId; +} VkPhysicalDeviceVulkan12Features; + +typedef struct VkConformanceVersion { + uint8_t major; + uint8_t minor; + uint8_t subminor; + uint8_t patch; +} VkConformanceVersion; + +typedef struct VkPhysicalDeviceVulkan12Properties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; + uint64_t maxTimelineSemaphoreValueDifference; + VkSampleCountFlags framebufferIntegerColorSampleCounts; +} VkPhysicalDeviceVulkan12Properties; + +typedef struct VkImageFormatListCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkImageFormatListCreateInfo; + +typedef struct VkAttachmentDescription2 { + VkStructureType sType; + const void* pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2; + +typedef struct VkAttachmentReference2 { + VkStructureType sType; + const void* pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2; + +typedef struct VkSubpassDescription2 { + VkStructureType sType; + const void* pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2* pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2* pColorAttachments; + const VkAttachmentReference2* pResolveAttachments; + const VkAttachmentReference2* pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t* pPreserveAttachments; +} VkSubpassDescription2; + +typedef struct VkSubpassDependency2 { + VkStructureType sType; + const void* pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2; + +typedef struct VkRenderPassCreateInfo2 { + VkStructureType sType; + const void* pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2* pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2* pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2* pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t* pCorrelatedViewMasks; +} VkRenderPassCreateInfo2; + +typedef struct VkSubpassBeginInfo { + VkStructureType sType; + const void* pNext; + VkSubpassContents contents; +} VkSubpassBeginInfo; + +typedef struct VkSubpassEndInfo { + VkStructureType sType; + const void* pNext; +} VkSubpassEndInfo; + +typedef struct VkPhysicalDevice8BitStorageFeatures { + VkStructureType sType; + void* pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeatures; + +typedef struct VkPhysicalDeviceDriverProperties { + VkStructureType sType; + void* pNext; + VkDriverId driverID; + char driverName[VK_MAX_DRIVER_NAME_SIZE]; + char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; + VkConformanceVersion conformanceVersion; +} VkPhysicalDeviceDriverProperties; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64Features; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features { + VkStructureType sType; + void* pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceShaderFloat16Int8Features; + +typedef struct VkPhysicalDeviceFloatControlsProperties { + VkStructureType sType; + void* pNext; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsProperties; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlags* pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfo; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeatures; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties { + VkStructureType sType; + void* pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingProperties; + +typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo { + VkStructureType sType; + const void* pNext; + uint32_t descriptorSetCount; + const uint32_t* pDescriptorCounts; +} VkDescriptorSetVariableDescriptorCountAllocateInfo; + +typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport { + VkStructureType sType; + void* pNext; + uint32_t maxVariableDescriptorCount; +} VkDescriptorSetVariableDescriptorCountLayoutSupport; + +typedef struct VkSubpassDescriptionDepthStencilResolve { + VkStructureType sType; + const void* pNext; + VkResolveModeFlagBits depthResolveMode; + VkResolveModeFlagBits stencilResolveMode; + const VkAttachmentReference2* pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolve; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties { + VkStructureType sType; + void* pNext; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolveProperties; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeatures; + +typedef struct VkImageStencilUsageCreateInfo { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfo; + +typedef struct VkSamplerReductionModeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSamplerReductionMode reductionMode; +} VkSamplerReductionModeCreateInfo; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { + VkStructureType sType; + void* pNext; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; +} VkPhysicalDeviceSamplerFilterMinmaxProperties; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { + VkStructureType sType; + void* pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; +} VkPhysicalDeviceVulkanMemoryModelFeatures; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { + VkStructureType sType; + void* pNext; + VkBool32 imagelessFramebuffer; +} VkPhysicalDeviceImagelessFramebufferFeatures; + +typedef struct VkFramebufferAttachmentImageInfo { + VkStructureType sType; + const void* pNext; + VkImageCreateFlags flags; + VkImageUsageFlags usage; + uint32_t width; + uint32_t height; + uint32_t layerCount; + uint32_t viewFormatCount; + const VkFormat* pViewFormats; +} VkFramebufferAttachmentImageInfo; + +typedef struct VkFramebufferAttachmentsCreateInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentImageInfoCount; + const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos; +} VkFramebufferAttachmentsCreateInfo; + +typedef struct VkRenderPassAttachmentBeginInfo { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkImageView* pAttachments; +} VkRenderPassAttachmentBeginInfo; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { + VkStructureType sType; + void* pNext; + VkBool32 uniformBufferStandardLayout; +} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupExtendedTypes; +} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { + VkStructureType sType; + void* pNext; + VkBool32 separateDepthStencilLayouts; +} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; + +typedef struct VkAttachmentReferenceStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilLayout; +} VkAttachmentReferenceStencilLayout; + +typedef struct VkAttachmentDescriptionStencilLayout { + VkStructureType sType; + void* pNext; + VkImageLayout stencilInitialLayout; + VkImageLayout stencilFinalLayout; +} VkAttachmentDescriptionStencilLayout; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures { + VkStructureType sType; + void* pNext; + VkBool32 hostQueryReset; +} VkPhysicalDeviceHostQueryResetFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { + VkStructureType sType; + void* pNext; + VkBool32 timelineSemaphore; +} VkPhysicalDeviceTimelineSemaphoreFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreProperties { + VkStructureType sType; + void* pNext; + uint64_t maxTimelineSemaphoreValueDifference; +} VkPhysicalDeviceTimelineSemaphoreProperties; + +typedef struct VkSemaphoreTypeCreateInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreType semaphoreType; + uint64_t initialValue; +} VkSemaphoreTypeCreateInfo; + +typedef struct VkTimelineSemaphoreSubmitInfo { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreValueCount; + const uint64_t* pWaitSemaphoreValues; + uint32_t signalSemaphoreValueCount; + const uint64_t* pSignalSemaphoreValues; +} VkTimelineSemaphoreSubmitInfo; + +typedef struct VkSemaphoreWaitInfo { + VkStructureType sType; + const void* pNext; + VkSemaphoreWaitFlags flags; + uint32_t semaphoreCount; + const VkSemaphore* pSemaphores; + const uint64_t* pValues; +} VkSemaphoreWaitInfo; + +typedef struct VkSemaphoreSignalInfo { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; +} VkSemaphoreSignalInfo; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeatures; + +typedef struct VkBufferDeviceAddressInfo { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; +} VkBufferDeviceAddressInfo; + +typedef struct VkBufferOpaqueCaptureAddressCreateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkBufferOpaqueCaptureAddressCreateInfo; + +typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo { + VkStructureType sType; + const void* pNext; + uint64_t opaqueCaptureAddress; +} VkMemoryOpaqueCaptureAddressAllocateInfo; + +typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkDeviceMemoryOpaqueCaptureAddressInfo; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCount( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkResetQueryPool( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValue( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphores( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphore( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddress( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddress( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif + + +#define VK_KHR_surface 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) +#define VK_KHR_SURFACE_SPEC_VERSION 25 +#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" + +typedef enum VkPresentModeKHR { + VK_PRESENT_MODE_IMMEDIATE_KHR = 0, + VK_PRESENT_MODE_MAILBOX_KHR = 1, + VK_PRESENT_MODE_FIFO_KHR = 2, + VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, + VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPresentModeKHR; + +typedef enum VkColorSpaceKHR { + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, + VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, + VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, + VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, + VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, + VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, + VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, + VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, + VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, + VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, + VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, + VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, + VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, + VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkColorSpaceKHR; + +typedef enum VkSurfaceTransformFlagBitsKHR { + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSurfaceTransformFlagBitsKHR; + +typedef enum VkCompositeAlphaFlagBitsKHR { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCompositeAlphaFlagBitsKHR; +typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +typedef struct VkSurfaceFormatKHR { + VkFormat format; + VkColorSpaceKHR colorSpace; +} VkSurfaceFormatKHR; + +typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( + VkInstance instance, + VkSurfaceKHR surface, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32* pSupported); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); +#endif + + +#define VK_KHR_swapchain 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) +#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 +#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" + +typedef enum VkSwapchainCreateFlagBitsKHR { + VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, + VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, + VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, + VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSwapchainCreateFlagBitsKHR; +typedef VkFlags VkSwapchainCreateFlagsKHR; + +typedef enum VkDeviceGroupPresentModeFlagBitsKHR { + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, + VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, + VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, + VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDeviceGroupPresentModeFlagBitsKHR; +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore* pWaitSemaphores; + uint32_t swapchainCount; + const VkSwapchainKHR* pSwapchains; + const uint32_t* pImageIndices; + VkResult* pResults; +} VkPresentInfoKHR; + +typedef struct VkImageSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; +} VkImageSwapchainCreateInfoKHR; + +typedef struct VkBindImageMemorySwapchainInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndex; +} VkBindImageMemorySwapchainInfoKHR; + +typedef struct VkAcquireNextImageInfoKHR { + VkStructureType sType; + const void* pNext; + VkSwapchainKHR swapchain; + uint64_t timeout; + VkSemaphore semaphore; + VkFence fence; + uint32_t deviceMask; +} VkAcquireNextImageInfoKHR; + +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + const void* pNext; + uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; + +typedef struct VkDeviceGroupPresentInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const uint32_t* pDeviceMasks; + VkDeviceGroupPresentModeFlagBitsKHR mode; +} VkDeviceGroupPresentInfoKHR; + +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); +typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); +typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( + VkDevice device, + const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchain); + +VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainImageCount, + VkImage* pSwapchainImages); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t* pImageIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( + VkQueue queue, + const VkPresentInfoKHR* pPresentInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR( + VkDevice device, + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR( + VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR* pModes); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( + VkDevice device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + uint32_t* pImageIndex); +#endif + + +#define VK_KHR_display 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) +#define VK_KHR_DISPLAY_SPEC_VERSION 23 +#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" +typedef VkFlags VkDisplayModeCreateFlagsKHR; + +typedef enum VkDisplayPlaneAlphaFlagBitsKHR { + VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, + VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkDisplayPlaneAlphaFlagBitsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +typedef struct VkDisplayModeParametersKHR { + VkExtent2D visibleRegion; + uint32_t refreshRate; +} VkDisplayModeParametersKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayModePropertiesKHR { + VkDisplayModeKHR displayMode; + VkDisplayModeParametersKHR parameters; +} VkDisplayModePropertiesKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplayPlanePropertiesKHR { + VkDisplayKHR currentDisplay; + uint32_t currentStackIndex; +} VkDisplayPlanePropertiesKHR; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char* displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlanePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t* pDisplayCount, + VkDisplayKHR* pDisplays); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDisplayModeKHR* pMode); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR mode, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR* pCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( + VkInstance instance, + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +#define VK_KHR_display_swapchain 1 +#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 10 +#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void* pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchains); +#endif + + +#define VK_KHR_sampler_mirror_clamp_to_edge 1 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 3 +#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" + + +#define VK_KHR_multiview 1 +#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 +#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" +typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; + +typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; + +typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; + + + +#define VK_KHR_get_physical_device_properties2 1 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 2 +#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" +typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; + +typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; + +typedef VkFormatProperties2 VkFormatProperties2KHR; + +typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; + +typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; + +typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; + +typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; + +typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + +typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2* pFeatures); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2* pProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2* pFormatProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, + VkImageFormatProperties2* pImageFormatProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pQueueFamilyPropertyCount, + VkQueueFamilyProperties2* pQueueFamilyProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2* pMemoryProperties); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, + uint32_t* pPropertyCount, + VkSparseImageFormatProperties2* pProperties); +#endif + + +#define VK_KHR_device_group 1 +#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 4 +#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" +typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; + +typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; + +typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; + +typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; + +typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; + +typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; + +typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; + +typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; + +typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; + +typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; + +typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); +typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR( + VkCommandBuffer commandBuffer, + uint32_t deviceMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( + VkCommandBuffer commandBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); +#endif + + +#define VK_KHR_shader_draw_parameters 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" + + +#define VK_KHR_maintenance1 1 +#define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" +typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; + +typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( + VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlags flags); +#endif + + +#define VK_KHR_device_group_creation 1 +#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 +#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" +#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE +typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; + +typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR( + VkInstance instance, + uint32_t* pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +#endif + + +#define VK_KHR_external_memory_capabilities 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" +#define VK_LUID_SIZE_KHR VK_LUID_SIZE +typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; + +typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; + +typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; + +typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; + +typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; + +typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; + +typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + +typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; + +typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; + +typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties); +#endif + + +#define VK_KHR_external_memory 1 +#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" +#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL +typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; + +typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; + +typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; + + + +#define VK_KHR_external_memory_fd 1 +#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" +typedef struct VkImportMemoryFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + int fd; +} VkImportMemoryFdInfoKHR; + +typedef struct VkMemoryFdPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryFdPropertiesKHR; + +typedef struct VkMemoryGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( + VkDevice device, + const VkMemoryGetFdInfoKHR* pGetFdInfo, + int* pFd); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + int fd, + VkMemoryFdPropertiesKHR* pMemoryFdProperties); +#endif + + +#define VK_KHR_external_semaphore_capabilities 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" +typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; + +typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; + +typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; + +typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; + +typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; + +typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, + VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +#endif + + +#define VK_KHR_external_semaphore 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" +typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; + +typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; + +typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; + + + +#define VK_KHR_external_semaphore_fd 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" +typedef struct VkImportSemaphoreFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + int fd; +} VkImportSemaphoreFdInfoKHR; + +typedef struct VkSemaphoreGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR( + VkDevice device, + const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR( + VkDevice device, + const VkSemaphoreGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif + + +#define VK_KHR_push_descriptor 1 +#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" +typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t maxPushDescriptors; +} VkPhysicalDevicePushDescriptorPropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); +typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites); + +VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( + VkCommandBuffer commandBuffer, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + VkPipelineLayout layout, + uint32_t set, + const void* pData); +#endif + + +#define VK_KHR_shader_float16_int8 1 +#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; + +typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; + + + +#define VK_KHR_16bit_storage 1 +#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" +typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; + + + +#define VK_KHR_incremental_present 1 +#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 2 +#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" +typedef struct VkRectLayerKHR { + VkOffset2D offset; + VkExtent2D extent; + uint32_t layer; +} VkRectLayerKHR; + +typedef struct VkPresentRegionKHR { + uint32_t rectangleCount; + const VkRectLayerKHR* pRectangles; +} VkPresentRegionKHR; + +typedef struct VkPresentRegionsKHR { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentRegionKHR* pRegions; +} VkPresentRegionsKHR; + + + +#define VK_KHR_descriptor_update_template 1 +typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; + +#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 +#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" +typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; + +typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; + +typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; + +typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR( + VkDevice device, + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR( + VkDevice device, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( + VkDevice device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void* pData); +#endif + + +#define VK_KHR_imageless_framebuffer 1 +#define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 +#define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" +typedef VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; + +typedef VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; + +typedef VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; + +typedef VkRenderPassAttachmentBeginInfo VkRenderPassAttachmentBeginInfoKHR; + + + +#define VK_KHR_create_renderpass2 1 +#define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 +#define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" +typedef VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; + +typedef VkAttachmentDescription2 VkAttachmentDescription2KHR; + +typedef VkAttachmentReference2 VkAttachmentReference2KHR; + +typedef VkSubpassDescription2 VkSubpassDescription2KHR; + +typedef VkSubpassDependency2 VkSubpassDependency2KHR; + +typedef VkSubpassBeginInfo VkSubpassBeginInfoKHR; + +typedef VkSubpassEndInfo VkSubpassEndInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); +typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo); +typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass2KHR( + VkDevice device, + const VkRenderPassCreateInfo2* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkRenderPass* pRenderPass); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + const VkSubpassBeginInfo* pSubpassBeginInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassBeginInfo* pSubpassBeginInfo, + const VkSubpassEndInfo* pSubpassEndInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass2KHR( + VkCommandBuffer commandBuffer, + const VkSubpassEndInfo* pSubpassEndInfo); +#endif + + +#define VK_KHR_shared_presentable_image 1 +#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 +#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" +typedef struct VkSharedPresentSurfaceCapabilitiesKHR { + VkStructureType sType; + void* pNext; + VkImageUsageFlags sharedPresentSupportedUsageFlags; +} VkSharedPresentSurfaceCapabilitiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR( + VkDevice device, + VkSwapchainKHR swapchain); +#endif + + +#define VK_KHR_external_fence_capabilities 1 +#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" +typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; + +typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; + +typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; + +typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; + +typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; + +typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; + +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, + VkExternalFenceProperties* pExternalFenceProperties); +#endif + + +#define VK_KHR_external_fence 1 +#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" +typedef VkFenceImportFlags VkFenceImportFlagsKHR; + +typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; + +typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + + + +#define VK_KHR_external_fence_fd 1 +#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" +typedef struct VkImportFenceFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + int fd; +} VkImportFenceFdInfoKHR; + +typedef struct VkFenceGetFdInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; +} VkFenceGetFdInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR( + VkDevice device, + const VkImportFenceFdInfoKHR* pImportFenceFdInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( + VkDevice device, + const VkFenceGetFdInfoKHR* pGetFdInfo, + int* pFd); +#endif + + +#define VK_KHR_performance_query 1 +#define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" + +typedef enum VkPerformanceCounterUnitKHR { + VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, + VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, + VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR = 2, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR = 3, + VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR = 4, + VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR = 5, + VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR = 6, + VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, + VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, + VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, + VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, + VK_PERFORMANCE_COUNTER_UNIT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterUnitKHR; + +typedef enum VkPerformanceCounterScopeKHR { + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, + VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR = 1, + VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, + VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, + VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, + VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, + VK_PERFORMANCE_COUNTER_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterScopeKHR; + +typedef enum VkPerformanceCounterStorageKHR { + VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, + VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, + VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, + VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, + VK_PERFORMANCE_COUNTER_STORAGE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterStorageKHR; + +typedef enum VkPerformanceCounterDescriptionFlagBitsKHR { + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR = 0x00000001, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR = 0x00000002, + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPerformanceCounterDescriptionFlagBitsKHR; +typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; + +typedef enum VkAcquireProfilingLockFlagBitsKHR { + VK_ACQUIRE_PROFILING_LOCK_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAcquireProfilingLockFlagBitsKHR; +typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 performanceCounterQueryPools; + VkBool32 performanceCounterMultipleQueryPools; +} VkPhysicalDevicePerformanceQueryFeaturesKHR; + +typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { + VkStructureType sType; + void* pNext; + VkBool32 allowCommandBufferQueryCopies; +} VkPhysicalDevicePerformanceQueryPropertiesKHR; + +typedef struct VkPerformanceCounterKHR { + VkStructureType sType; + const void* pNext; + VkPerformanceCounterUnitKHR unit; + VkPerformanceCounterScopeKHR scope; + VkPerformanceCounterStorageKHR storage; + uint8_t uuid[VK_UUID_SIZE]; +} VkPerformanceCounterKHR; + +typedef struct VkPerformanceCounterDescriptionKHR { + VkStructureType sType; + const void* pNext; + VkPerformanceCounterDescriptionFlagsKHR flags; + char name[VK_MAX_DESCRIPTION_SIZE]; + char category[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; +} VkPerformanceCounterDescriptionKHR; + +typedef struct VkQueryPoolPerformanceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t queueFamilyIndex; + uint32_t counterIndexCount; + const uint32_t* pCounterIndices; +} VkQueryPoolPerformanceCreateInfoKHR; + +typedef union VkPerformanceCounterResultKHR { + int32_t int32; + int64_t int64; + uint32_t uint32; + uint64_t uint64; + float float32; + double float64; +} VkPerformanceCounterResultKHR; + +typedef struct VkAcquireProfilingLockInfoKHR { + VkStructureType sType; + const void* pNext; + VkAcquireProfilingLockFlagsKHR flags; + uint64_t timeout; +} VkAcquireProfilingLockInfoKHR; + +typedef struct VkPerformanceQuerySubmitInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t counterPassIndex; +} VkPerformanceQuerySubmitInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t* pCounterCount, VkPerformanceCounterKHR* pCounters, VkPerformanceCounterDescriptionKHR* pCounterDescriptions); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, uint32_t* pNumPasses); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice device, const VkAcquireProfilingLockInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice device); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + uint32_t* pCounterCount, + VkPerformanceCounterKHR* pCounters, + VkPerformanceCounterDescriptionKHR* pCounterDescriptions); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR( + VkPhysicalDevice physicalDevice, + const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo, + uint32_t* pNumPasses); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireProfilingLockKHR( + VkDevice device, + const VkAcquireProfilingLockInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkReleaseProfilingLockKHR( + VkDevice device); +#endif + + +#define VK_KHR_maintenance2 1 +#define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" +typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; + +typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; + +typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; + +typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; + +typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; + +typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; + +typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; + + + +#define VK_KHR_get_surface_capabilities2 1 +#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" +typedef struct VkPhysicalDeviceSurfaceInfo2KHR { + VkStructureType sType; + const void* pNext; + VkSurfaceKHR surface; +} VkPhysicalDeviceSurfaceInfo2KHR; + +typedef struct VkSurfaceCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkSurfaceCapabilitiesKHR surfaceCapabilities; +} VkSurfaceCapabilities2KHR; + +typedef struct VkSurfaceFormat2KHR { + VkStructureType sType; + void* pNext; + VkSurfaceFormatKHR surfaceFormat; +} VkSurfaceFormat2KHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + VkSurfaceCapabilities2KHR* pSurfaceCapabilities); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormat2KHR* pSurfaceFormats); +#endif + + +#define VK_KHR_variable_pointers 1 +#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 +#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; + +typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; + + + +#define VK_KHR_get_display_properties2 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 +#define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" +typedef struct VkDisplayProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPropertiesKHR displayProperties; +} VkDisplayProperties2KHR; + +typedef struct VkDisplayPlaneProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlanePropertiesKHR displayPlaneProperties; +} VkDisplayPlaneProperties2KHR; + +typedef struct VkDisplayModeProperties2KHR { + VkStructureType sType; + void* pNext; + VkDisplayModePropertiesKHR displayModeProperties; +} VkDisplayModeProperties2KHR; + +typedef struct VkDisplayPlaneInfo2KHR { + VkStructureType sType; + const void* pNext; + VkDisplayModeKHR mode; + uint32_t planeIndex; +} VkDisplayPlaneInfo2KHR; + +typedef struct VkDisplayPlaneCapabilities2KHR { + VkStructureType sType; + void* pNext; + VkDisplayPlaneCapabilitiesKHR capabilities; +} VkDisplayPlaneCapabilities2KHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlaneProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModeProperties2KHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR* pCapabilities); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlaneProperties2KHR( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkDisplayPlaneProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModeProperties2KHR( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t* pPropertyCount, + VkDisplayModeProperties2KHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilities2KHR( + VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR* pCapabilities); +#endif + + +#define VK_KHR_dedicated_allocation 1 +#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 +#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" +typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; + +typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; + + + +#define VK_KHR_storage_buffer_storage_class 1 +#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 +#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" + + +#define VK_KHR_relaxed_block_layout 1 +#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" + + +#define VK_KHR_get_memory_requirements2 1 +#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 +#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" +typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; + +typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; + +typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; + +typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; + +typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; + +typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( + VkDevice device, + const VkImageMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( + VkDevice device, + const VkBufferMemoryRequirementsInfo2* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2* pInfo, + uint32_t* pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +#endif + + +#define VK_KHR_image_format_list 1 +#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 +#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" +typedef VkImageFormatListCreateInfo VkImageFormatListCreateInfoKHR; + + + +#define VK_KHR_sampler_ycbcr_conversion 1 +typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; + +#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 14 +#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" +typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; + +typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; + +typedef VkChromaLocation VkChromaLocationKHR; + +typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; + +typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; + +typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; + +typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; + +typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; + +typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSamplerYcbcrConversion* pYcbcrConversion); + +VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR( + VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks* pAllocator); +#endif + + +#define VK_KHR_bind_memory2 1 +#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 +#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" +typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + +typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfo* pBindInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( + VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo* pBindInfos); +#endif + + +#define VK_KHR_maintenance3 1 +#define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" +typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; + +typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; + +typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayoutSupport* pSupport); +#endif + + +#define VK_KHR_draw_indirect_count 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 +#define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + + +#define VK_KHR_shader_subgroup_extended_types 1 +#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" +typedef VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; + + + +#define VK_KHR_8bit_storage 1 +#define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" +typedef VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; + + + +#define VK_KHR_shader_atomic_int64 1 +#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" +typedef VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + + + +#define VK_KHR_shader_clock 1 +#define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 +#define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" +typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderSubgroupClock; + VkBool32 shaderDeviceClock; +} VkPhysicalDeviceShaderClockFeaturesKHR; + + + +#define VK_KHR_driver_properties 1 +#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" +#define VK_MAX_DRIVER_NAME_SIZE_KHR VK_MAX_DRIVER_NAME_SIZE +#define VK_MAX_DRIVER_INFO_SIZE_KHR VK_MAX_DRIVER_INFO_SIZE +typedef VkDriverId VkDriverIdKHR; + +typedef VkConformanceVersion VkConformanceVersionKHR; + +typedef VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; + + + +#define VK_KHR_shader_float_controls 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 +#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" +typedef VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; + +typedef VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; + + + +#define VK_KHR_depth_stencil_resolve 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 +#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" +typedef VkResolveModeFlagBits VkResolveModeFlagBitsKHR; + +typedef VkResolveModeFlags VkResolveModeFlagsKHR; + +typedef VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; + +typedef VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; + + + +#define VK_KHR_swapchain_mutable_format 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 +#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" + + +#define VK_KHR_timeline_semaphore 1 +#define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 +#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" +typedef VkSemaphoreType VkSemaphoreTypeKHR; + +typedef VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; + +typedef VkSemaphoreWaitFlags VkSemaphoreWaitFlagsKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + +typedef VkPhysicalDeviceTimelineSemaphoreProperties VkPhysicalDeviceTimelineSemaphorePropertiesKHR; + +typedef VkSemaphoreTypeCreateInfo VkSemaphoreTypeCreateInfoKHR; + +typedef VkTimelineSemaphoreSubmitInfo VkTimelineSemaphoreSubmitInfoKHR; + +typedef VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; + +typedef VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice device, VkSemaphore semaphore, uint64_t* pValue); +typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout); +typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreCounterValueKHR( + VkDevice device, + VkSemaphore semaphore, + uint64_t* pValue); + +VKAPI_ATTR VkResult VKAPI_CALL vkWaitSemaphoresKHR( + VkDevice device, + const VkSemaphoreWaitInfo* pWaitInfo, + uint64_t timeout); + +VKAPI_ATTR VkResult VKAPI_CALL vkSignalSemaphoreKHR( + VkDevice device, + const VkSemaphoreSignalInfo* pSignalInfo); +#endif + + +#define VK_KHR_vulkan_memory_model 1 +#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 +#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" +typedef VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; + + + +#define VK_KHR_shader_terminate_invocation 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderTerminateInvocation; +} VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; + + + +#define VK_KHR_fragment_shading_rate 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" + +typedef enum VkFragmentShadingRateCombinerOpKHR { + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR = 0, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR = 1, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR = 2, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR = 3, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR = 4, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_ENUM_KHR = 0x7FFFFFFF +} VkFragmentShadingRateCombinerOpKHR; +typedef struct VkFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void* pNext; + const VkAttachmentReference2* pFragmentShadingRateAttachment; + VkExtent2D shadingRateAttachmentTexelSize; +} VkFragmentShadingRateAttachmentInfoKHR; + +typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkExtent2D fragmentSize; + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; +} VkPipelineFragmentShadingRateStateCreateInfoKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineFragmentShadingRate; + VkBool32 primitiveFragmentShadingRate; + VkBool32 attachmentFragmentShadingRate; +} VkPhysicalDeviceFragmentShadingRateFeaturesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentShadingRateAttachmentTexelSize; + VkExtent2D maxFragmentShadingRateAttachmentTexelSize; + uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; + VkBool32 primitiveFragmentShadingRateWithMultipleViewports; + VkBool32 layeredShadingRateAttachments; + VkBool32 fragmentShadingRateNonTrivialCombinerOps; + VkExtent2D maxFragmentSize; + uint32_t maxFragmentSizeAspectRatio; + uint32_t maxFragmentShadingRateCoverageSamples; + VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; + VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; + VkBool32 fragmentShadingRateWithSampleMask; + VkBool32 fragmentShadingRateWithShaderSampleMask; + VkBool32 fragmentShadingRateWithConservativeRasterization; + VkBool32 fragmentShadingRateWithFragmentShaderInterlock; + VkBool32 fragmentShadingRateWithCustomSampleLocations; + VkBool32 fragmentShadingRateStrictMultiplyCombiner; +} VkPhysicalDeviceFragmentShadingRatePropertiesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateKHR { + VkStructureType sType; + void* pNext; + VkSampleCountFlags sampleCounts; + VkExtent2D fragmentSize; +} VkPhysicalDeviceFragmentShadingRateKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates); +typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer commandBuffer, const VkExtent2D* pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceFragmentShadingRatesKHR( + VkPhysicalDevice physicalDevice, + uint32_t* pFragmentShadingRateCount, + VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateKHR( + VkCommandBuffer commandBuffer, + const VkExtent2D* pFragmentSize, + const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); +#endif + + +#define VK_KHR_spirv_1_4 1 +#define VK_KHR_SPIRV_1_4_SPEC_VERSION 1 +#define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" + + +#define VK_KHR_surface_protected_capabilities 1 +#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION 1 +#define VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME "VK_KHR_surface_protected_capabilities" +typedef struct VkSurfaceProtectedCapabilitiesKHR { + VkStructureType sType; + const void* pNext; + VkBool32 supportsProtected; +} VkSurfaceProtectedCapabilitiesKHR; + + + +#define VK_KHR_separate_depth_stencil_layouts 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 +#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME "VK_KHR_separate_depth_stencil_layouts" +typedef VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; + +typedef VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; + +typedef VkAttachmentDescriptionStencilLayout VkAttachmentDescriptionStencilLayoutKHR; + + + +#define VK_KHR_uniform_buffer_standard_layout 1 +#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" +typedef VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; + + + +#define VK_KHR_buffer_device_address 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 +#define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" +typedef VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoKHR; + +typedef VkBufferOpaqueCaptureAddressCreateInfo VkBufferOpaqueCaptureAddressCreateInfoKHR; + +typedef VkMemoryOpaqueCaptureAddressAllocateInfo VkMemoryOpaqueCaptureAddressAllocateInfoKHR; + +typedef VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); +typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddressKHR( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); + +VKAPI_ATTR uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddressKHR( + VkDevice device, + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo); +#endif + + +#define VK_KHR_deferred_host_operations 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 4 +#define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" +typedef VkResult (VKAPI_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice device, const VkAllocationCallbacks* pAllocator, VkDeferredOperationKHR* pDeferredOperation); +typedef void (VKAPI_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks* pAllocator); +typedef uint32_t (VKAPI_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (VKAPI_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice device, VkDeferredOperationKHR operation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDeferredOperationKHR( + VkDevice device, + const VkAllocationCallbacks* pAllocator, + VkDeferredOperationKHR* pDeferredOperation); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDeferredOperationKHR( + VkDevice device, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR uint32_t VKAPI_CALL vkGetDeferredOperationMaxConcurrencyKHR( + VkDevice device, + VkDeferredOperationKHR operation); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeferredOperationResultKHR( + VkDevice device, + VkDeferredOperationKHR operation); + +VKAPI_ATTR VkResult VKAPI_CALL vkDeferredOperationJoinKHR( + VkDevice device, + VkDeferredOperationKHR operation); +#endif + + +#define VK_KHR_pipeline_executable_properties 1 +#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" + +typedef enum VkPipelineExecutableStatisticFormatKHR { + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR = 0, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPipelineExecutableStatisticFormatKHR; +typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 pipelineExecutableInfo; +} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; + +typedef struct VkPipelineInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipeline pipeline; +} VkPipelineInfoKHR; + +typedef struct VkPipelineExecutablePropertiesKHR { + VkStructureType sType; + void* pNext; + VkShaderStageFlags stages; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + uint32_t subgroupSize; +} VkPipelineExecutablePropertiesKHR; + +typedef struct VkPipelineExecutableInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipeline pipeline; + uint32_t executableIndex; +} VkPipelineExecutableInfoKHR; + +typedef union VkPipelineExecutableStatisticValueKHR { + VkBool32 b32; + int64_t i64; + uint64_t u64; + double f64; +} VkPipelineExecutableStatisticValueKHR; + +typedef struct VkPipelineExecutableStatisticKHR { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkPipelineExecutableStatisticFormatKHR format; + VkPipelineExecutableStatisticValueKHR value; +} VkPipelineExecutableStatisticKHR; + +typedef struct VkPipelineExecutableInternalRepresentationKHR { + VkStructureType sType; + void* pNext; + char name[VK_MAX_DESCRIPTION_SIZE]; + char description[VK_MAX_DESCRIPTION_SIZE]; + VkBool32 isText; + size_t dataSize; + void* pData; +} VkPipelineExecutableInternalRepresentationKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutablePropertiesKHR)(VkDevice device, const VkPipelineInfoKHR* pPipelineInfo, uint32_t* pExecutableCount, VkPipelineExecutablePropertiesKHR* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableStatisticsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR* pExecutableInfo, uint32_t* pStatisticCount, VkPipelineExecutableStatisticKHR* pStatistics); +typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR* pExecutableInfo, uint32_t* pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutablePropertiesKHR( + VkDevice device, + const VkPipelineInfoKHR* pPipelineInfo, + uint32_t* pExecutableCount, + VkPipelineExecutablePropertiesKHR* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableStatisticsKHR( + VkDevice device, + const VkPipelineExecutableInfoKHR* pExecutableInfo, + uint32_t* pStatisticCount, + VkPipelineExecutableStatisticKHR* pStatistics); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR( + VkDevice device, + const VkPipelineExecutableInfoKHR* pExecutableInfo, + uint32_t* pInternalRepresentationCount, + VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations); +#endif + + +#define VK_KHR_pipeline_library 1 +#define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" +typedef struct VkPipelineLibraryCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t libraryCount; + const VkPipeline* pLibraries; +} VkPipelineLibraryCreateInfoKHR; + + + +#define VK_KHR_shader_non_semantic_info 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 +#define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" + + +#define VK_KHR_synchronization2 1 +typedef uint64_t VkFlags64; +#define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 +#define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" +typedef VkFlags64 VkPipelineStageFlags2KHR; + +// Flag bits for VkPipelineStageFlagBits2KHR +typedef VkFlags64 VkPipelineStageFlagBits2KHR; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_NONE_KHR = 0ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 0x00000001ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 0x00000002ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 0x00000004ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 0x00000008ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 0x00000010ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 0x00000020ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 0x00000040ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 0x00000080ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 0x00000100ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 0x00000200ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 0x00000400ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 0x00000800ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 0x00001000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 0x00001000; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 0x00002000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 0x00004000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 0x00008000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 0x00010000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 0x100000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 0x200000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 0x400000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 0x800000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 0x1000000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 0x2000000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR = 0x04000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR = 0x08000000ULL; +#endif +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 0x00400000; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 0x00200000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 0x00200000; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ULL; +static const VkPipelineStageFlagBits2KHR VK_PIPELINE_STAGE_FLAG_BITS_2KHR_MAX_ENUM_KHR = 0x7FFFFFFFFFFFFFFFULL; + +typedef VkFlags64 VkAccessFlags2KHR; + +// Flag bits for VkAccessFlagBits2KHR +typedef VkFlags64 VkAccessFlagBits2KHR; +static const VkAccessFlagBits2KHR VK_ACCESS_2_NONE_KHR = 0ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR = 0x800000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR = 0x1000000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR = 0x2000000000ULL; +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS +static const VkAccessFlagBits2KHR VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR = 0x4000000000ULL; +#endif +static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000; +static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000; +static const VkAccessFlagBits2KHR VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000; +static const VkAccessFlagBits2KHR VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ULL; +static const VkAccessFlagBits2KHR VK_ACCESS_FLAG_BITS_2KHR_MAX_ENUM_KHR = 0x7FFFFFFFFFFFFFFFULL; + + +typedef enum VkSubmitFlagBitsKHR { + VK_SUBMIT_PROTECTED_BIT_KHR = 0x00000001, + VK_SUBMIT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkSubmitFlagBitsKHR; +typedef VkFlags VkSubmitFlagsKHR; +typedef struct VkMemoryBarrier2KHR { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2KHR srcStageMask; + VkAccessFlags2KHR srcAccessMask; + VkPipelineStageFlags2KHR dstStageMask; + VkAccessFlags2KHR dstAccessMask; +} VkMemoryBarrier2KHR; + +typedef struct VkBufferMemoryBarrier2KHR { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2KHR srcStageMask; + VkAccessFlags2KHR srcAccessMask; + VkPipelineStageFlags2KHR dstStageMask; + VkAccessFlags2KHR dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier2KHR; + +typedef struct VkImageMemoryBarrier2KHR { + VkStructureType sType; + const void* pNext; + VkPipelineStageFlags2KHR srcStageMask; + VkAccessFlags2KHR srcAccessMask; + VkPipelineStageFlags2KHR dstStageMask; + VkAccessFlags2KHR dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier2KHR; + +typedef struct VkDependencyInfoKHR { + VkStructureType sType; + const void* pNext; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier2KHR* pMemoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier2KHR* pBufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier2KHR* pImageMemoryBarriers; +} VkDependencyInfoKHR; + +typedef struct VkSemaphoreSubmitInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + uint64_t value; + VkPipelineStageFlags2KHR stageMask; + uint32_t deviceIndex; +} VkSemaphoreSubmitInfoKHR; + +typedef struct VkCommandBufferSubmitInfoKHR { + VkStructureType sType; + const void* pNext; + VkCommandBuffer commandBuffer; + uint32_t deviceMask; +} VkCommandBufferSubmitInfoKHR; + +typedef struct VkSubmitInfo2KHR { + VkStructureType sType; + const void* pNext; + VkSubmitFlagsKHR flags; + uint32_t waitSemaphoreInfoCount; + const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos; + uint32_t commandBufferInfoCount; + const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos; + uint32_t signalSemaphoreInfoCount; + const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos; +} VkSubmitInfo2KHR; + +typedef struct VkPhysicalDeviceSynchronization2FeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 synchronization2; +} VkPhysicalDeviceSynchronization2FeaturesKHR; + +typedef struct VkQueueFamilyCheckpointProperties2NV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2KHR checkpointExecutionStageMask; +} VkQueueFamilyCheckpointProperties2NV; + +typedef struct VkCheckpointData2NV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags2KHR stage; + void* pCheckpointMarker; +} VkCheckpointData2NV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfoKHR* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2KHR stageMask); +typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, const VkDependencyInfoKHR* pDependencyInfos); +typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfoKHR* pDependencyInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage, VkQueryPool queryPool, uint32_t query); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2KHR* pSubmits, VkFence fence); +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointData2NV* pCheckpointData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent2KHR( + VkCommandBuffer commandBuffer, + VkEvent event, + const VkDependencyInfoKHR* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent2KHR( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags2KHR stageMask); + +VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents2KHR( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + const VkDependencyInfoKHR* pDependencyInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier2KHR( + VkCommandBuffer commandBuffer, + const VkDependencyInfoKHR* pDependencyInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp2KHR( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2KHR stage, + VkQueryPool queryPool, + uint32_t query); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit2KHR( + VkQueue queue, + uint32_t submitCount, + const VkSubmitInfo2KHR* pSubmits, + VkFence fence); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarker2AMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags2KHR stage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker); + +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointData2NV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointData2NV* pCheckpointData); +#endif + + +#define VK_KHR_zero_initialize_workgroup_memory 1 +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 shaderZeroInitializeWorkgroupMemory; +} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; + + + +#define VK_KHR_workgroup_memory_explicit_layout 1 +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME "VK_KHR_workgroup_memory_explicit_layout" +typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 workgroupMemoryExplicitLayout; + VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; + VkBool32 workgroupMemoryExplicitLayout8BitAccess; + VkBool32 workgroupMemoryExplicitLayout16BitAccess; +} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR; + + + +#define VK_KHR_copy_commands2 1 +#define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 +#define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" +typedef struct VkBufferCopy2KHR { + VkStructureType sType; + const void* pNext; + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy2KHR; + +typedef struct VkCopyBufferInfo2KHR { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferCopy2KHR* pRegions; +} VkCopyBufferInfo2KHR; + +typedef struct VkImageCopy2KHR { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy2KHR; + +typedef struct VkCopyImageInfo2KHR { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2KHR* pRegions; +} VkCopyImageInfo2KHR; + +typedef struct VkBufferImageCopy2KHR { + VkStructureType sType; + const void* pNext; + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy2KHR; + +typedef struct VkCopyBufferToImageInfo2KHR { + VkStructureType sType; + const void* pNext; + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy2KHR* pRegions; +} VkCopyBufferToImageInfo2KHR; + +typedef struct VkCopyImageToBufferInfo2KHR { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy2KHR* pRegions; +} VkCopyImageToBufferInfo2KHR; + +typedef struct VkImageBlit2KHR { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets[2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets[2]; +} VkImageBlit2KHR; + +typedef struct VkBlitImageInfo2KHR { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit2KHR* pRegions; + VkFilter filter; +} VkBlitImageInfo2KHR; + +typedef struct VkImageResolve2KHR { + VkStructureType sType; + const void* pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve2KHR; + +typedef struct VkResolveImageInfo2KHR { + VkStructureType sType; + const void* pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageResolve2KHR* pRegions; +} VkResolveImageInfo2KHR; + +typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2KHR* pCopyBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2KHR* pCopyImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2KHR* pCopyBufferToImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2KHR* pCopyImageToBufferInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2KHR* pBlitImageInfo); +typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2KHR* pResolveImageInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer2KHR( + VkCommandBuffer commandBuffer, + const VkCopyBufferInfo2KHR* pCopyBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage2KHR( + VkCommandBuffer commandBuffer, + const VkCopyImageInfo2KHR* pCopyImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage2KHR( + VkCommandBuffer commandBuffer, + const VkCopyBufferToImageInfo2KHR* pCopyBufferToImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer2KHR( + VkCommandBuffer commandBuffer, + const VkCopyImageToBufferInfo2KHR* pCopyImageToBufferInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage2KHR( + VkCommandBuffer commandBuffer, + const VkBlitImageInfo2KHR* pBlitImageInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage2KHR( + VkCommandBuffer commandBuffer, + const VkResolveImageInfo2KHR* pResolveImageInfo); +#endif + + +#define VK_EXT_debug_report 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10 +#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" + +typedef enum VkDebugReportObjectTypeEXT { + VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, + VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, + VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, + VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, + VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, + VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, + VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, + VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, + VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, + VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, + VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, + VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, + VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, + VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, + VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, + VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportObjectTypeEXT; + +typedef enum VkDebugReportFlagBitsEXT { + VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, + VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, + VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugReportFlagBitsEXT; +typedef VkFlags VkDebugReportFlagsEXT; +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void* pUserData; +} VkDebugReportCallbackCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( + VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugReportCallbackEXT* pCallback); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( + VkInstance instance, + VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( + VkInstance instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage); +#endif + + +#define VK_NV_glsl_shader 1 +#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" + + +#define VK_EXT_depth_range_unrestricted 1 +#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 +#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" + + +#define VK_IMG_filter_cubic 1 +#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 +#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" + + +#define VK_AMD_rasterization_order 1 +#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 +#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" + +typedef enum VkRasterizationOrderAMD { + VK_RASTERIZATION_ORDER_STRICT_AMD = 0, + VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, + VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF +} VkRasterizationOrderAMD; +typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { + VkStructureType sType; + const void* pNext; + VkRasterizationOrderAMD rasterizationOrder; +} VkPipelineRasterizationStateRasterizationOrderAMD; + + + +#define VK_AMD_shader_trinary_minmax 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 +#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" + + +#define VK_AMD_shader_explicit_vertex_parameter 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 +#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" + + +#define VK_EXT_debug_marker 1 +#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 +#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" +typedef struct VkDebugMarkerObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + const char* pObjectName; +} VkDebugMarkerObjectNameInfoEXT; + +typedef struct VkDebugMarkerObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugReportObjectTypeEXT objectType; + uint64_t object; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugMarkerObjectTagInfoEXT; + +typedef struct VkDebugMarkerMarkerInfoEXT { + VkStructureType sType; + const void* pNext; + const char* pMarkerName; + float color[4]; +} VkDebugMarkerMarkerInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo); +typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( + VkDevice device, + const VkDebugMarkerObjectTagInfoEXT* pTagInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( + VkDevice device, + const VkDebugMarkerObjectNameInfoEXT* pNameInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( + VkCommandBuffer commandBuffer, + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( + VkCommandBuffer commandBuffer, + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); +#endif + + +#define VK_AMD_gcn_shader 1 +#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 +#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" + + +#define VK_NV_dedicated_allocation 1 +#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" +typedef struct VkDedicatedAllocationImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationImageCreateInfoNV; + +typedef struct VkDedicatedAllocationBufferCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationBufferCreateInfoNV; + +typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkImage image; + VkBuffer buffer; +} VkDedicatedAllocationMemoryAllocateInfoNV; + + + +#define VK_EXT_transform_feedback 1 +#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes); +typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( + VkCommandBuffer commandBuffer, + uint32_t instanceCount, + uint32_t firstInstance, + VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, + uint32_t counterOffset, + uint32_t vertexStride); +#endif + + +#define VK_NVX_image_view_handle 1 +#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 2 +#define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" +typedef struct VkImageViewHandleInfoNVX { + VkStructureType sType; + const void* pNext; + VkImageView imageView; + VkDescriptorType descriptorType; + VkSampler sampler; +} VkImageViewHandleInfoNVX; + +typedef struct VkImageViewAddressPropertiesNVX { + VkStructureType sType; + void* pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; +} VkImageViewAddressPropertiesNVX; + +typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR uint32_t VKAPI_CALL vkGetImageViewHandleNVX( + VkDevice device, + const VkImageViewHandleInfoNVX* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageViewAddressNVX( + VkDevice device, + VkImageView imageView, + VkImageViewAddressPropertiesNVX* pProperties); +#endif + + +#define VK_AMD_draw_indirect_count 1 +#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 2 +#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + + +#define VK_AMD_negative_viewport_height 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 +#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" + + +#define VK_AMD_gpu_shader_half_float 1 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 2 +#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" + + +#define VK_AMD_shader_ballot 1 +#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 +#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" + + +#define VK_AMD_texture_gather_bias_lod 1 +#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 +#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" +typedef struct VkTextureLODGatherFormatPropertiesAMD { + VkStructureType sType; + void* pNext; + VkBool32 supportsTextureGatherLODBiasAMD; +} VkTextureLODGatherFormatPropertiesAMD; + + + +#define VK_AMD_shader_info 1 +#define VK_AMD_SHADER_INFO_SPEC_VERSION 1 +#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" + +typedef enum VkShaderInfoTypeAMD { + VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, + VK_SHADER_INFO_TYPE_BINARY_AMD = 1, + VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, + VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkShaderInfoTypeAMD; +typedef struct VkShaderResourceUsageAMD { + uint32_t numUsedVgprs; + uint32_t numUsedSgprs; + uint32_t ldsSizePerLocalWorkGroup; + size_t ldsUsageSizeInBytes; + size_t scratchMemUsageInBytes; +} VkShaderResourceUsageAMD; + +typedef struct VkShaderStatisticsInfoAMD { + VkShaderStageFlags shaderStageMask; + VkShaderResourceUsageAMD resourceUsage; + uint32_t numPhysicalVgprs; + uint32_t numPhysicalSgprs; + uint32_t numAvailableVgprs; + uint32_t numAvailableSgprs; + uint32_t computeWorkGroupSize[3]; +} VkShaderStatisticsInfoAMD; + +typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD( + VkDevice device, + VkPipeline pipeline, + VkShaderStageFlagBits shaderStage, + VkShaderInfoTypeAMD infoType, + size_t* pInfoSize, + void* pInfo); +#endif + + +#define VK_AMD_shader_image_load_store_lod 1 +#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 +#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" + + +#define VK_NV_corner_sampled_image 1 +#define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 +#define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" +typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cornerSampledImage; +} VkPhysicalDeviceCornerSampledImageFeaturesNV; + + + +#define VK_IMG_format_pvrtc 1 +#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 +#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" + + +#define VK_NV_external_memory_capabilities 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" + +typedef enum VkExternalMemoryHandleTypeFlagBitsNV { + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryHandleTypeFlagBitsNV; +typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; + +typedef enum VkExternalMemoryFeatureFlagBitsNV { + VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkExternalMemoryFeatureFlagBitsNV; +typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef struct VkExternalImageFormatPropertiesNV { + VkImageFormatProperties imageFormatProperties; + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; +} VkExternalImageFormatPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkExternalMemoryHandleTypeFlagsNV externalHandleType, + VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); +#endif + + +#define VK_NV_external_memory 1 +#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" +typedef struct VkExternalMemoryImageCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExternalMemoryImageCreateInfoNV; + +typedef struct VkExportMemoryAllocateInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExportMemoryAllocateInfoNV; + + + +#define VK_EXT_validation_flags 1 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2 +#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" + +typedef enum VkValidationCheckEXT { + VK_VALIDATION_CHECK_ALL_EXT = 0, + VK_VALIDATION_CHECK_SHADERS_EXT = 1, + VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCheckEXT; +typedef struct VkValidationFlagsEXT { + VkStructureType sType; + const void* pNext; + uint32_t disabledValidationCheckCount; + const VkValidationCheckEXT* pDisabledValidationChecks; +} VkValidationFlagsEXT; + + + +#define VK_EXT_shader_subgroup_ballot 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" + + +#define VK_EXT_shader_subgroup_vote 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 +#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" + + +#define VK_EXT_texture_compression_astc_hdr 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION 1 +#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 textureCompressionASTC_HDR; +} VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; + + + +#define VK_EXT_astc_decode_mode 1 +#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 +#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" +typedef struct VkImageViewASTCDecodeModeEXT { + VkStructureType sType; + const void* pNext; + VkFormat decodeMode; +} VkImageViewASTCDecodeModeEXT; + +typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 decodeModeSharedExponent; +} VkPhysicalDeviceASTCDecodeFeaturesEXT; + + + +#define VK_EXT_conditional_rendering 1 +#define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2 +#define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" + +typedef enum VkConditionalRenderingFlagBitsEXT { + VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, + VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConditionalRenderingFlagBitsEXT; +typedef VkFlags VkConditionalRenderingFlagsEXT; +typedef struct VkConditionalRenderingBeginInfoEXT { + VkStructureType sType; + const void* pNext; + VkBuffer buffer; + VkDeviceSize offset; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfoEXT; + +typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 conditionalRendering; + VkBool32 inheritedConditionalRendering; +} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + +typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 conditionalRenderingEnable; +} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); +typedef void (VKAPI_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBeginConditionalRenderingEXT( + VkCommandBuffer commandBuffer, + const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndConditionalRenderingEXT( + VkCommandBuffer commandBuffer); +#endif + + +#define VK_NV_clip_space_w_scaling 1 +#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 +#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" +typedef struct VkViewportWScalingNV { + float xcoeff; + float ycoeff; +} VkViewportWScalingNV; + +typedef struct VkPipelineViewportWScalingStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 viewportWScalingEnable; + uint32_t viewportCount; + const VkViewportWScalingNV* pViewportWScalings; +} VkPipelineViewportWScalingStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewportWScalingNV* pViewportWScalings); +#endif + + +#define VK_EXT_direct_mode_display 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 +#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" +typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); +#endif + + +#define VK_EXT_display_surface_counter 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" + +typedef enum VkSurfaceCounterFlagBitsEXT { + VK_SURFACE_COUNTER_VBLANK_BIT_EXT = 0x00000001, + VK_SURFACE_COUNTER_VBLANK_EXT = VK_SURFACE_COUNTER_VBLANK_BIT_EXT, + VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSurfaceCounterFlagBitsEXT; +typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef struct VkSurfaceCapabilities2EXT { + VkStructureType sType; + void* pNext; + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; + VkSurfaceCounterFlagsEXT supportedSurfaceCounters; +} VkSurfaceCapabilities2EXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT* pSurfaceCapabilities); +#endif + + +#define VK_EXT_display_control 1 +#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" + +typedef enum VkDisplayPowerStateEXT { + VK_DISPLAY_POWER_STATE_OFF_EXT = 0, + VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, + VK_DISPLAY_POWER_STATE_ON_EXT = 2, + VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayPowerStateEXT; + +typedef enum VkDeviceEventTypeEXT { + VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, + VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceEventTypeEXT; + +typedef enum VkDisplayEventTypeEXT { + VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, + VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDisplayEventTypeEXT; +typedef struct VkDisplayPowerInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayPowerStateEXT powerState; +} VkDisplayPowerInfoEXT; + +typedef struct VkDeviceEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceEventTypeEXT deviceEvent; +} VkDeviceEventInfoEXT; + +typedef struct VkDisplayEventInfoEXT { + VkStructureType sType; + const void* pNext; + VkDisplayEventTypeEXT displayEvent; +} VkDisplayEventInfoEXT; + +typedef struct VkSwapchainCounterCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkSurfaceCounterFlagsEXT surfaceCounters; +} VkSwapchainCounterCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); +typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT* pDisplayPowerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( + VkDevice device, + const VkDeviceEventInfoEXT* pDeviceEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( + VkDevice device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT* pDisplayEventInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( + VkDevice device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT counter, + uint64_t* pCounterValue); +#endif + + +#define VK_GOOGLE_display_timing 1 +#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 +#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing" +typedef struct VkRefreshCycleDurationGOOGLE { + uint64_t refreshDuration; +} VkRefreshCycleDurationGOOGLE; + +typedef struct VkPastPresentationTimingGOOGLE { + uint32_t presentID; + uint64_t desiredPresentTime; + uint64_t actualPresentTime; + uint64_t earliestPresentTime; + uint64_t presentMargin; +} VkPastPresentationTimingGOOGLE; + +typedef struct VkPresentTimeGOOGLE { + uint32_t presentID; + uint64_t desiredPresentTime; +} VkPresentTimeGOOGLE; + +typedef struct VkPresentTimesInfoGOOGLE { + VkStructureType sType; + const void* pNext; + uint32_t swapchainCount; + const VkPresentTimeGOOGLE* pTimes; +} VkPresentTimesInfoGOOGLE; + +typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE( + VkDevice device, + VkSwapchainKHR swapchain, + VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pPresentationTimingCount, + VkPastPresentationTimingGOOGLE* pPresentationTimings); +#endif + + +#define VK_NV_sample_mask_override_coverage 1 +#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 +#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" + + +#define VK_NV_geometry_shader_passthrough 1 +#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 +#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" + + +#define VK_NV_viewport_array2 1 +#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" + + +#define VK_NVX_multiview_per_view_attributes 1 +#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 +#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" +typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { + VkStructureType sType; + void* pNext; + VkBool32 perViewPositionAllComponents; +} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + + + +#define VK_NV_viewport_swizzle 1 +#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" + +typedef enum VkViewportCoordinateSwizzleNV { + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, + VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, + VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF +} VkViewportCoordinateSwizzleNV; +typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef struct VkViewportSwizzleNV { + VkViewportCoordinateSwizzleNV x; + VkViewportCoordinateSwizzleNV y; + VkViewportCoordinateSwizzleNV z; + VkViewportCoordinateSwizzleNV w; +} VkViewportSwizzleNV; + +typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineViewportSwizzleStateCreateFlagsNV flags; + uint32_t viewportCount; + const VkViewportSwizzleNV* pViewportSwizzles; +} VkPipelineViewportSwizzleStateCreateInfoNV; + + + +#define VK_EXT_discard_rectangles 1 +#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 +#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" + +typedef enum VkDiscardRectangleModeEXT { + VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, + VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, + VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDiscardRectangleModeEXT; +typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxDiscardRectangles; +} VkPhysicalDeviceDiscardRectanglePropertiesEXT; + +typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineDiscardRectangleStateCreateFlagsEXT flags; + VkDiscardRectangleModeEXT discardRectangleMode; + uint32_t discardRectangleCount; + const VkRect2D* pDiscardRectangles; +} VkPipelineDiscardRectangleStateCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( + VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, + uint32_t discardRectangleCount, + const VkRect2D* pDiscardRectangles); +#endif + + +#define VK_EXT_conservative_rasterization 1 +#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" + +typedef enum VkConservativeRasterizationModeEXT { + VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, + VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, + VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, + VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkConservativeRasterizationModeEXT; +typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { + VkStructureType sType; + void* pNext; + float primitiveOverestimationSize; + float maxExtraPrimitiveOverestimationSize; + float extraPrimitiveOverestimationSizeGranularity; + VkBool32 primitiveUnderestimation; + VkBool32 conservativePointAndLineRasterization; + VkBool32 degenerateTrianglesRasterized; + VkBool32 degenerateLinesRasterized; + VkBool32 fullyCoveredFragmentShaderInputVariable; + VkBool32 conservativeRasterizationPostDepthCoverage; +} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + +typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; + VkConservativeRasterizationModeEXT conservativeRasterizationMode; + float extraPrimitiveOverestimationSize; +} VkPipelineRasterizationConservativeStateCreateInfoEXT; + + + +#define VK_EXT_depth_clip_enable 1 +#define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" +typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 depthClipEnable; +} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + +typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; + VkBool32 depthClipEnable; +} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + + + +#define VK_EXT_swapchain_colorspace 1 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 4 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" + + +#define VK_EXT_hdr_metadata 1 +#define VK_EXT_HDR_METADATA_SPEC_VERSION 2 +#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" +typedef struct VkXYColorEXT { + float x; + float y; +} VkXYColorEXT; + +typedef struct VkHdrMetadataEXT { + VkStructureType sType; + const void* pNext; + VkXYColorEXT displayPrimaryRed; + VkXYColorEXT displayPrimaryGreen; + VkXYColorEXT displayPrimaryBlue; + VkXYColorEXT whitePoint; + float maxLuminance; + float minLuminance; + float maxContentLightLevel; + float maxFrameAverageLightLevel; +} VkHdrMetadataEXT; + +typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( + VkDevice device, + uint32_t swapchainCount, + const VkSwapchainKHR* pSwapchains, + const VkHdrMetadataEXT* pMetadata); +#endif + + +#define VK_EXT_external_memory_dma_buf 1 +#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" + + +#define VK_EXT_queue_family_foreign 1 +#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 +#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" +#define VK_QUEUE_FAMILY_FOREIGN_EXT (~2U) + + +#define VK_EXT_debug_utils 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) +#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 +#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" +typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; + +typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugUtilsMessageSeverityFlagBitsEXT; + +typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, + VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDebugUtilsMessageTypeFlagBitsEXT; +typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +typedef struct VkDebugUtilsLabelEXT { + VkStructureType sType; + const void* pNext; + const char* pLabelName; + float color[4]; +} VkDebugUtilsLabelEXT; + +typedef struct VkDebugUtilsObjectNameInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + const char* pObjectName; +} VkDebugUtilsObjectNameInfoEXT; + +typedef struct VkDebugUtilsMessengerCallbackDataEXT { + VkStructureType sType; + const void* pNext; + VkDebugUtilsMessengerCallbackDataFlagsEXT flags; + const char* pMessageIdName; + int32_t messageIdNumber; + const char* pMessage; + uint32_t queueLabelCount; + const VkDebugUtilsLabelEXT* pQueueLabels; + uint32_t cmdBufLabelCount; + const VkDebugUtilsLabelEXT* pCmdBufLabels; + uint32_t objectCount; + const VkDebugUtilsObjectNameInfoEXT* pObjects; +} VkDebugUtilsMessengerCallbackDataEXT; + +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); + +typedef struct VkDebugUtilsMessengerCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDebugUtilsMessengerCreateFlagsEXT flags; + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; + VkDebugUtilsMessageTypeFlagsEXT messageType; + PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; + void* pUserData; +} VkDebugUtilsMessengerCreateInfoEXT; + +typedef struct VkDebugUtilsObjectTagInfoEXT { + VkStructureType sType; + const void* pNext; + VkObjectType objectType; + uint64_t objectHandle; + uint64_t tagName; + size_t tagSize; + const void* pTag; +} VkDebugUtilsObjectTagInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo); +typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT* pTagInfo); +typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); +typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); +typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger); +typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT( + VkDevice device, + const VkDebugUtilsObjectNameInfoEXT* pNameInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT( + VkDevice device, + const VkDebugUtilsObjectTagInfoEXT* pTagInfo); + +VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT( + VkQueue queue, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT( + VkQueue queue); + +VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT( + VkQueue queue, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer); + +VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT( + VkCommandBuffer commandBuffer, + const VkDebugUtilsLabelEXT* pLabelInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pMessenger); + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( + VkInstance instance, + VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( + VkInstance instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); +#endif + + +#define VK_EXT_sampler_filter_minmax 1 +#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 2 +#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" +typedef VkSamplerReductionMode VkSamplerReductionModeEXT; + +typedef VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; + +typedef VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; + + + +#define VK_AMD_gpu_shader_int16 1 +#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 2 +#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" + + +#define VK_AMD_mixed_attachment_samples 1 +#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 +#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" + + +#define VK_AMD_shader_fragment_mask 1 +#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 +#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" + + +#define VK_EXT_inline_uniform_block 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 +#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" +typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + +typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; +} VkPhysicalDeviceInlineUniformBlockPropertiesEXT; + +typedef struct VkWriteDescriptorSetInlineUniformBlockEXT { + VkStructureType sType; + const void* pNext; + uint32_t dataSize; + const void* pData; +} VkWriteDescriptorSetInlineUniformBlockEXT; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfoEXT; + + + +#define VK_EXT_shader_stencil_export 1 +#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 +#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" + + +#define VK_EXT_sample_locations 1 +#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 +#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" +typedef struct VkSampleLocationEXT { + float x; + float y; +} VkSampleLocationEXT; + +typedef struct VkSampleLocationsInfoEXT { + VkStructureType sType; + const void* pNext; + VkSampleCountFlagBits sampleLocationsPerPixel; + VkExtent2D sampleLocationGridSize; + uint32_t sampleLocationsCount; + const VkSampleLocationEXT* pSampleLocations; +} VkSampleLocationsInfoEXT; + +typedef struct VkAttachmentSampleLocationsEXT { + uint32_t attachmentIndex; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkAttachmentSampleLocationsEXT; + +typedef struct VkSubpassSampleLocationsEXT { + uint32_t subpassIndex; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkSubpassSampleLocationsEXT; + +typedef struct VkRenderPassSampleLocationsBeginInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t attachmentInitialSampleLocationsCount; + const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations; + uint32_t postSubpassSampleLocationsCount; + const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations; +} VkRenderPassSampleLocationsBeginInfoEXT; + +typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 sampleLocationsEnable; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkPipelineSampleLocationsStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { + VkStructureType sType; + void* pNext; + VkSampleCountFlags sampleLocationSampleCounts; + VkExtent2D maxSampleLocationGridSize; + float sampleLocationCoordinateRange[2]; + uint32_t sampleLocationSubPixelBits; + VkBool32 variableSampleLocations; +} VkPhysicalDeviceSampleLocationsPropertiesEXT; + +typedef struct VkMultisamplePropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D maxSampleLocationGridSize; +} VkMultisamplePropertiesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo); +typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT( + VkCommandBuffer commandBuffer, + const VkSampleLocationsInfoEXT* pSampleLocationsInfo); + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT( + VkPhysicalDevice physicalDevice, + VkSampleCountFlagBits samples, + VkMultisamplePropertiesEXT* pMultisampleProperties); +#endif + + +#define VK_EXT_blend_operation_advanced 1 +#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 +#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" + +typedef enum VkBlendOverlapEXT { + VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, + VK_BLEND_OVERLAP_DISJOINT_EXT = 1, + VK_BLEND_OVERLAP_CONJOINT_EXT = 2, + VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBlendOverlapEXT; +typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 advancedBlendCoherentOperations; +} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t advancedBlendMaxColorAttachments; + VkBool32 advancedBlendIndependentBlend; + VkBool32 advancedBlendNonPremultipliedSrcColor; + VkBool32 advancedBlendNonPremultipliedDstColor; + VkBool32 advancedBlendCorrelatedOverlap; + VkBool32 advancedBlendAllOperations; +} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + +typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; +} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + + + +#define VK_NV_fragment_coverage_to_color 1 +#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" +typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +typedef struct VkPipelineCoverageToColorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageToColorStateCreateFlagsNV flags; + VkBool32 coverageToColorEnable; + uint32_t coverageToColorLocation; +} VkPipelineCoverageToColorStateCreateInfoNV; + + + +#define VK_NV_framebuffer_mixed_samples 1 +#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 +#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" + +typedef enum VkCoverageModulationModeNV { + VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, + VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, + VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, + VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, + VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoverageModulationModeNV; +typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +typedef struct VkPipelineCoverageModulationStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageModulationStateCreateFlagsNV flags; + VkCoverageModulationModeNV coverageModulationMode; + VkBool32 coverageModulationTableEnable; + uint32_t coverageModulationTableCount; + const float* pCoverageModulationTable; +} VkPipelineCoverageModulationStateCreateInfoNV; + + + +#define VK_NV_fill_rectangle 1 +#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 +#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" + + +#define VK_NV_shader_sm_builtins 1 +#define VK_NV_SHADER_SM_BUILTINS_SPEC_VERSION 1 +#define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" +typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderSMCount; + uint32_t shaderWarpsPerSM; +} VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; + +typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shaderSMBuiltins; +} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; + + + +#define VK_EXT_post_depth_coverage 1 +#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 +#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" + + +#define VK_EXT_image_drm_format_modifier 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierPropertiesListEXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesListEXT; + +typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkPhysicalDeviceImageDrmFormatModifierInfoEXT; + +typedef struct VkImageDrmFormatModifierListCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t drmFormatModifierCount; + const uint64_t* pDrmFormatModifiers; +} VkImageDrmFormatModifierListCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout* pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t drmFormatModifier; +} VkImageDrmFormatModifierPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT( + VkDevice device, + VkImage image, + VkImageDrmFormatModifierPropertiesEXT* pProperties); +#endif + + +#define VK_EXT_validation_cache 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) +#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 +#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" + +typedef enum VkValidationCacheHeaderVersionEXT { + VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, + VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationCacheHeaderVersionEXT; +typedef VkFlags VkValidationCacheCreateFlagsEXT; +typedef struct VkValidationCacheCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkValidationCacheCreateFlagsEXT flags; + size_t initialDataSize; + const void* pInitialData; +} VkValidationCacheCreateInfoEXT; + +typedef struct VkShaderModuleValidationCacheCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkValidationCacheEXT validationCache; +} VkShaderModuleValidationCacheCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache); +typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches); +typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT( + VkDevice device, + const VkValidationCacheCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkValidationCacheEXT* pValidationCache); + +VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT( + VkDevice device, + VkValidationCacheEXT validationCache, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT( + VkDevice device, + VkValidationCacheEXT dstCache, + uint32_t srcCacheCount, + const VkValidationCacheEXT* pSrcCaches); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( + VkDevice device, + VkValidationCacheEXT validationCache, + size_t* pDataSize, + void* pData); +#endif + + +#define VK_EXT_descriptor_indexing 1 +#define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 +#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" +typedef VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; + +typedef VkDescriptorBindingFlags VkDescriptorBindingFlagsEXT; + +typedef VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; + +typedef VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; + +typedef VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; + +typedef VkDescriptorSetVariableDescriptorCountAllocateInfo VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; + +typedef VkDescriptorSetVariableDescriptorCountLayoutSupport VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; + + + +#define VK_EXT_shader_viewport_index_layer 1 +#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 +#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" + + +#define VK_NV_shading_rate_image 1 +#define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 +#define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" + +typedef enum VkShadingRatePaletteEntryNV { + VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, + VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, + VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, + VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, + VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, + VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF +} VkShadingRatePaletteEntryNV; + +typedef enum VkCoarseSampleOrderTypeNV { + VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, + VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, + VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, + VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, + VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoarseSampleOrderTypeNV; +typedef struct VkShadingRatePaletteNV { + uint32_t shadingRatePaletteEntryCount; + const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries; +} VkShadingRatePaletteNV; + +typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 shadingRateImageEnable; + uint32_t viewportCount; + const VkShadingRatePaletteNV* pShadingRatePalettes; +} VkPipelineViewportShadingRateImageStateCreateInfoNV; + +typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 shadingRateImage; + VkBool32 shadingRateCoarseSampleOrder; +} VkPhysicalDeviceShadingRateImageFeaturesNV; + +typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { + VkStructureType sType; + void* pNext; + VkExtent2D shadingRateTexelSize; + uint32_t shadingRatePaletteSize; + uint32_t shadingRateMaxCoarseSamples; +} VkPhysicalDeviceShadingRateImagePropertiesNV; + +typedef struct VkCoarseSampleLocationNV { + uint32_t pixelX; + uint32_t pixelY; + uint32_t sample; +} VkCoarseSampleLocationNV; + +typedef struct VkCoarseSampleOrderCustomNV { + VkShadingRatePaletteEntryNV shadingRate; + uint32_t sampleCount; + uint32_t sampleLocationCount; + const VkCoarseSampleLocationNV* pSampleLocations; +} VkCoarseSampleOrderCustomNV; + +typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkCoarseSampleOrderTypeNV sampleOrderType; + uint32_t customSampleOrderCount; + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders; +} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV* pShadingRatePalettes); +typedef void (VKAPI_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindShadingRateImageNV( + VkCommandBuffer commandBuffer, + VkImageView imageView, + VkImageLayout imageLayout); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportShadingRatePaletteNV( + VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkShadingRatePaletteNV* pShadingRatePalettes); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( + VkCommandBuffer commandBuffer, + VkCoarseSampleOrderTypeNV sampleOrderType, + uint32_t customSampleOrderCount, + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); +#endif + + +#define VK_NV_ray_tracing 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) +#define VK_NV_RAY_TRACING_SPEC_VERSION 3 +#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_SHADER_UNUSED_KHR (~0U) +#define VK_SHADER_UNUSED_NV VK_SHADER_UNUSED_KHR + +typedef enum VkRayTracingShaderGroupTypeKHR { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkRayTracingShaderGroupTypeKHR; +typedef VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; + + +typedef enum VkGeometryTypeKHR { + VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, + VK_GEOMETRY_TYPE_AABBS_KHR = 1, + VK_GEOMETRY_TYPE_INSTANCES_KHR = 2, + VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, + VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, + VK_GEOMETRY_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryTypeKHR; +typedef VkGeometryTypeKHR VkGeometryTypeNV; + + +typedef enum VkAccelerationStructureTypeKHR { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, + VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR = 2, + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureTypeKHR; +typedef VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; + + +typedef enum VkCopyAccelerationStructureModeKHR { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, + VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, + VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkCopyAccelerationStructureModeKHR; +typedef VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; + + +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; + +typedef enum VkGeometryFlagBitsKHR { + VK_GEOMETRY_OPAQUE_BIT_KHR = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 0x00000002, + VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryFlagBitsKHR; +typedef VkFlags VkGeometryFlagsKHR; +typedef VkGeometryFlagsKHR VkGeometryFlagsNV; + +typedef VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; + + +typedef enum VkGeometryInstanceFlagBitsKHR { + VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 0x00000008, + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkGeometryInstanceFlagBitsKHR; +typedef VkFlags VkGeometryInstanceFlagsKHR; +typedef VkGeometryInstanceFlagsKHR VkGeometryInstanceFlagsNV; + +typedef VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; + + +typedef enum VkBuildAccelerationStructureFlagBitsKHR { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR = 0x00000010, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureFlagBitsKHR; +typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +typedef VkBuildAccelerationStructureFlagsKHR VkBuildAccelerationStructureFlagsNV; + +typedef VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; + +typedef struct VkRayTracingShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; +} VkRayTracingShaderGroupCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV* pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkGeometryTrianglesNV { + VkStructureType sType; + const void* pNext; + VkBuffer vertexData; + VkDeviceSize vertexOffset; + uint32_t vertexCount; + VkDeviceSize vertexStride; + VkFormat vertexFormat; + VkBuffer indexData; + VkDeviceSize indexOffset; + uint32_t indexCount; + VkIndexType indexType; + VkBuffer transformData; + VkDeviceSize transformOffset; +} VkGeometryTrianglesNV; + +typedef struct VkGeometryAABBNV { + VkStructureType sType; + const void* pNext; + VkBuffer aabbData; + uint32_t numAABBs; + uint32_t stride; + VkDeviceSize offset; +} VkGeometryAABBNV; + +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; + +typedef struct VkGeometryNV { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsKHR flags; +} VkGeometryNV; + +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsNV flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV* pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; + +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkWriteDescriptorSetAccelerationStructureNV { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; + +typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureMemoryRequirementsTypeNV type; + VkAccelerationStructureNV accelerationStructure; +} VkAccelerationStructureMemoryRequirementsInfoNV; + +typedef struct VkPhysicalDeviceRayTracingPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxTriangleCount; + uint32_t maxDescriptorSetAccelerationStructures; +} VkPhysicalDeviceRayTracingPropertiesNV; + +typedef struct VkTransformMatrixKHR { + float matrix[3][4]; +} VkTransformMatrixKHR; + +typedef VkTransformMatrixKHR VkTransformMatrixNV; + +typedef struct VkAabbPositionsKHR { + float minX; + float minY; + float minZ; + float maxX; + float maxY; + float maxZ; +} VkAabbPositionsKHR; + +typedef VkAabbPositionsKHR VkAabbPositionsNV; + +typedef struct VkAccelerationStructureInstanceKHR { + VkTransformMatrixKHR transform; + uint32_t instanceCustomIndex:24; + uint32_t mask:8; + uint32_t instanceShaderBindingTableRecordOffset:24; + VkGeometryInstanceFlagsKHR flags:8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureInstanceKHR; + +typedef VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( + VkDevice device, + const VkAccelerationStructureCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureNV* pAccelerationStructure); + +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( + VkDevice device, + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2KHR* pMemoryRequirements); + +VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( + VkDevice device, + uint32_t bindInfoCount, + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( + VkCommandBuffer commandBuffer, + const VkAccelerationStructureInfoNV* pInfo, + VkBuffer instanceData, + VkDeviceSize instanceOffset, + VkBool32 update, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkBuffer scratch, + VkDeviceSize scratchOffset); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( + VkCommandBuffer commandBuffer, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkCopyAccelerationStructureModeKHR mode); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( + VkCommandBuffer commandBuffer, + VkBuffer raygenShaderBindingTableBuffer, + VkDeviceSize raygenShaderBindingOffset, + VkBuffer missShaderBindingTableBuffer, + VkDeviceSize missShaderBindingOffset, + VkDeviceSize missShaderBindingStride, + VkBuffer hitShaderBindingTableBuffer, + VkDeviceSize hitShaderBindingOffset, + VkDeviceSize hitShaderBindingStride, + VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, + VkDeviceSize callableShaderBindingStride, + uint32_t width, + uint32_t height, + uint32_t depth); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( + VkDevice device, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoNV* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( + VkDevice device, + VkAccelerationStructureNV accelerationStructure, + size_t dataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureNV* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + +VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV( + VkDevice device, + VkPipeline pipeline, + uint32_t shader); +#endif + + +#define VK_NV_representative_fragment_test 1 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 2 +#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" +typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 representativeFragmentTest; +} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; + +typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 representativeFragmentTestEnable; +} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + + + +#define VK_EXT_filter_cubic 1 +#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 +#define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" +typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT { + VkStructureType sType; + void* pNext; + VkImageViewType imageViewType; +} VkPhysicalDeviceImageViewImageFormatInfoEXT; + +typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 filterCubic; + VkBool32 filterCubicMinmax; +} VkFilterCubicImageViewImageFormatPropertiesEXT; + + + +#define VK_QCOM_render_pass_shader_resolve 1 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 +#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" + + +#define VK_EXT_global_priority 1 +#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 +#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" + +typedef enum VkQueueGlobalPriorityEXT { + VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT = 0x7FFFFFFF +} VkQueueGlobalPriorityEXT; +typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkQueueGlobalPriorityEXT globalPriority; +} VkDeviceQueueGlobalPriorityCreateInfoEXT; + + + +#define VK_EXT_external_memory_host 1 +#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" +typedef struct VkImportMemoryHostPointerInfoEXT { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + void* pHostPointer; +} VkImportMemoryHostPointerInfoEXT; + +typedef struct VkMemoryHostPointerPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryHostPointerPropertiesEXT; + +typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize minImportedHostPointerAlignment; +} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + const void* pHostPointer, + VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); +#endif + + +#define VK_AMD_buffer_marker 1 +#define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 +#define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" +typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker); +#endif + + +#define VK_AMD_pipeline_compiler_control 1 +#define VK_AMD_PIPELINE_COMPILER_CONTROL_SPEC_VERSION 1 +#define VK_AMD_PIPELINE_COMPILER_CONTROL_EXTENSION_NAME "VK_AMD_pipeline_compiler_control" + +typedef enum VkPipelineCompilerControlFlagBitsAMD { + VK_PIPELINE_COMPILER_CONTROL_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkPipelineCompilerControlFlagBitsAMD; +typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef struct VkPipelineCompilerControlCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkPipelineCompilerControlFlagsAMD compilerControlFlags; +} VkPipelineCompilerControlCreateInfoAMD; + + + +#define VK_EXT_calibrated_timestamps 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 +#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" + +typedef enum VkTimeDomainEXT { + VK_TIME_DOMAIN_DEVICE_EXT = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, + VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} VkTimeDomainEXT; +typedef struct VkCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkTimeDomainEXT timeDomain; +} VkCalibratedTimestampInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainEXT* pTimeDomains); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif + + +#define VK_AMD_shader_core_properties 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 2 +#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" +typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { + VkStructureType sType; + void* pNext; + uint32_t shaderEngineCount; + uint32_t shaderArraysPerEngineCount; + uint32_t computeUnitsPerShaderArray; + uint32_t simdPerComputeUnit; + uint32_t wavefrontsPerSimd; + uint32_t wavefrontSize; + uint32_t sgprsPerSimd; + uint32_t minSgprAllocation; + uint32_t maxSgprAllocation; + uint32_t sgprAllocationGranularity; + uint32_t vgprsPerSimd; + uint32_t minVgprAllocation; + uint32_t maxVgprAllocation; + uint32_t vgprAllocationGranularity; +} VkPhysicalDeviceShaderCorePropertiesAMD; + + + +#define VK_AMD_memory_overallocation_behavior 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" + +typedef enum VkMemoryOverallocationBehaviorAMD { + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF +} VkMemoryOverallocationBehaviorAMD; +typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkMemoryOverallocationBehaviorAMD overallocationBehavior; +} VkDeviceMemoryOverallocationCreateInfoAMD; + + + +#define VK_EXT_vertex_attribute_divisor 1 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 +#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" +typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxVertexAttribDivisor; +} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; + +typedef struct VkVertexInputBindingDivisorDescriptionEXT { + uint32_t binding; + uint32_t divisor; +} VkVertexInputBindingDivisorDescriptionEXT; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t vertexBindingDivisorCount; + const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors; +} VkPipelineVertexInputDivisorStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + + + +#define VK_EXT_pipeline_creation_feedback 1 +#define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" + +typedef enum VkPipelineCreationFeedbackFlagBitsEXT { + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = 0x00000001, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = 0x00000002, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = 0x00000004, + VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPipelineCreationFeedbackFlagBitsEXT; +typedef VkFlags VkPipelineCreationFeedbackFlagsEXT; +typedef struct VkPipelineCreationFeedbackEXT { + VkPipelineCreationFeedbackFlagsEXT flags; + uint64_t duration; +} VkPipelineCreationFeedbackEXT; + +typedef struct VkPipelineCreationFeedbackCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineCreationFeedbackEXT* pPipelineCreationFeedback; + uint32_t pipelineStageCreationFeedbackCount; + VkPipelineCreationFeedbackEXT* pPipelineStageCreationFeedbacks; +} VkPipelineCreationFeedbackCreateInfoEXT; + + + +#define VK_NV_shader_subgroup_partitioned 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 +#define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" + + +#define VK_NV_compute_shader_derivatives 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 computeDerivativeGroupQuads; + VkBool32 computeDerivativeGroupLinear; +} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + + + +#define VK_NV_mesh_shader 1 +#define VK_NV_MESH_SHADER_SPEC_VERSION 1 +#define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" +typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 taskShader; + VkBool32 meshShader; +} VkPhysicalDeviceMeshShaderFeaturesNV; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxDrawMeshTasksCount; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize[3]; + uint32_t maxTaskTotalMemorySize; + uint32_t maxTaskOutputCount; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize[3]; + uint32_t maxMeshTotalMemorySize; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; +} VkPhysicalDeviceMeshShaderPropertiesNV; + +typedef struct VkDrawMeshTasksIndirectCommandNV { + uint32_t taskCount; + uint32_t firstTask; +} VkDrawMeshTasksIndirectCommandNV; + +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksNV( + VkCommandBuffer commandBuffer, + uint32_t taskCount, + uint32_t firstTask); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountNV( + VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride); +#endif + + +#define VK_NV_fragment_shader_barycentric 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderBarycentric; +} VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + + + +#define VK_NV_shader_image_footprint 1 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 2 +#define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" +typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 imageFootprint; +} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + + + +#define VK_NV_scissor_exclusive 1 +#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 +#define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" +typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t exclusiveScissorCount; + const VkRect2D* pExclusiveScissors; +} VkPipelineViewportExclusiveScissorStateCreateInfoNV; + +typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 exclusiveScissor; +} VkPhysicalDeviceExclusiveScissorFeaturesNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D* pExclusiveScissors); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetExclusiveScissorNV( + VkCommandBuffer commandBuffer, + uint32_t firstExclusiveScissor, + uint32_t exclusiveScissorCount, + const VkRect2D* pExclusiveScissors); +#endif + + +#define VK_NV_device_diagnostic_checkpoints 1 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 +#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" +typedef struct VkQueueFamilyCheckpointPropertiesNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlags checkpointExecutionStageMask; +} VkQueueFamilyCheckpointPropertiesNV; + +typedef struct VkCheckpointDataNV { + VkStructureType sType; + void* pNext; + VkPipelineStageFlagBits stage; + void* pCheckpointMarker; +} VkCheckpointDataNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void* pCheckpointMarker); +typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointDataNV* pCheckpointData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCheckpointNV( + VkCommandBuffer commandBuffer, + const void* pCheckpointMarker); + +VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointDataNV* pCheckpointData); +#endif + + +#define VK_INTEL_shader_integer_functions2 1 +#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_SPEC_VERSION 1 +#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" +typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { + VkStructureType sType; + void* pNext; + VkBool32 shaderIntegerFunctions2; +} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; + + + +#define VK_INTEL_performance_query 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) +#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 +#define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" + +typedef enum VkPerformanceConfigurationTypeINTEL { + VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, + VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceConfigurationTypeINTEL; + +typedef enum VkQueryPoolSamplingModeINTEL { + VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, + VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkQueryPoolSamplingModeINTEL; + +typedef enum VkPerformanceOverrideTypeINTEL { + VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, + VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, + VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceOverrideTypeINTEL; + +typedef enum VkPerformanceParameterTypeINTEL { + VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, + VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, + VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceParameterTypeINTEL; + +typedef enum VkPerformanceValueTypeINTEL { + VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, + VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, + VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, + VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, + VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, + VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF +} VkPerformanceValueTypeINTEL; +typedef union VkPerformanceValueDataINTEL { + uint32_t value32; + uint64_t value64; + float valueFloat; + VkBool32 valueBool; + const char* valueString; +} VkPerformanceValueDataINTEL; + +typedef struct VkPerformanceValueINTEL { + VkPerformanceValueTypeINTEL type; + VkPerformanceValueDataINTEL data; +} VkPerformanceValueINTEL; + +typedef struct VkInitializePerformanceApiInfoINTEL { + VkStructureType sType; + const void* pNext; + void* pUserData; +} VkInitializePerformanceApiInfoINTEL; + +typedef struct VkQueryPoolPerformanceQueryCreateInfoINTEL { + VkStructureType sType; + const void* pNext; + VkQueryPoolSamplingModeINTEL performanceCountersSampling; +} VkQueryPoolPerformanceQueryCreateInfoINTEL; + +typedef VkQueryPoolPerformanceQueryCreateInfoINTEL VkQueryPoolCreateInfoINTEL; + +typedef struct VkPerformanceMarkerInfoINTEL { + VkStructureType sType; + const void* pNext; + uint64_t marker; +} VkPerformanceMarkerInfoINTEL; + +typedef struct VkPerformanceStreamMarkerInfoINTEL { + VkStructureType sType; + const void* pNext; + uint32_t marker; +} VkPerformanceStreamMarkerInfoINTEL; + +typedef struct VkPerformanceOverrideInfoINTEL { + VkStructureType sType; + const void* pNext; + VkPerformanceOverrideTypeINTEL type; + VkBool32 enable; + uint64_t parameter; +} VkPerformanceOverrideInfoINTEL; + +typedef struct VkPerformanceConfigurationAcquireInfoINTEL { + VkStructureType sType; + const void* pNext; + VkPerformanceConfigurationTypeINTEL type; +} VkPerformanceConfigurationAcquireInfoINTEL; + +typedef VkResult (VKAPI_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); +typedef void (VKAPI_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice device); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL* pMarkerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL* pOverrideInfo); +typedef VkResult (VKAPI_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, VkPerformanceConfigurationINTEL* pConfiguration); +typedef VkResult (VKAPI_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice device, VkPerformanceConfigurationINTEL configuration); +typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue queue, VkPerformanceConfigurationINTEL configuration); +typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL* pValue); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkInitializePerformanceApiINTEL( + VkDevice device, + const VkInitializePerformanceApiInfoINTEL* pInitializeInfo); + +VKAPI_ATTR void VKAPI_CALL vkUninitializePerformanceApiINTEL( + VkDevice device); + +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceMarkerINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceMarkerInfoINTEL* pMarkerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceStreamMarkerINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCmdSetPerformanceOverrideINTEL( + VkCommandBuffer commandBuffer, + const VkPerformanceOverrideInfoINTEL* pOverrideInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquirePerformanceConfigurationINTEL( + VkDevice device, + const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo, + VkPerformanceConfigurationINTEL* pConfiguration); + +VKAPI_ATTR VkResult VKAPI_CALL vkReleasePerformanceConfigurationINTEL( + VkDevice device, + VkPerformanceConfigurationINTEL configuration); + +VKAPI_ATTR VkResult VKAPI_CALL vkQueueSetPerformanceConfigurationINTEL( + VkQueue queue, + VkPerformanceConfigurationINTEL configuration); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPerformanceParameterINTEL( + VkDevice device, + VkPerformanceParameterTypeINTEL parameter, + VkPerformanceValueINTEL* pValue); +#endif + + +#define VK_EXT_pci_bus_info 1 +#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 +#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" +typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t pciDomain; + uint32_t pciBus; + uint32_t pciDevice; + uint32_t pciFunction; +} VkPhysicalDevicePCIBusInfoPropertiesEXT; + + + +#define VK_AMD_display_native_hdr 1 +#define VK_AMD_DISPLAY_NATIVE_HDR_SPEC_VERSION 1 +#define VK_AMD_DISPLAY_NATIVE_HDR_EXTENSION_NAME "VK_AMD_display_native_hdr" +typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { + VkStructureType sType; + void* pNext; + VkBool32 localDimmingSupport; +} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + +typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkBool32 localDimmingEnable; +} VkSwapchainDisplayNativeHdrCreateInfoAMD; + +typedef void (VKAPI_PTR *PFN_vkSetLocalDimmingAMD)(VkDevice device, VkSwapchainKHR swapChain, VkBool32 localDimmingEnable); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkSetLocalDimmingAMD( + VkDevice device, + VkSwapchainKHR swapChain, + VkBool32 localDimmingEnable); +#endif + + +#define VK_EXT_fragment_density_map 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" +typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMap; + VkBool32 fragmentDensityMapDynamic; + VkBool32 fragmentDensityMapNonSubsampledImages; +} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { + VkStructureType sType; + void* pNext; + VkExtent2D minFragmentDensityTexelSize; + VkExtent2D maxFragmentDensityTexelSize; + VkBool32 fragmentDensityInvocations; +} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + +typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkAttachmentReference fragmentDensityMapAttachment; +} VkRenderPassFragmentDensityMapCreateInfoEXT; + + + +#define VK_EXT_scalar_block_layout 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" +typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + + + +#define VK_GOOGLE_hlsl_functionality1 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" + + +#define VK_GOOGLE_decorate_string 1 +#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 +#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" + + +#define VK_EXT_subgroup_size_control 1 +#define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 +#define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" +typedef struct VkPhysicalDeviceSubgroupSizeControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; +} VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; + +typedef struct VkPhysicalDeviceSubgroupSizeControlPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; +} VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT { + VkStructureType sType; + void* pNext; + uint32_t requiredSubgroupSize; +} VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; + + + +#define VK_AMD_shader_core_properties2 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION 1 +#define VK_AMD_SHADER_CORE_PROPERTIES_2_EXTENSION_NAME "VK_AMD_shader_core_properties2" + +typedef enum VkShaderCorePropertiesFlagBitsAMD { + VK_SHADER_CORE_PROPERTIES_FLAG_BITS_MAX_ENUM_AMD = 0x7FFFFFFF +} VkShaderCorePropertiesFlagBitsAMD; +typedef VkFlags VkShaderCorePropertiesFlagsAMD; +typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { + VkStructureType sType; + void* pNext; + VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; + uint32_t activeComputeUnitCount; +} VkPhysicalDeviceShaderCoreProperties2AMD; + + + +#define VK_AMD_device_coherent_memory 1 +#define VK_AMD_DEVICE_COHERENT_MEMORY_SPEC_VERSION 1 +#define VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME "VK_AMD_device_coherent_memory" +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { + VkStructureType sType; + void* pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; + + + +#define VK_EXT_shader_image_atomic_int64 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME "VK_EXT_shader_image_atomic_int64" +typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderImageInt64Atomics; + VkBool32 sparseImageInt64Atomics; +} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT; + + + +#define VK_EXT_memory_budget 1 +#define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 +#define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS]; + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + + + +#define VK_EXT_memory_priority 1 +#define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 +#define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + +typedef struct VkMemoryPriorityAllocateInfoEXT { + VkStructureType sType; + const void* pNext; + float priority; +} VkMemoryPriorityAllocateInfoEXT; + + + +#define VK_NV_dedicated_allocation_image_aliasing 1 +#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 +#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" +typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 dedicatedAllocationImageAliasing; +} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + + + +#define VK_EXT_buffer_device_address 1 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 +#define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + +typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; + +typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoEXT; + +typedef struct VkBufferDeviceAddressCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceAddress deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; + +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfo* pInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT( + VkDevice device, + const VkBufferDeviceAddressInfo* pInfo); +#endif + + +#define VK_EXT_tooling_info 1 +#define VK_EXT_TOOLING_INFO_SPEC_VERSION 1 +#define VK_EXT_TOOLING_INFO_EXTENSION_NAME "VK_EXT_tooling_info" + +typedef enum VkToolPurposeFlagBitsEXT { + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = 0x00000001, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = 0x00000002, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = 0x00000004, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = 0x00000008, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = 0x00000010, + VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkToolPurposeFlagBitsEXT; +typedef VkFlags VkToolPurposeFlagsEXT; +typedef struct VkPhysicalDeviceToolPropertiesEXT { + VkStructureType sType; + void* pNext; + char name[VK_MAX_EXTENSION_NAME_SIZE]; + char version[VK_MAX_EXTENSION_NAME_SIZE]; + VkToolPurposeFlagsEXT purposes; + char description[VK_MAX_DESCRIPTION_SIZE]; + char layer[VK_MAX_EXTENSION_NAME_SIZE]; +} VkPhysicalDeviceToolPropertiesEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t* pToolCount, VkPhysicalDeviceToolPropertiesEXT* pToolProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceToolPropertiesEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pToolCount, + VkPhysicalDeviceToolPropertiesEXT* pToolProperties); +#endif + + +#define VK_EXT_separate_stencil_usage 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" +typedef VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; + + + +#define VK_EXT_validation_features 1 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 4 +#define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" + +typedef enum VkValidationFeatureEnableEXT { + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, + VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4, + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureEnableEXT; + +typedef enum VkValidationFeatureDisableEXT { + VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, + VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, + VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, + VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, + VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, + VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkValidationFeatureDisableEXT; +typedef struct VkValidationFeaturesEXT { + VkStructureType sType; + const void* pNext; + uint32_t enabledValidationFeatureCount; + const VkValidationFeatureEnableEXT* pEnabledValidationFeatures; + uint32_t disabledValidationFeatureCount; + const VkValidationFeatureDisableEXT* pDisabledValidationFeatures; +} VkValidationFeaturesEXT; + + + +#define VK_NV_cooperative_matrix 1 +#define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" + +typedef enum VkComponentTypeNV { + VK_COMPONENT_TYPE_FLOAT16_NV = 0, + VK_COMPONENT_TYPE_FLOAT32_NV = 1, + VK_COMPONENT_TYPE_FLOAT64_NV = 2, + VK_COMPONENT_TYPE_SINT8_NV = 3, + VK_COMPONENT_TYPE_SINT16_NV = 4, + VK_COMPONENT_TYPE_SINT32_NV = 5, + VK_COMPONENT_TYPE_SINT64_NV = 6, + VK_COMPONENT_TYPE_UINT8_NV = 7, + VK_COMPONENT_TYPE_UINT16_NV = 8, + VK_COMPONENT_TYPE_UINT32_NV = 9, + VK_COMPONENT_TYPE_UINT64_NV = 10, + VK_COMPONENT_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkComponentTypeNV; + +typedef enum VkScopeNV { + VK_SCOPE_DEVICE_NV = 1, + VK_SCOPE_WORKGROUP_NV = 2, + VK_SCOPE_SUBGROUP_NV = 3, + VK_SCOPE_QUEUE_FAMILY_NV = 5, + VK_SCOPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkScopeNV; +typedef struct VkCooperativeMatrixPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeNV AType; + VkComponentTypeNV BType; + VkComponentTypeNV CType; + VkComponentTypeNV DType; + VkScopeNV scope; +} VkCooperativeMatrixPropertiesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; + +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { + VkStructureType sType; + void* pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkCooperativeMatrixPropertiesNV* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesNV( + VkPhysicalDevice physicalDevice, + uint32_t* pPropertyCount, + VkCooperativeMatrixPropertiesNV* pProperties); +#endif + + +#define VK_NV_coverage_reduction_mode 1 +#define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 +#define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" + +typedef enum VkCoverageReductionModeNV { + VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, + VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, + VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCoverageReductionModeNV; +typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 coverageReductionMode; +} VkPhysicalDeviceCoverageReductionModeFeaturesNV; + +typedef struct VkPipelineCoverageReductionStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCoverageReductionStateCreateFlagsNV flags; + VkCoverageReductionModeNV coverageReductionMode; +} VkPipelineCoverageReductionStateCreateInfoNV; + +typedef struct VkFramebufferMixedSamplesCombinationNV { + VkStructureType sType; + void* pNext; + VkCoverageReductionModeNV coverageReductionMode; + VkSampleCountFlagBits rasterizationSamples; + VkSampleCountFlags depthStencilSamples; + VkSampleCountFlags colorSamples; +} VkFramebufferMixedSamplesCombinationNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)(VkPhysicalDevice physicalDevice, uint32_t* pCombinationCount, VkFramebufferMixedSamplesCombinationNV* pCombinations); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV( + VkPhysicalDevice physicalDevice, + uint32_t* pCombinationCount, + VkFramebufferMixedSamplesCombinationNV* pCombinations); +#endif + + +#define VK_EXT_fragment_shader_interlock 1 +#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" +typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShaderSampleInterlock; + VkBool32 fragmentShaderPixelInterlock; + VkBool32 fragmentShaderShadingRateInterlock; +} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; + + + +#define VK_EXT_ycbcr_image_arrays 1 +#define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 +#define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" +typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 ycbcrImageArrays; +} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; + + + +#define VK_EXT_headless_surface 1 +#define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1 +#define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface" +typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +typedef struct VkHeadlessSurfaceCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkHeadlessSurfaceCreateFlagsEXT flags; +} VkHeadlessSurfaceCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateHeadlessSurfaceEXT( + VkInstance instance, + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + + +#define VK_EXT_line_rasterization 1 +#define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" + +typedef enum VkLineRasterizationModeEXT { + VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = 0, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3, + VK_LINE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkLineRasterizationModeEXT; +typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; +} VkPhysicalDeviceLineRasterizationFeaturesEXT; + +typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t lineSubPixelPrecisionBits; +} VkPhysicalDeviceLineRasterizationPropertiesEXT; + +typedef struct VkPipelineRasterizationLineStateCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkLineRasterizationModeEXT lineRasterizationMode; + VkBool32 stippledLineEnable; + uint32_t lineStippleFactor; + uint16_t lineStipplePattern; +} VkPipelineRasterizationLineStateCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEXT( + VkCommandBuffer commandBuffer, + uint32_t lineStippleFactor, + uint16_t lineStipplePattern); +#endif + + +#define VK_EXT_shader_atomic_float 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME "VK_EXT_shader_atomic_float" +typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderBufferFloat32Atomics; + VkBool32 shaderBufferFloat32AtomicAdd; + VkBool32 shaderBufferFloat64Atomics; + VkBool32 shaderBufferFloat64AtomicAdd; + VkBool32 shaderSharedFloat32Atomics; + VkBool32 shaderSharedFloat32AtomicAdd; + VkBool32 shaderSharedFloat64Atomics; + VkBool32 shaderSharedFloat64AtomicAdd; + VkBool32 shaderImageFloat32Atomics; + VkBool32 shaderImageFloat32AtomicAdd; + VkBool32 sparseImageFloat32Atomics; + VkBool32 sparseImageFloat32AtomicAdd; +} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + + + +#define VK_EXT_host_query_reset 1 +#define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 +#define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" +typedef VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkResetQueryPoolEXT( + VkDevice device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount); +#endif + + +#define VK_EXT_index_type_uint8 1 +#define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" +typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 indexTypeUint8; +} VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + + + +#define VK_EXT_extended_dynamic_state 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_extended_dynamic_state" +typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState; +} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetCullModeEXT)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); +typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFaceEXT)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport* pViewports); +typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors); +typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes, const VkDeviceSize* pStrides); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOpEXT)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetCullModeEXT( + VkCommandBuffer commandBuffer, + VkCullModeFlags cullMode); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetFrontFaceEXT( + VkCommandBuffer commandBuffer, + VkFrontFace frontFace); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveTopologyEXT( + VkCommandBuffer commandBuffer, + VkPrimitiveTopology primitiveTopology); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t viewportCount, + const VkViewport* pViewports); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetScissorWithCountEXT( + VkCommandBuffer commandBuffer, + uint32_t scissorCount, + const VkRect2D* pScissors); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers2EXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes, + const VkDeviceSize* pStrides); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthWriteEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthWriteEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthCompareOpEXT( + VkCommandBuffer commandBuffer, + VkCompareOp depthCompareOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBoundsTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBoundsTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilTestEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stencilTestEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilOpEXT( + VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + VkStencilOp failOp, + VkStencilOp passOp, + VkStencilOp depthFailOp, + VkCompareOp compareOp); +#endif + + +#define VK_EXT_shader_demote_to_helper_invocation 1 +#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 +#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 shaderDemoteToHelperInvocation; +} VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; + + + +#define VK_NV_device_generated_commands 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) +#define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 +#define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" + +typedef enum VkIndirectCommandsTokenTypeNV { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeNV; + +typedef enum VkIndirectStateFlagBitsNV { + VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 0x00000001, + VK_INDIRECT_STATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectStateFlagBitsNV; +typedef VkFlags VkIndirectStateFlagsNV; + +typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 0x00000001, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 0x00000002, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 0x00000004, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsNV; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { + VkStructureType sType; + void* pNext; + uint32_t maxGraphicsShaderGroupCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsStreamCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsStreamStride; + uint32_t minSequencesCountBufferOffsetAlignment; + uint32_t minSequencesIndexBufferOffsetAlignment; + uint32_t minIndirectCommandsBufferOffsetAlignment; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 deviceGeneratedCommands; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; + +typedef struct VkGraphicsShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + const VkPipelineTessellationStateCreateInfo* pTessellationState; +} VkGraphicsShaderGroupCreateInfoNV; + +typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t groupCount; + const VkGraphicsShaderGroupCreateInfoNV* pGroups; + uint32_t pipelineCount; + const VkPipeline* pPipelines; +} VkGraphicsPipelineShaderGroupsCreateInfoNV; + +typedef struct VkBindShaderGroupIndirectCommandNV { + uint32_t groupIndex; +} VkBindShaderGroupIndirectCommandNV; + +typedef struct VkBindIndexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandNV; + +typedef struct VkBindVertexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandNV; + +typedef struct VkSetStateFlagsIndirectCommandNV { + uint32_t data; +} VkSetStateFlagsIndirectCommandNV; + +typedef struct VkIndirectCommandsStreamNV { + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsStreamNV; + +typedef struct VkIndirectCommandsLayoutTokenNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsTokenTypeNV tokenType; + uint32_t stream; + uint32_t offset; + uint32_t vertexBindingUnit; + VkBool32 vertexDynamicStride; + VkPipelineLayout pushconstantPipelineLayout; + VkShaderStageFlags pushconstantShaderStageFlags; + uint32_t pushconstantOffset; + uint32_t pushconstantSize; + VkIndirectStateFlagsNV indirectStateFlags; + uint32_t indexTypeCount; + const VkIndexType* pIndexTypes; + const uint32_t* pIndexTypeValues; +} VkIndirectCommandsLayoutTokenNV; + +typedef struct VkIndirectCommandsLayoutCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkIndirectCommandsLayoutUsageFlagsNV flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNV* pTokens; + uint32_t streamCount; + const uint32_t* pStreamStrides; +} VkIndirectCommandsLayoutCreateInfoNV; + +typedef struct VkGeneratedCommandsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t streamCount; + const VkIndirectCommandsStreamNV* pStreams; + uint32_t sequencesCount; + VkBuffer preprocessBuffer; + VkDeviceSize preprocessOffset; + VkDeviceSize preprocessSize; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkGeneratedCommandsInfoNV; + +typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t maxSequencesCount; +} VkGeneratedCommandsMemoryRequirementsInfoNV; + +typedef void (VKAPI_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2* pMemoryRequirements); +typedef void (VKAPI_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); +typedef void (VKAPI_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); +typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); +typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkGetGeneratedCommandsMemoryRequirementsNV( + VkDevice device, + const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo, + VkMemoryRequirements2* pMemoryRequirements); + +VKAPI_ATTR void VKAPI_CALL vkCmdPreprocessGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdExecuteGeneratedCommandsNV( + VkCommandBuffer commandBuffer, + VkBool32 isPreprocessed, + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdBindPipelineShaderGroupNV( + VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline, + uint32_t groupIndex); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNV( + VkDevice device, + const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkIndirectCommandsLayoutNV* pIndirectCommandsLayout); + +VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNV( + VkDevice device, + VkIndirectCommandsLayoutNV indirectCommandsLayout, + const VkAllocationCallbacks* pAllocator); +#endif + + +#define VK_NV_inherited_viewport_scissor 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME "VK_NV_inherited_viewport_scissor" +typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 inheritedViewportScissor2D; +} VkPhysicalDeviceInheritedViewportScissorFeaturesNV; + +typedef struct VkCommandBufferInheritanceViewportScissorInfoNV { + VkStructureType sType; + const void* pNext; + VkBool32 viewportScissor2D; + uint32_t viewportDepthCount; + const VkViewport* pViewportDepths; +} VkCommandBufferInheritanceViewportScissorInfoNV; + + + +#define VK_EXT_texel_buffer_alignment 1 +#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 +#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" +typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 texelBufferAlignment; +} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; + +typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; +} VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + + + +#define VK_QCOM_render_pass_transform 1 +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 2 +#define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" +typedef struct VkRenderPassTransformBeginInfoQCOM { + VkStructureType sType; + void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkRenderPassTransformBeginInfoQCOM; + +typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { + VkStructureType sType; + void* pNext; + VkSurfaceTransformFlagBitsKHR transform; + VkRect2D renderArea; +} VkCommandBufferInheritanceRenderPassTransformInfoQCOM; + + + +#define VK_EXT_device_memory_report 1 +#define VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME "VK_EXT_device_memory_report" + +typedef enum VkDeviceMemoryReportEventTypeEXT { + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT = 0, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT = 1, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT = 2, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT = 3, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT = 4, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceMemoryReportEventTypeEXT; +typedef VkFlags VkDeviceMemoryReportFlagsEXT; +typedef struct VkPhysicalDeviceDeviceMemoryReportFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 deviceMemoryReport; +} VkPhysicalDeviceDeviceMemoryReportFeaturesEXT; + +typedef struct VkDeviceMemoryReportCallbackDataEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemoryReportFlagsEXT flags; + VkDeviceMemoryReportEventTypeEXT type; + uint64_t memoryObjectId; + VkDeviceSize size; + VkObjectType objectType; + uint64_t objectHandle; + uint32_t heapIndex; +} VkDeviceMemoryReportCallbackDataEXT; + +typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( + const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, + void* pUserData); + +typedef struct VkDeviceDeviceMemoryReportCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkDeviceMemoryReportFlagsEXT flags; + PFN_vkDeviceMemoryReportCallbackEXT pfnUserCallback; + void* pUserData; +} VkDeviceDeviceMemoryReportCreateInfoEXT; + + + +#define VK_EXT_robustness2 1 +#define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 +#define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" +typedef struct VkPhysicalDeviceRobustness2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 robustBufferAccess2; + VkBool32 robustImageAccess2; + VkBool32 nullDescriptor; +} VkPhysicalDeviceRobustness2FeaturesEXT; + +typedef struct VkPhysicalDeviceRobustness2PropertiesEXT { + VkStructureType sType; + void* pNext; + VkDeviceSize robustStorageBufferAccessSizeAlignment; + VkDeviceSize robustUniformBufferAccessSizeAlignment; +} VkPhysicalDeviceRobustness2PropertiesEXT; + + + +#define VK_EXT_custom_border_color 1 +#define VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION 12 +#define VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME "VK_EXT_custom_border_color" +typedef struct VkSamplerCustomBorderColorCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkClearColorValue customBorderColor; + VkFormat format; +} VkSamplerCustomBorderColorCreateInfoEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxCustomBorderColorSamplers; +} VkPhysicalDeviceCustomBorderColorPropertiesEXT; + +typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 customBorderColors; + VkBool32 customBorderColorWithoutFormat; +} VkPhysicalDeviceCustomBorderColorFeaturesEXT; + + + +#define VK_GOOGLE_user_type 1 +#define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 +#define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" + + +#define VK_EXT_private_data 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlotEXT) +#define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 +#define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" + +typedef enum VkPrivateDataSlotCreateFlagBitsEXT { + VK_PRIVATE_DATA_SLOT_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPrivateDataSlotCreateFlagBitsEXT; +typedef VkFlags VkPrivateDataSlotCreateFlagsEXT; +typedef struct VkPhysicalDevicePrivateDataFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeaturesEXT; + +typedef struct VkDevicePrivateDataCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t privateDataSlotRequestCount; +} VkDevicePrivateDataCreateInfoEXT; + +typedef struct VkPrivateDataSlotCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPrivateDataSlotCreateFlagsEXT flags; +} VkPrivateDataSlotCreateInfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPrivateDataSlotEXT* pPrivateDataSlot); +typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlotEXT privateDataSlot, const VkAllocationCallbacks* pAllocator); +typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t data); +typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t* pData); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreatePrivateDataSlotEXT( + VkDevice device, + const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot); + +VKAPI_ATTR void VKAPI_CALL vkDestroyPrivateDataSlotEXT( + VkDevice device, + VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR VkResult VKAPI_CALL vkSetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t data); + +VKAPI_ATTR void VKAPI_CALL vkGetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t* pData); +#endif + + +#define VK_EXT_pipeline_creation_cache_control 1 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 +#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; + + + +#define VK_NV_device_diagnostics_config 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" + +typedef enum VkDeviceDiagnosticsConfigFlagBitsNV { + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 0x00000001, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 0x00000002, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 0x00000004, + VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkDeviceDiagnosticsConfigFlagBitsNV; +typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 diagnosticsConfig; +} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; + +typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceDiagnosticsConfigFlagsNV flags; +} VkDeviceDiagnosticsConfigCreateInfoNV; + + + +#define VK_QCOM_render_pass_store_ops 1 +#define VK_QCOM_render_pass_store_ops_SPEC_VERSION 2 +#define VK_QCOM_render_pass_store_ops_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" + + +#define VK_NV_fragment_shading_rate_enums 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" + +typedef enum VkFragmentShadingRateTypeNV { + VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV = 0, + VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV = 1, + VK_FRAGMENT_SHADING_RATE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateTypeNV; + +typedef enum VkFragmentShadingRateNV { + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV = 0, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV = 1, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV = 4, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV = 5, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV = 6, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV = 10, + VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV = 11, + VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV = 12, + VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV = 13, + VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV = 14, + VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV = 15, + VK_FRAGMENT_SHADING_RATE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateNV; +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV { + VkStructureType sType; + void* pNext; + VkBool32 fragmentShadingRateEnums; + VkBool32 supersampleFragmentShadingRates; + VkBool32 noInvocationFragmentShadingRates; +} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV; + +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV { + VkStructureType sType; + void* pNext; + VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; +} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV; + +typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkFragmentShadingRateTypeNV shadingRateType; + VkFragmentShadingRateNV shadingRate; + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; +} VkPipelineFragmentShadingRateEnumStateCreateInfoNV; + +typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetFragmentShadingRateEnumNV( + VkCommandBuffer commandBuffer, + VkFragmentShadingRateNV shadingRate, + const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); +#endif + + +#define VK_EXT_ycbcr_2plane_444_formats 1 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME "VK_EXT_ycbcr_2plane_444_formats" +typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 ycbcr2plane444Formats; +} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT; + + + +#define VK_EXT_fragment_density_map2 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME "VK_EXT_fragment_density_map2" +typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 fragmentDensityMapDeferred; +} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { + VkStructureType sType; + void* pNext; + VkBool32 subsampledLoads; + VkBool32 subsampledCoarseReconstructionEarlyAccess; + uint32_t maxSubsampledArrayLayers; + uint32_t maxDescriptorSetSubsampledSamplers; +} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + + + +#define VK_QCOM_rotated_copy_commands 1 +#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 1 +#define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" +typedef struct VkCopyCommandTransformInfoQCOM { + VkStructureType sType; + const void* pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkCopyCommandTransformInfoQCOM; + + + +#define VK_EXT_image_robustness 1 +#define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" +typedef struct VkPhysicalDeviceImageRobustnessFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 robustImageAccess; +} VkPhysicalDeviceImageRobustnessFeaturesEXT; + + + +#define VK_EXT_4444_formats 1 +#define VK_EXT_4444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats" +typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 formatA4R4G4B4; + VkBool32 formatA4B4G4R4; +} VkPhysicalDevice4444FormatsFeaturesEXT; + + + +#define VK_NV_acquire_winrt_display 1 +#define VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION 1 +#define VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME "VK_NV_acquire_winrt_display" +typedef VkResult (VKAPI_PTR *PFN_vkAcquireWinrtDisplayNV)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); +typedef VkResult (VKAPI_PTR *PFN_vkGetWinrtDisplayNV)(VkPhysicalDevice physicalDevice, uint32_t deviceRelativeId, VkDisplayKHR* pDisplay); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireWinrtDisplayNV( + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetWinrtDisplayNV( + VkPhysicalDevice physicalDevice, + uint32_t deviceRelativeId, + VkDisplayKHR* pDisplay); +#endif + + +#define VK_VALVE_mutable_descriptor_type 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type" +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE { + VkStructureType sType; + void* pNext; + VkBool32 mutableDescriptorType; +} VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE; + +typedef struct VkMutableDescriptorTypeListVALVE { + uint32_t descriptorTypeCount; + const VkDescriptorType* pDescriptorTypes; +} VkMutableDescriptorTypeListVALVE; + +typedef struct VkMutableDescriptorTypeCreateInfoVALVE { + VkStructureType sType; + const void* pNext; + uint32_t mutableDescriptorTypeListCount; + const VkMutableDescriptorTypeListVALVE* pMutableDescriptorTypeLists; +} VkMutableDescriptorTypeCreateInfoVALVE; + + + +#define VK_EXT_vertex_input_dynamic_state 1 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION 2 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_vertex_input_dynamic_state" +typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 vertexInputDynamicState; +} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT; + +typedef struct VkVertexInputBindingDescription2EXT { + VkStructureType sType; + void* pNext; + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; + uint32_t divisor; +} VkVertexInputBindingDescription2EXT; + +typedef struct VkVertexInputAttributeDescription2EXT { + VkStructureType sType; + void* pNext; + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription2EXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetVertexInputEXT)(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetVertexInputEXT( + VkCommandBuffer commandBuffer, + uint32_t vertexBindingDescriptionCount, + const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions, + uint32_t vertexAttributeDescriptionCount, + const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions); +#endif + + +#define VK_EXT_extended_dynamic_state2 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2" +typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 extendedDynamicState2; + VkBool32 extendedDynamicState2LogicOp; + VkBool32 extendedDynamicState2PatchControlPoints; +} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer commandBuffer, uint32_t patchControlPoints); +typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEXT)(VkCommandBuffer commandBuffer, VkLogicOp logicOp); +typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetPatchControlPointsEXT( + VkCommandBuffer commandBuffer, + uint32_t patchControlPoints); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRasterizerDiscardEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 rasterizerDiscardEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBiasEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthBiasEnable); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetLogicOpEXT( + VkCommandBuffer commandBuffer, + VkLogicOp logicOp); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetPrimitiveRestartEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 primitiveRestartEnable); +#endif + + +#define VK_EXT_color_write_enable 1 +#define VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION 1 +#define VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME "VK_EXT_color_write_enable" +typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 colorWriteEnable; +} VkPhysicalDeviceColorWriteEnableFeaturesEXT; + +typedef struct VkPipelineColorWriteCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t attachmentCount; + const VkBool32* pColorWriteEnables; +} VkPipelineColorWriteCreateInfoEXT; + +typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdSetColorWriteEnableEXT( + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkBool32* pColorWriteEnables); +#endif + + +#define VK_KHR_acceleration_structure 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) +#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 11 +#define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" + +typedef enum VkBuildAccelerationStructureModeKHR { + VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR = 0, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR = 1, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureModeKHR; + +typedef enum VkAccelerationStructureBuildTypeKHR { + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureBuildTypeKHR; + +typedef enum VkAccelerationStructureCompatibilityKHR { + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR = 0, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR = 1, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCompatibilityKHR; + +typedef enum VkAccelerationStructureCreateFlagBitsKHR { + VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = 0x00000001, + VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCreateFlagBitsKHR; +typedef VkFlags VkAccelerationStructureCreateFlagsKHR; +typedef union VkDeviceOrHostAddressKHR { + VkDeviceAddress deviceAddress; + void* hostAddress; +} VkDeviceOrHostAddressKHR; + +typedef union VkDeviceOrHostAddressConstKHR { + VkDeviceAddress deviceAddress; + const void* hostAddress; +} VkDeviceOrHostAddressConstKHR; + +typedef struct VkAccelerationStructureBuildRangeInfoKHR { + uint32_t primitiveCount; + uint32_t primitiveOffset; + uint32_t firstVertex; + uint32_t transformOffset; +} VkAccelerationStructureBuildRangeInfoKHR; + +typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { + VkStructureType sType; + const void* pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + uint32_t maxVertex; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceOrHostAddressConstKHR transformData; +} VkAccelerationStructureGeometryTrianglesDataKHR; + +typedef struct VkAccelerationStructureGeometryAabbsDataKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR data; + VkDeviceSize stride; +} VkAccelerationStructureGeometryAabbsDataKHR; + +typedef struct VkAccelerationStructureGeometryInstancesDataKHR { + VkStructureType sType; + const void* pNext; + VkBool32 arrayOfPointers; + VkDeviceOrHostAddressConstKHR data; +} VkAccelerationStructureGeometryInstancesDataKHR; + +typedef union VkAccelerationStructureGeometryDataKHR { + VkAccelerationStructureGeometryTrianglesDataKHR triangles; + VkAccelerationStructureGeometryAabbsDataKHR aabbs; + VkAccelerationStructureGeometryInstancesDataKHR instances; +} VkAccelerationStructureGeometryDataKHR; + +typedef struct VkAccelerationStructureGeometryKHR { + VkStructureType sType; + const void* pNext; + VkGeometryTypeKHR geometryType; + VkAccelerationStructureGeometryDataKHR geometry; + VkGeometryFlagsKHR flags; +} VkAccelerationStructureGeometryKHR; + +typedef struct VkAccelerationStructureBuildGeometryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + VkBuildAccelerationStructureModeKHR mode; + VkAccelerationStructureKHR srcAccelerationStructure; + VkAccelerationStructureKHR dstAccelerationStructure; + uint32_t geometryCount; + const VkAccelerationStructureGeometryKHR* pGeometries; + const VkAccelerationStructureGeometryKHR* const* ppGeometries; + VkDeviceOrHostAddressKHR scratchData; +} VkAccelerationStructureBuildGeometryInfoKHR; + +typedef struct VkAccelerationStructureCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureCreateFlagsKHR createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkAccelerationStructureTypeKHR type; + VkDeviceAddress deviceAddress; +} VkAccelerationStructureCreateInfoKHR; + +typedef struct VkWriteDescriptorSetAccelerationStructureKHR { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureKHR* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureKHR; + +typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 accelerationStructure; + VkBool32 accelerationStructureCaptureReplay; + VkBool32 accelerationStructureIndirectBuild; + VkBool32 accelerationStructureHostCommands; + VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; +} VkPhysicalDeviceAccelerationStructureFeaturesKHR; + +typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR { + VkStructureType sType; + void* pNext; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxPrimitiveCount; + uint32_t maxPerStageDescriptorAccelerationStructures; + uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; + uint32_t maxDescriptorSetAccelerationStructures; + uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; + uint32_t minAccelerationStructureScratchOffsetAlignment; +} VkPhysicalDeviceAccelerationStructurePropertiesKHR; + +typedef struct VkAccelerationStructureDeviceAddressInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR accelerationStructure; +} VkAccelerationStructureDeviceAddressInfoKHR; + +typedef struct VkAccelerationStructureVersionInfoKHR { + VkStructureType sType; + const void* pNext; + const uint8_t* pVersionData; +} VkAccelerationStructureVersionInfoKHR; + +typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkDeviceOrHostAddressKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureToMemoryInfoKHR; + +typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceOrHostAddressConstKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyMemoryToAccelerationStructureInfoKHR; + +typedef struct VkCopyAccelerationStructureInfoKHR { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureInfoKHR; + +typedef struct VkAccelerationStructureBuildSizesInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceSize accelerationStructureSize; + VkDeviceSize updateScratchSize; + VkDeviceSize buildScratchSize; +} VkAccelerationStructureBuildSizesInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice device, const VkAccelerationStructureCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureKHR* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkDeviceAddress* pIndirectDeviceAddresses, const uint32_t* pIndirectStrides, const uint32_t* const* ppMaxPrimitiveCounts); +typedef VkResult (VKAPI_PTR *PFN_vkBuildAccelerationStructuresKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkResult (VKAPI_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, size_t dataSize, void* pData, size_t stride); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); +typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (VKAPI_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionInfoKHR* pVersionInfo, VkAccelerationStructureCompatibilityKHR* pCompatibility); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureBuildSizesKHR)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo, const uint32_t* pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureKHR( + VkDevice device, + const VkAccelerationStructureCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkAccelerationStructureKHR* pAccelerationStructure); + +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureKHR( + VkDevice device, + VkAccelerationStructureKHR accelerationStructure, + const VkAllocationCallbacks* pAllocator); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructuresKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); + +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructuresIndirectKHR( + VkCommandBuffer commandBuffer, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkDeviceAddress* pIndirectDeviceAddresses, + const uint32_t* pIndirectStrides, + const uint32_t* const* ppMaxPrimitiveCounts); + +VKAPI_ATTR VkResult VKAPI_CALL vkBuildAccelerationStructuresKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + uint32_t infoCount, + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyAccelerationStructureToMemoryKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkCopyMemoryToAccelerationStructureKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkWriteAccelerationStructuresPropertiesKHR( + VkDevice device, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + size_t dataSize, + void* pData, + size_t stride); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureToMemoryKHR( + VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdCopyMemoryToAccelerationStructureKHR( + VkCommandBuffer commandBuffer, + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo); + +VKAPI_ATTR VkDeviceAddress VKAPI_CALL vkGetAccelerationStructureDeviceAddressKHR( + VkDevice device, + const VkAccelerationStructureDeviceAddressInfoKHR* pInfo); + +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesKHR( + VkCommandBuffer commandBuffer, + uint32_t accelerationStructureCount, + const VkAccelerationStructureKHR* pAccelerationStructures, + VkQueryType queryType, + VkQueryPool queryPool, + uint32_t firstQuery); + +VKAPI_ATTR void VKAPI_CALL vkGetDeviceAccelerationStructureCompatibilityKHR( + VkDevice device, + const VkAccelerationStructureVersionInfoKHR* pVersionInfo, + VkAccelerationStructureCompatibilityKHR* pCompatibility); + +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureBuildSizesKHR( + VkDevice device, + VkAccelerationStructureBuildTypeKHR buildType, + const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo, + const uint32_t* pMaxPrimitiveCounts, + VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo); +#endif + + +#define VK_KHR_ray_tracing_pipeline 1 +#define VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME "VK_KHR_ray_tracing_pipeline" + +typedef enum VkShaderGroupShaderKHR { + VK_SHADER_GROUP_SHADER_GENERAL_KHR = 0, + VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR = 1, + VK_SHADER_GROUP_SHADER_ANY_HIT_KHR = 2, + VK_SHADER_GROUP_SHADER_INTERSECTION_KHR = 3, + VK_SHADER_GROUP_SHADER_MAX_ENUM_KHR = 0x7FFFFFFF +} VkShaderGroupShaderKHR; +typedef struct VkRayTracingShaderGroupCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeKHR type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; + const void* pShaderGroupCaptureReplayHandle; +} VkRayTracingShaderGroupCreateInfoKHR; + +typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t maxPipelineRayPayloadSize; + uint32_t maxPipelineRayHitAttributeSize; +} VkRayTracingPipelineInterfaceCreateInfoKHR; + +typedef struct VkRayTracingPipelineCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoKHR* pGroups; + uint32_t maxPipelineRayRecursionDepth; + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo; + const VkRayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface; + const VkPipelineDynamicStateCreateInfo* pDynamicState; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayTracingPipeline; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; + VkBool32 rayTracingPipelineTraceRaysIndirect; + VkBool32 rayTraversalPrimitiveCulling; +} VkPhysicalDeviceRayTracingPipelineFeaturesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRayRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupHandleCaptureReplaySize; + uint32_t maxRayDispatchInvocationCount; + uint32_t shaderGroupHandleAlignment; + uint32_t maxRayHitAttributeSize; +} VkPhysicalDeviceRayTracingPipelinePropertiesKHR; + +typedef struct VkStridedDeviceAddressRegionKHR { + VkDeviceAddress deviceAddress; + VkDeviceSize stride; + VkDeviceSize size; +} VkStridedDeviceAddressRegionKHR; + +typedef struct VkTraceRaysIndirectCommandKHR { + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommandKHR; + +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress); +typedef VkDeviceSize (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader); +typedef void (VKAPI_PTR *PFN_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysKHR( + VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + uint32_t width, + uint32_t height, + uint32_t depth); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR( + VkDevice device, + VkDeferredOperationKHR deferredOperation, + VkPipelineCache pipelineCache, + uint32_t createInfoCount, + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos, + const VkAllocationCallbacks* pAllocator, + VkPipeline* pPipelines); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingCaptureReplayShaderGroupHandlesKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t firstGroup, + uint32_t groupCount, + size_t dataSize, + void* pData); + +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirectKHR( + VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + VkDeviceAddress indirectDeviceAddress); + +VKAPI_ATTR VkDeviceSize VKAPI_CALL vkGetRayTracingShaderGroupStackSizeKHR( + VkDevice device, + VkPipeline pipeline, + uint32_t group, + VkShaderGroupShaderKHR groupShader); + +VKAPI_ATTR void VKAPI_CALL vkCmdSetRayTracingPipelineStackSizeKHR( + VkCommandBuffer commandBuffer, + uint32_t pipelineStackSize); +#endif + + +#define VK_KHR_ray_query 1 +#define VK_KHR_RAY_QUERY_SPEC_VERSION 1 +#define VK_KHR_RAY_QUERY_EXTENSION_NAME "VK_KHR_ray_query" +typedef struct VkPhysicalDeviceRayQueryFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 rayQuery; +} VkPhysicalDeviceRayQueryFeaturesKHR; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_ios.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_ios.h new file mode 100644 index 00000000000000..6e7e6afea6ce9c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_ios.h @@ -0,0 +1,47 @@ +#ifndef VULKAN_IOS_H_ +#define VULKAN_IOS_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_MVK_ios_surface 1 +#define VK_MVK_IOS_SURFACE_SPEC_VERSION 3 +#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" +typedef VkFlags VkIOSSurfaceCreateFlagsMVK; +typedef struct VkIOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void* pNext; + VkIOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkIOSSurfaceCreateInfoMVK; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK( + VkInstance instance, + const VkIOSSurfaceCreateInfoMVK* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_macos.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_macos.h new file mode 100644 index 00000000000000..c49b123d078e93 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_macos.h @@ -0,0 +1,47 @@ +#ifndef VULKAN_MACOS_H_ +#define VULKAN_MACOS_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_MVK_macos_surface 1 +#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3 +#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +typedef struct VkMacOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void* pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void* pView; +} VkMacOSSurfaceCreateInfoMVK; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK( + VkInstance instance, + const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_win32.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_win32.h new file mode 100644 index 00000000000000..1b680f0b1a20d0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_win32.h @@ -0,0 +1,315 @@ +#ifndef VULKAN_WIN32_H_ +#define VULKAN_WIN32_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_KHR_win32_surface 1 +#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 +#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR( + VkInstance instance, + const VkWin32SurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex); +#endif + + +#define VK_KHR_external_memory_win32 1 +#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" +typedef struct VkImportMemoryWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportMemoryWin32HandleInfoKHR; + +typedef struct VkExportMemoryWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; + LPCWSTR name; +} VkExportMemoryWin32HandleInfoKHR; + +typedef struct VkMemoryWin32HandlePropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t memoryTypeBits; +} VkMemoryWin32HandlePropertiesKHR; + +typedef struct VkMemoryGetWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetWin32HandleInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR( + VkDevice device, + const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + HANDLE handle, + VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties); +#endif + + +#define VK_KHR_win32_keyed_mutex 1 +#define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1 +#define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex" +typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t acquireCount; + const VkDeviceMemory* pAcquireSyncs; + const uint64_t* pAcquireKeys; + const uint32_t* pAcquireTimeouts; + uint32_t releaseCount; + const VkDeviceMemory* pReleaseSyncs; + const uint64_t* pReleaseKeys; +} VkWin32KeyedMutexAcquireReleaseInfoKHR; + + + +#define VK_KHR_external_semaphore_win32 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" +typedef struct VkImportSemaphoreWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportSemaphoreWin32HandleInfoKHR; + +typedef struct VkExportSemaphoreWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; + LPCWSTR name; +} VkExportSemaphoreWin32HandleInfoKHR; + +typedef struct VkD3D12FenceSubmitInfoKHR { + VkStructureType sType; + const void* pNext; + uint32_t waitSemaphoreValuesCount; + const uint64_t* pWaitSemaphoreValues; + uint32_t signalSemaphoreValuesCount; + const uint64_t* pSignalSemaphoreValues; +} VkD3D12FenceSubmitInfoKHR; + +typedef struct VkSemaphoreGetWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetWin32HandleInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR( + VkDevice device, + const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR( + VkDevice device, + const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle); +#endif + + +#define VK_KHR_external_fence_win32 1 +#define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1 +#define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" +typedef struct VkImportFenceWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportFenceWin32HandleInfoKHR; + +typedef struct VkExportFenceWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; + LPCWSTR name; +} VkExportFenceWin32HandleInfoKHR; + +typedef struct VkFenceGetWin32HandleInfoKHR { + VkStructureType sType; + const void* pNext; + VkFence fence; + VkExternalFenceHandleTypeFlagBits handleType; +} VkFenceGetWin32HandleInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo); +typedef VkResult (VKAPI_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceWin32HandleKHR( + VkDevice device, + const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR( + VkDevice device, + const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle); +#endif + + +#define VK_NV_external_memory_win32 1 +#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" +typedef struct VkImportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void* pNext; + VkExternalMemoryHandleTypeFlagsNV handleType; + HANDLE handle; +} VkImportMemoryWin32HandleInfoNV; + +typedef struct VkExportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void* pNext; + const SECURITY_ATTRIBUTES* pAttributes; + DWORD dwAccess; +} VkExportMemoryWin32HandleInfoNV; + +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV( + VkDevice device, + VkDeviceMemory memory, + VkExternalMemoryHandleTypeFlagsNV handleType, + HANDLE* pHandle); +#endif + + +#define VK_NV_win32_keyed_mutex 1 +#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2 +#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" +typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { + VkStructureType sType; + const void* pNext; + uint32_t acquireCount; + const VkDeviceMemory* pAcquireSyncs; + const uint64_t* pAcquireKeys; + const uint32_t* pAcquireTimeoutMilliseconds; + uint32_t releaseCount; + const VkDeviceMemory* pReleaseSyncs; + const uint64_t* pReleaseKeys; +} VkWin32KeyedMutexAcquireReleaseInfoNV; + + + +#define VK_EXT_full_screen_exclusive 1 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive" + +typedef enum VkFullScreenExclusiveEXT { + VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0, + VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, + VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, + VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, + VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFullScreenExclusiveEXT; +typedef struct VkSurfaceFullScreenExclusiveInfoEXT { + VkStructureType sType; + void* pNext; + VkFullScreenExclusiveEXT fullScreenExclusive; +} VkSurfaceFullScreenExclusiveInfoEXT; + +typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { + VkStructureType sType; + void* pNext; + VkBool32 fullScreenExclusiveSupported; +} VkSurfaceCapabilitiesFullScreenExclusiveEXT; + +typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT { + VkStructureType sType; + const void* pNext; + HMONITOR hmonitor; +} VkSurfaceFullScreenExclusiveWin32InfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); +typedef VkResult (VKAPI_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR* pModes); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModes2EXT( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireFullScreenExclusiveModeEXT( + VkDevice device, + VkSwapchainKHR swapchain); + +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseFullScreenExclusiveModeEXT( + VkDevice device, + VkSwapchainKHR swapchain); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT( + VkDevice device, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + VkDeviceGroupPresentModeFlagsKHR* pModes); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_xcb.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_xcb.h new file mode 100644 index 00000000000000..5ba2ad850a2d75 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/third_party/vulkan/vulkan/vulkan_xcb.h @@ -0,0 +1,55 @@ +#ifndef VULKAN_XCB_H_ +#define VULKAN_XCB_H_ 1 + +/* +** Copyright 2015-2021 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define VK_KHR_xcb_surface 1 +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkAnimCodecPlayer.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkAnimCodecPlayer.h new file mode 100644 index 00000000000000..f4729aa37d6bce --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkAnimCodecPlayer.h @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAnimCodecPlayer_DEFINED +#define SkAnimCodecPlayer_DEFINED + +#include "include/codec/SkCodec.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" + +#include +#include +#include + +class SkImage; + +class SkAnimCodecPlayer { +public: + SkAnimCodecPlayer(std::unique_ptr codec); + ~SkAnimCodecPlayer(); + + /** + * Returns the current frame of the animation. This defaults to the first frame for + * animated codecs (i.e. msec = 0). Calling this multiple times (without calling seek()) + * will always return the same image object (or null if there was an error). + */ + sk_sp getFrame(); + + /** + * Return the size of the image(s) that will be returned by getFrame(). + */ + SkISize dimensions() const; + + /** + * Returns the total duration of the animation in milliseconds. Returns 0 for a single-frame + * image. + */ + uint32_t duration() const { return fTotalDuration; } + + /** + * Finds the closest frame associated with the time code (in milliseconds) and sets that + * to be the current frame (call getFrame() to retrieve that image). + * Returns true iff this call to seek() changed the "current frame" for the animation. + * Thus if seek() returns false, then getFrame() will return the same image as it did + * before this call to seek(). + */ + bool seek(uint32_t msec); + + +private: + std::unique_ptr fCodec; + SkImageInfo fImageInfo; + std::vector fFrameInfos; + std::vector > fImages; + int fCurrIndex = 0; + uint32_t fTotalDuration; + + sk_sp getFrameAt(int index); +}; + +#endif + diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkBase64.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkBase64.h new file mode 100644 index 00000000000000..e01028543a4230 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkBase64.h @@ -0,0 +1,53 @@ +/* + * 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 SkBase64_DEFINED +#define SkBase64_DEFINED + +#include "include/core/SkTypes.h" + +#include + +struct SkBase64 { +public: + enum Error { + kNoError, + kPadError, + kBadCharError + }; + + /** + Base64 encodes src into dst. + + Normally this is called once with 'dst' nullptr to get the required size, then again with an + allocated 'dst' pointer to do the actual encoding. + + @param dst nullptr or a pointer to a buffer large enough to receive the result + + @param encode nullptr for default encoding or a pointer to at least 65 chars. + encode[64] will be used as the pad character. + Encodings other than the default encoding cannot be decoded. + + @return the required length of dst for encoding. + */ + static size_t Encode(const void* src, size_t length, void* dst, const char* encode = nullptr); + + /** + Base64 decodes src into dst. + + Normally this is called once with 'dst' nullptr to get the required size, then again with an + allocated 'dst' pointer to do the actual encoding. + + @param dst nullptr or a pointer to a buffer large enough to receive the result + + @param dstLength assigned the length dst is required to be. Must not be nullptr. + */ + static Error SK_WARN_UNUSED_RESULT Decode(const void* src, size_t srcLength, + void* dst, size_t* dstLength); +}; + +#endif // SkBase64_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCamera.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCamera.h new file mode 100644 index 00000000000000..536691875e4f4c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCamera.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +// Inspired by Rob Johnson's most excellent QuickDraw GX sample code + +#ifndef SkCamera_DEFINED +#define SkCamera_DEFINED + +#include "include/core/SkM44.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkNoncopyable.h" + +// NOTE -- This entire header / impl is deprecated, and will be removed from Skia soon. +// +// Skia now has support for a 4x matrix (SkM44) in SkCanvas. +// + +class SkCanvas; + +// DEPRECATED +class SkPatch3D { +public: + SkPatch3D(); + + void reset(); + void transform(const SkM44&, SkPatch3D* dst = nullptr) const; + + // dot a unit vector with the patch's normal + SkScalar dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const; + SkScalar dotWith(const SkV3& v) const { + return this->dotWith(v.x, v.y, v.z); + } + + // deprecated, but still here for animator (for now) + void rotate(SkScalar /*x*/, SkScalar /*y*/, SkScalar /*z*/) {} + void rotateDegrees(SkScalar /*x*/, SkScalar /*y*/, SkScalar /*z*/) {} + +private: +public: // make public for SkDraw3D for now + SkV3 fU, fV; + SkV3 fOrigin; + + friend class SkCamera3D; +}; + +// DEPRECATED +class SkCamera3D { +public: + SkCamera3D(); + + void reset(); + void update(); + void patchToMatrix(const SkPatch3D&, SkMatrix* matrix) const; + + SkV3 fLocation; // origin of the camera's space + SkV3 fAxis; // view direction + SkV3 fZenith; // up direction + SkV3 fObserver; // eye position (may not be the same as the origin) + +private: + mutable SkMatrix fOrientation; + mutable bool fNeedToUpdate; + + void doUpdate() const; +}; + +// DEPRECATED +class SK_API Sk3DView : SkNoncopyable { +public: + Sk3DView(); + ~Sk3DView(); + + void save(); + void restore(); + + void translate(SkScalar x, SkScalar y, SkScalar z); + void rotateX(SkScalar deg); + void rotateY(SkScalar deg); + void rotateZ(SkScalar deg); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + void setCameraLocation(SkScalar x, SkScalar y, SkScalar z); + SkScalar getCameraLocationX() const; + SkScalar getCameraLocationY() const; + SkScalar getCameraLocationZ() const; +#endif + + void getMatrix(SkMatrix*) const; + void applyToCanvas(SkCanvas*) const; + + SkScalar dotWithNormal(SkScalar dx, SkScalar dy, SkScalar dz) const; + +private: + struct Rec { + Rec* fNext; + SkM44 fMatrix; + }; + Rec* fRec; + Rec fInitialRec; + SkCamera3D fCamera; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCanvasStateUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCanvasStateUtils.h new file mode 100644 index 00000000000000..0172e379310671 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCanvasStateUtils.h @@ -0,0 +1,81 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCanvasStateUtils_DEFINED +#define SkCanvasStateUtils_DEFINED + +#include "include/core/SkTypes.h" + +#include + +class SkCanvas; +class SkCanvasState; + +/** + * A set of functions that are useful for copying the state of an SkCanvas + * across a library boundary where the Skia library on the other side of the + * boundary may be newer. The expected usage is outline below... + * + * Lib Boundary + * CaptureCanvasState(...) ||| + * SkCanvas --> SkCanvasState ||| + * ||| CreateFromCanvasState(...) + * ||| SkCanvasState --> SkCanvas` + * ||| Draw into SkCanvas` + * ||| Unref SkCanvas` + * ReleaseCanvasState(...) ||| + * + */ +class SK_API SkCanvasStateUtils { +public: + /** + * Captures the current state of the canvas into an opaque ptr that is safe + * to pass to a different instance of Skia (which may be the same version, + * or may be newer). The function will return NULL in the event that one of the + * following conditions are true. + * 1) the canvas device type is not supported (currently only raster is supported) + * 2) the canvas clip type is not supported (currently only non-AA clips are supported) + * + * It is recommended that the original canvas also not be used until all + * canvases that have been created using its captured state have been dereferenced. + * + * Finally, it is important to note that any draw filters attached to the + * canvas are NOT currently captured. + * + * @param canvas The canvas you wish to capture the current state of. + * @return NULL or an opaque ptr that can be passed to CreateFromCanvasState + * to reconstruct the canvas. The caller is responsible for calling + * ReleaseCanvasState to free the memory associated with this state. + */ + static SkCanvasState* CaptureCanvasState(SkCanvas* canvas); + + /** + * Create a new SkCanvas from the captured state of another SkCanvas. The + * function will return NULL in the event that one of the + * following conditions are true. + * 1) the captured state is in an unrecognized format + * 2) the captured canvas device type is not supported + * + * @param state Opaque object created by CaptureCanvasState. + * @return NULL or an SkCanvas* whose devices and matrix/clip state are + * identical to the captured canvas. The caller is responsible for + * calling unref on the SkCanvas. + */ + static std::unique_ptr MakeFromCanvasState(const SkCanvasState* state); + + /** + * Free the memory associated with the captured canvas state. The state + * should not be released until all SkCanvas objects created using that + * state have been dereferenced. Must be called from the same library + * instance that created the state via CaptureCanvasState. + * + * @param state The captured state you wish to dispose of. + */ + static void ReleaseCanvasState(SkCanvasState* state); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCustomTypeface.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCustomTypeface.h new file mode 100644 index 00000000000000..d387fb24ca6bc9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkCustomTypeface.h @@ -0,0 +1,69 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCustomTypeface_DEFINED +#define SkCustomTypeface_DEFINED + +#include "include/core/SkDrawable.h" +#include "include/core/SkFontMetrics.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkPath.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkStream; +class SkStreamAsset; +struct SkFontArguments; + +class SK_API SkCustomTypefaceBuilder { +public: + SkCustomTypefaceBuilder(); + + void setGlyph(SkGlyphID, float advance, const SkPath&); + void setGlyph(SkGlyphID, float advance, sk_sp, const SkRect& bounds); + + void setMetrics(const SkFontMetrics& fm, float scale = 1); + void setFontStyle(SkFontStyle); + + sk_sp detach(); + + static constexpr SkTypeface::FactoryId FactoryId = SkSetFourByteTag('u','s','e','r'); + static sk_sp MakeFromStream(std::unique_ptr, const SkFontArguments&); + +private: + struct GlyphRec { + // logical union + SkPath fPath; + sk_sp fDrawable; + + SkRect fBounds = {0,0,0,0}; // only used for drawable glyphs atm + float fAdvance = 0; + + bool isDrawable() const { + SkASSERT(!fDrawable || fPath.isEmpty()); + return fDrawable != nullptr; + } + }; + + std::vector fGlyphRecs; + SkFontMetrics fMetrics; + SkFontStyle fStyle; + + GlyphRec& ensureStorage(SkGlyphID); + + static sk_sp Deserialize(SkStream*); + + friend class SkTypeface; + friend class SkUserTypeface; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkEventTracer.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkEventTracer.h new file mode 100644 index 00000000000000..2ec0a3b3554f2f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkEventTracer.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Google Inc. All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEventTracer_DEFINED +#define SkEventTracer_DEFINED + +// The class in this header defines the interface between Skia's internal +// tracing macros and an external entity (e.g., Chrome) that will consume them. +// Such an entity should subclass SkEventTracer and provide an instance of +// that event to SkEventTracer::SetInstance. + +// If you're looking for the tracing macros to instrument Skia itself, those +// live in src/core/SkTraceEvent.h + +#include "include/core/SkTypes.h" + +#include + +class SK_API SkEventTracer { +public: + + typedef uint64_t Handle; + + /** + * If this is the first call to SetInstance or GetInstance then the passed instance is + * installed and true is returned. Otherwise, false is returned. In either case ownership of the + * tracer is transferred and it will be deleted when no longer needed. + * + * Not deleting the tracer on process exit should not cause problems as + * the whole heap is about to go away with the process. This can also + * improve performance by reducing the amount of work needed. + * + * @param leakTracer Do not delete tracer on process exit. + */ + static bool SetInstance(SkEventTracer*, bool leakTracer = false); + + /** + * Gets the event tracer. If this is the first call to SetInstance or GetIntance then a default + * event tracer is installed and returned. + */ + static SkEventTracer* GetInstance(); + + virtual ~SkEventTracer() = default; + + // The pointer returned from GetCategoryGroupEnabled() points to a + // value with zero or more of the following bits. Used in this class only. + // The TRACE_EVENT macros should only use the value as a bool. + // These values must be in sync with macro values in trace_event.h in chromium. + enum CategoryGroupEnabledFlags { + // Category group enabled for the recording mode. + kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0, + // Category group enabled for the monitoring mode. + kEnabledForMonitoring_CategoryGroupEnabledFlags = 1 << 1, + // Category group enabled by SetEventCallbackEnabled(). + kEnabledForEventCallback_CategoryGroupEnabledFlags = 1 << 2, + }; + + virtual const uint8_t* getCategoryGroupEnabled(const char* name) = 0; + virtual const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) = 0; + + virtual SkEventTracer::Handle + addTraceEvent(char phase, + const uint8_t* categoryEnabledFlag, + const char* name, + uint64_t id, + int32_t numArgs, + const char** argNames, + const uint8_t* argTypes, + const uint64_t* argValues, + uint8_t flags) = 0; + + virtual void + updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) = 0; + + // Optional method that can be implemented to allow splitting up traces into different sections. + virtual void newTracingSection(const char*) {} + +protected: + SkEventTracer() = default; + SkEventTracer(const SkEventTracer&) = delete; + SkEventTracer& operator=(const SkEventTracer&) = delete; +}; + +#endif // SkEventTracer_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNWayCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNWayCanvas.h new file mode 100644 index 00000000000000..87c6916b39f09c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNWayCanvas.h @@ -0,0 +1,133 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkNWayCanvas_DEFINED +#define SkNWayCanvas_DEFINED + +#include "include/core/SkCanvasVirtualEnforcer.h" +#include "include/core/SkColor.h" +#include "include/core/SkM44.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTDArray.h" +#include "include/utils/SkNoDrawCanvas.h" + +#include + +namespace sktext { +class GlyphRunList; +} + +class SkCanvas; +class SkData; +class SkDrawable; +class SkImage; +class SkMatrix; +class SkPaint; +class SkPath; +class SkPicture; +class SkRRect; +class SkRegion; +class SkShader; +class SkTextBlob; +class SkVertices; +enum class SkBlendMode; +enum class SkClipOp; +struct SkDrawShadowRec; +struct SkPoint; +struct SkRSXform; +struct SkRect; + +#if defined(SK_GANESH) +namespace sktext::gpu { +class Slug; +} +#endif + +class SK_API SkNWayCanvas : public SkCanvasVirtualEnforcer { +public: + SkNWayCanvas(int width, int height); + ~SkNWayCanvas() override; + + virtual void addCanvas(SkCanvas*); + virtual void removeCanvas(SkCanvas*); + virtual void removeAll(); + +protected: + SkTDArray fList; + + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + bool onDoSaveBehind(const SkRect*) override; + void willRestore() override; + + void didConcat44(const SkM44&) override; + void didSetM44(const SkM44&) override; + void didScale(SkScalar, SkScalar) override; + void didTranslate(SkScalar, SkScalar) override; + + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawGlyphRunList(const sktext::GlyphRunList&, const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; +#if defined(SK_GANESH) + void onDrawSlug(const sktext::gpu::Slug* slug) override; +#endif + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawBehind(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + + void onDrawImage2(const SkImage*, SkScalar, SkScalar, const SkSamplingOptions&, + const SkPaint*) override; + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, + const SkPaint*, SrcRectConstraint) override; + void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect&, SkFilterMode, + const SkPaint*) override; + void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override; + + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipShader(sk_sp, SkClipOp) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + void onResetClip() override; + + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], QuadAAFlags, const SkColor4f&, + SkBlendMode) override; + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int count, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&,const SkPaint*, SrcRectConstraint) override; + + void onFlush() override; + + class Iter; + +private: + using INHERITED = SkCanvasVirtualEnforcer; +}; + + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNoDrawCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNoDrawCanvas.h new file mode 100644 index 00000000000000..3f2563873858c0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNoDrawCanvas.h @@ -0,0 +1,80 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkNoDrawCanvas_DEFINED +#define SkNoDrawCanvas_DEFINED + +#include "include/core/SkCanvas.h" +#include "include/core/SkCanvasVirtualEnforcer.h" + +struct SkIRect; + +// SkNoDrawCanvas is a helper for SkCanvas subclasses which do not need to +// actually rasterize (e.g., analysis of the draw calls). +// +// It provides the following simplifications: +// +// * not backed by any device/pixels +// * conservative clipping (clipping calls only use rectangles) +// +class SK_API SkNoDrawCanvas : public SkCanvasVirtualEnforcer { +public: + SkNoDrawCanvas(int width, int height); + SkNoDrawCanvas(const SkIRect&); + + explicit SkNoDrawCanvas(sk_sp device); + + // Optimization to reset state to be the same as after construction. + void resetCanvas(int w, int h) { this->resetForNextPicture(SkIRect::MakeWH(w, h)); } + void resetCanvas(const SkIRect& rect) { this->resetForNextPicture(rect); } + +protected: + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; + bool onDoSaveBehind(const SkRect*) override; + + // No-op overrides for aborting rasterization earlier than SkNullBlitter. + void onDrawAnnotation(const SkRect&, const char[], SkData*) override {} + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override {} + void onDrawDrawable(SkDrawable*, const SkMatrix*) override {} + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override {} + void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&) override {} + + void onDrawPaint(const SkPaint&) override {} + void onDrawBehind(const SkPaint&) override {} + void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override {} + void onDrawRect(const SkRect&, const SkPaint&) override {} + void onDrawRegion(const SkRegion&, const SkPaint&) override {} + void onDrawOval(const SkRect&, const SkPaint&) override {} + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override {} + void onDrawRRect(const SkRRect&, const SkPaint&) override {} + void onDrawPath(const SkPath&, const SkPaint&) override {} + + void onDrawImage2(const SkImage*, SkScalar, SkScalar, const SkSamplingOptions&, + const SkPaint*) override {} + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, + const SkPaint*, SrcRectConstraint) override {} + void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect&, SkFilterMode, + const SkPaint*) override {} + void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override {} + + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override {} + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override {} + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override {} + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], QuadAAFlags, const SkColor4f&, + SkBlendMode) override {} + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint) override {} + +private: + using INHERITED = SkCanvasVirtualEnforcer; +}; + +#endif // SkNoDrawCanvas_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNullCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNullCanvas.h new file mode 100644 index 00000000000000..a77e3e3de9bb80 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkNullCanvas.h @@ -0,0 +1,22 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkNullCanvas_DEFINED +#define SkNullCanvas_DEFINED + +#include "include/core/SkTypes.h" + +#include + +class SkCanvas; + +/** + * Creates a canvas that draws nothing. This is useful for performance testing. + */ +SK_API std::unique_ptr SkMakeNullCanvas(); + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkOrderedFontMgr.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkOrderedFontMgr.h new file mode 100644 index 00000000000000..0b686e5edc5af2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkOrderedFontMgr.h @@ -0,0 +1,66 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOrderedFontMgr_DEFINED +#define SkOrderedFontMgr_DEFINED + +#include "include/core/SkFontMgr.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkData; +class SkFontStyle; +class SkStreamAsset; +class SkString; +class SkTypeface; +struct SkFontArguments; + +/** + * Collects an order list of other font managers, and visits them in order + * when a request to find or match is issued. + * + * Note: this explicitly fails on any attempt to Make a typeface: all of + * those requests will return null. + */ +class SK_API SkOrderedFontMgr : public SkFontMgr { +public: + SkOrderedFontMgr(); + ~SkOrderedFontMgr() override; + + void append(sk_sp); + +protected: + int onCountFamilies() const override; + void onGetFamilyName(int index, SkString* familyName) const override; + sk_sp onCreateStyleSet(int index)const override; + + sk_sp onMatchFamily(const char familyName[]) const override; + + sk_sp onMatchFamilyStyle(const char familyName[], + const SkFontStyle&) const override; + sk_sp onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const override; + + // Note: all of these always return null + sk_sp onMakeFromData(sk_sp, int ttcIndex) const override; + sk_sp onMakeFromStreamIndex(std::unique_ptr, + int ttcIndex) const override; + sk_sp onMakeFromStreamArgs(std::unique_ptr, + const SkFontArguments&) const override; + sk_sp onMakeFromFile(const char path[], int ttcIndex) const override; + + sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override; + +private: + std::vector> fList; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkPaintFilterCanvas.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkPaintFilterCanvas.h new file mode 100644 index 00000000000000..9a836bc7c2551a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkPaintFilterCanvas.h @@ -0,0 +1,141 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPaintFilterCanvas_DEFINED +#define SkPaintFilterCanvas_DEFINED + +#include "include/core/SkCanvas.h" +#include "include/core/SkCanvasVirtualEnforcer.h" +#include "include/core/SkColor.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTDArray.h" +#include "include/utils/SkNWayCanvas.h" + +#include + +namespace sktext { +class GlyphRunList; +} + +class GrRecordingContext; +class SkData; +class SkDrawable; +class SkImage; +class SkMatrix; +class SkPaint; +class SkPath; +class SkPicture; +class SkPixmap; +class SkRRect; +class SkRegion; +class SkSurface; +class SkSurfaceProps; +class SkTextBlob; +class SkVertices; +enum class SkBlendMode; +struct SkDrawShadowRec; +struct SkPoint; +struct SkRSXform; +struct SkRect; + +/** \class SkPaintFilterCanvas + + A utility proxy base class for implementing draw/paint filters. +*/ +class SK_API SkPaintFilterCanvas : public SkCanvasVirtualEnforcer { +public: + /** + * The new SkPaintFilterCanvas is configured for forwarding to the + * specified canvas. Also copies the target canvas matrix and clip bounds. + */ + SkPaintFilterCanvas(SkCanvas* canvas); + + enum Type { + kPicture_Type, + }; + + // Forwarded to the wrapped canvas. + SkISize getBaseLayerSize() const override { return proxy()->getBaseLayerSize(); } + GrRecordingContext* recordingContext() override { return proxy()->recordingContext(); } + +protected: + /** + * Called with the paint that will be used to draw the specified type. + * The implementation may modify the paint as they wish. + * + * The result bool is used to determine whether the draw op is to be + * executed (true) or skipped (false). + * + * Note: The base implementation calls onFilter() for top-level/explicit paints only. + * To also filter encapsulated paints (e.g. SkPicture, SkTextBlob), clients may need to + * override the relevant methods (i.e. drawPicture, drawTextBlob). + */ + virtual bool onFilter(SkPaint& paint) const = 0; + + void onDrawPaint(const SkPaint&) override; + void onDrawBehind(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + + void onDrawImage2(const SkImage*, SkScalar, SkScalar, const SkSamplingOptions&, + const SkPaint*) override; + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, + const SkPaint*, SrcRectConstraint) override; + void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect&, SkFilterMode, + const SkPaint*) override; + void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override; + + void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, + const SkPaint& paint) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + + void onDrawGlyphRunList(const sktext::GlyphRunList&, const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override; + void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override; + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], QuadAAFlags, const SkColor4f&, + SkBlendMode) override; + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int count, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&,const SkPaint*, SrcRectConstraint) override; + + // Forwarded to the wrapped canvas. + sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + bool onPeekPixels(SkPixmap* pixmap) override; + bool onAccessTopLayerPixels(SkPixmap* pixmap) override; + SkImageInfo onImageInfo() const override; + bool onGetProps(SkSurfaceProps* props, bool top) const override; + +private: + class AutoPaintFilter; + + SkCanvas* proxy() const { SkASSERT(fList.size() == 1); return fList[0]; } + + SkPaintFilterCanvas* internal_private_asPaintFilterCanvas() const override { + return const_cast(this); + } + + friend class SkAndroidFrameworkUtils; +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkParse.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkParse.h new file mode 100644 index 00000000000000..bcabc3c793ac18 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkParse.h @@ -0,0 +1,37 @@ + +/* + * 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 SkParse_DEFINED +#define SkParse_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SK_API SkParse { +public: + static int Count(const char str[]); // number of scalars or int values + static int Count(const char str[], char separator); + static const char* FindColor(const char str[], SkColor* value); + static const char* FindHex(const char str[], uint32_t* value); + static const char* FindMSec(const char str[], SkMSec* value); + static const char* FindNamedColor(const char str[], size_t len, SkColor* color); + static const char* FindS32(const char str[], int32_t* value); + static const char* FindScalar(const char str[], SkScalar* value); + static const char* FindScalars(const char str[], SkScalar value[], int count); + + static bool FindBool(const char str[], bool* value); + // return the index of str in list[], or -1 if not found + static int FindList(const char str[], const char list[]); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkParsePath.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkParsePath.h new file mode 100644 index 00000000000000..acd0ef2305c038 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkParsePath.h @@ -0,0 +1,25 @@ + +/* + * 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 SkParsePath_DEFINED +#define SkParsePath_DEFINED + +#include "include/core/SkPath.h" + +class SkString; + +class SK_API SkParsePath { +public: + static bool FromSVGString(const char str[], SkPath*); + + enum class PathEncoding { Absolute, Relative }; + static SkString ToSVGString(const SkPath&, PathEncoding = PathEncoding::Absolute); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkShadowUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkShadowUtils.h new file mode 100644 index 00000000000000..b7c43d569f89cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkShadowUtils.h @@ -0,0 +1,88 @@ + +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkShadowUtils_DEFINED +#define SkShadowUtils_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/SkShadowFlags.h" + +#include + +class SkCanvas; +class SkMatrix; +class SkPath; +struct SkPoint3; +struct SkRect; + +class SK_API SkShadowUtils { +public: + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. The shadow may be cached, depending on the path type and canvas matrix. If the + * matrix is perspective or the path is volatile, it will not be cached. + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param zPlaneParams Values for the plane function which returns the Z offset of the + * occluder from the canvas based on local x and y values (the current matrix is not applied). + * @param lightPos Generally, the 3D position of the light relative to the canvas plane. + * If kDirectionalLight_ShadowFlag is set, this specifies a vector pointing + * towards the light. + * @param lightRadius Generally, the radius of the disc light. + * If DirectionalLight_ShadowFlag is set, this specifies the amount of + * blur when the occluder is at Z offset == 1. The blur will grow linearly + * as the Z value increases. + * @param ambientColor The color of the ambient shadow. + * @param spotColor The color of the spot shadow. + * @param flags Options controlling opaque occluder optimizations, shadow appearance, + * and light position. See SkShadowFlags. + */ + static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams, + const SkPoint3& lightPos, SkScalar lightRadius, + SkColor ambientColor, SkColor spotColor, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag); + + /** + * Generate bounding box for shadows relative to path. Includes both the ambient and spot + * shadow bounds. + * + * @param ctm Current transformation matrix to device space. + * @param path The occluder used to generate the shadows. + * @param zPlaneParams Values for the plane function which returns the Z offset of the + * occluder from the canvas based on local x and y values (the current matrix is not applied). + * @param lightPos Generally, the 3D position of the light relative to the canvas plane. + * If kDirectionalLight_ShadowFlag is set, this specifies a vector pointing + * towards the light. + * @param lightRadius Generally, the radius of the disc light. + * If DirectionalLight_ShadowFlag is set, this specifies the amount of + * blur when the occluder is at Z offset == 1. The blur will grow linearly + * as the Z value increases. + * @param flags Options controlling opaque occluder optimizations, shadow appearance, + * and light position. See SkShadowFlags. + * @param bounds Return value for shadow bounding box. + * @return Returns true if successful, false otherwise. + */ + static bool GetLocalBounds(const SkMatrix& ctm, const SkPath& path, + const SkPoint3& zPlaneParams, const SkPoint3& lightPos, + SkScalar lightRadius, uint32_t flags, SkRect* bounds); + + /** + * Helper routine to compute color values for one-pass tonal alpha. + * + * @param inAmbientColor Original ambient color + * @param inSpotColor Original spot color + * @param outAmbientColor Modified ambient color + * @param outSpotColor Modified spot color + */ + static void ComputeTonalColors(SkColor inAmbientColor, SkColor inSpotColor, + SkColor* outAmbientColor, SkColor* outSpotColor); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkTextUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkTextUtils.h new file mode 100644 index 00000000000000..b73ab771e8312d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkTextUtils.h @@ -0,0 +1,43 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTextUtils_DEFINED +#define SkTextUtils_DEFINED + +#include "include/core/SkFontTypes.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkCanvas; +class SkFont; +class SkPaint; +class SkPath; + +class SK_API SkTextUtils { +public: + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + }; + + static void Draw(SkCanvas*, const void* text, size_t size, SkTextEncoding, + SkScalar x, SkScalar y, const SkFont&, const SkPaint&, Align = kLeft_Align); + + static void DrawString(SkCanvas* canvas, const char text[], SkScalar x, SkScalar y, + const SkFont& font, const SkPaint& paint, Align align = kLeft_Align) { + Draw(canvas, text, strlen(text), SkTextEncoding::kUTF8, x, y, font, paint, align); + } + + static void GetPath(const void* text, size_t length, SkTextEncoding, SkScalar x, SkScalar y, + const SkFont&, SkPath*); +}; + +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkTraceEventPhase.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkTraceEventPhase.h new file mode 100644 index 00000000000000..38457be24b4079 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/SkTraceEventPhase.h @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef SkTraceEventPhase_DEFINED +#define SkTraceEventPhase_DEFINED + +// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. +#define TRACE_EVENT_PHASE_BEGIN ('B') +#define TRACE_EVENT_PHASE_END ('E') +#define TRACE_EVENT_PHASE_COMPLETE ('X') +#define TRACE_EVENT_PHASE_INSTANT ('I') +#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') +#define TRACE_EVENT_PHASE_ASYNC_END ('F') +#define TRACE_EVENT_PHASE_COUNTER ('C') +#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N') +#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O') +#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D') + +#endif // SkTraceEventPhase_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/mac/SkCGUtils.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/mac/SkCGUtils.h new file mode 100644 index 00000000000000..a320dd8d4c9d24 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/include/utils/mac/SkCGUtils.h @@ -0,0 +1,78 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkCGUtils_DEFINED +#define SkCGUtils_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkSize.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#include +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +class SkBitmap; +class SkData; +class SkPixmap; +class SkStreamRewindable; + +SK_API CGContextRef SkCreateCGContext(const SkPixmap&); + +/** + * Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not + * null, use it to determine the size of the bitmap, and scale the image to fill the bitmap. + * Otherwise use the image's width/height. + * + * On failure, return false, and leave bitmap unchanged. + */ +SK_API bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef src); + +SK_API sk_sp SkMakeImageFromCGImage(CGImageRef); + +/** + * Copy the pixels from src into the memory specified by info/rowBytes/dstPixels. On failure, + * return false (e.g. ImageInfo incompatible with src). + */ +SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* dstPixels, + CGImageRef src); +static inline bool SkCopyPixelsFromCGImage(const SkPixmap& dst, CGImageRef src) { + return SkCopyPixelsFromCGImage(dst.info(), dst.rowBytes(), dst.writable_addr(), src); +} + +/** + * Create an imageref from the specified bitmap using the specified colorspace. + * If space is NULL, then CGColorSpaceCreateDeviceRGB() is used. + */ +SK_API CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, + CGColorSpaceRef space); + +/** + * Create an imageref from the specified bitmap using the colorspace returned + * by CGColorSpaceCreateDeviceRGB() + */ +static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) { + return SkCreateCGImageRefWithColorspace(bm, nil); +} + +/** + * Draw the bitmap into the specified CG context. The bitmap will be converted + * to a CGImage using the generic RGB colorspace. (x,y) specifies the position + * of the top-left corner of the bitmap. The bitmap is converted using the + * colorspace returned by CGColorSpaceCreateDeviceRGB() + */ +void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y); + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkCGUtils_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/skcms.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/skcms.h new file mode 100644 index 00000000000000..322549b38f7ed4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/skcms.h @@ -0,0 +1,418 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#pragma once + +// skcms.h contains the entire public API for skcms. + +#ifndef SKCMS_API + #define SKCMS_API +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// A row-major 3x3 matrix (ie vals[row][col]) +typedef struct skcms_Matrix3x3 { + float vals[3][3]; +} skcms_Matrix3x3; + +// It is _not_ safe to alias the pointers to invert in-place. +SKCMS_API bool skcms_Matrix3x3_invert(const skcms_Matrix3x3*, skcms_Matrix3x3*); +SKCMS_API skcms_Matrix3x3 skcms_Matrix3x3_concat(const skcms_Matrix3x3*, const skcms_Matrix3x3*); + +// A row-major 3x4 matrix (ie vals[row][col]) +typedef struct skcms_Matrix3x4 { + float vals[3][4]; +} skcms_Matrix3x4; + +// A transfer function mapping encoded values to linear values, +// represented by this 7-parameter piecewise function: +// +// linear = sign(encoded) * (c*|encoded| + f) , 0 <= |encoded| < d +// = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded| +// +// (A simple gamma transfer function sets g to gamma and a to 1.) +typedef struct skcms_TransferFunction { + float g, a,b,c,d,e,f; +} skcms_TransferFunction; + +SKCMS_API float skcms_TransferFunction_eval (const skcms_TransferFunction*, float); +SKCMS_API bool skcms_TransferFunction_invert(const skcms_TransferFunction*, + skcms_TransferFunction*); + +typedef enum skcms_TFType { + skcms_TFType_Invalid, + skcms_TFType_sRGBish, + skcms_TFType_PQish, + skcms_TFType_HLGish, + skcms_TFType_HLGinvish, +} skcms_TFType; + +// Identify which kind of transfer function is encoded in an skcms_TransferFunction +SKCMS_API skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction*); + +// We can jam a couple alternate transfer function forms into skcms_TransferFunction, +// including those matching the general forms of the SMPTE ST 2084 PQ function or HLG. +// +// PQish: +// max(A + B|encoded|^C, 0) +// linear = sign(encoded) * (------------------------) ^ F +// D + E|encoded|^C +SKCMS_API bool skcms_TransferFunction_makePQish(skcms_TransferFunction*, + float A, float B, float C, + float D, float E, float F); +// HLGish: +// { K * sign(encoded) * ( (R|encoded|)^G ) when 0 <= |encoded| <= 1/R +// linear = { K * sign(encoded) * ( e^(a(|encoded|-c)) + b ) when 1/R < |encoded| +SKCMS_API bool skcms_TransferFunction_makeScaledHLGish(skcms_TransferFunction*, + float K, float R, float G, + float a, float b, float c); + +// Compatibility shim with K=1 for old callers. +static inline bool skcms_TransferFunction_makeHLGish(skcms_TransferFunction* fn, + float R, float G, + float a, float b, float c) { + return skcms_TransferFunction_makeScaledHLGish(fn, 1.0f, R,G, a,b,c); +} + +// PQ mapping encoded [0,1] to linear [0,1]. +static inline bool skcms_TransferFunction_makePQ(skcms_TransferFunction* tf) { + return skcms_TransferFunction_makePQish(tf, -107/128.0f, 1.0f, 32/2523.0f + , 2413/128.0f, -2392/128.0f, 8192/1305.0f); +} +// HLG mapping encoded [0,1] to linear [0,12]. +static inline bool skcms_TransferFunction_makeHLG(skcms_TransferFunction* tf) { + return skcms_TransferFunction_makeHLGish(tf, 2.0f, 2.0f + , 1/0.17883277f, 0.28466892f, 0.55991073f); +} + +// Is this an ordinary sRGB-ish transfer function, or one of the HDR forms we support? +SKCMS_API bool skcms_TransferFunction_isSRGBish(const skcms_TransferFunction*); +SKCMS_API bool skcms_TransferFunction_isPQish (const skcms_TransferFunction*); +SKCMS_API bool skcms_TransferFunction_isHLGish (const skcms_TransferFunction*); + +// Unified representation of 'curv' or 'para' tag data, or a 1D table from 'mft1' or 'mft2' +typedef union skcms_Curve { + struct { + uint32_t alias_of_table_entries; + skcms_TransferFunction parametric; + }; + struct { + uint32_t table_entries; + const uint8_t* table_8; + const uint8_t* table_16; + }; +} skcms_Curve; + +// Complex transforms between device space (A) and profile connection space (B): +// A2B: device -> [ "A" curves -> CLUT ] -> [ "M" curves -> matrix ] -> "B" curves -> PCS +// B2A: device <- [ "A" curves <- CLUT ] <- [ "M" curves <- matrix ] <- "B" curves <- PCS + +typedef struct skcms_A2B { + // Optional: N 1D "A" curves, followed by an N-dimensional CLUT. + // If input_channels == 0, these curves and CLUT are skipped, + // Otherwise, input_channels must be in [1, 4]. + uint32_t input_channels; + skcms_Curve input_curves[4]; + uint8_t grid_points[4]; + const uint8_t* grid_8; + const uint8_t* grid_16; + + // Optional: 3 1D "M" curves, followed by a color matrix. + // If matrix_channels == 0, these curves and matrix are skipped, + // Otherwise, matrix_channels must be 3. + uint32_t matrix_channels; + skcms_Curve matrix_curves[3]; + skcms_Matrix3x4 matrix; + + // Required: 3 1D "B" curves. Always present, and output_channels must be 3. + uint32_t output_channels; + skcms_Curve output_curves[3]; +} skcms_A2B; + +typedef struct skcms_B2A { + // Required: 3 1D "B" curves. Always present, and input_channels must be 3. + uint32_t input_channels; + skcms_Curve input_curves[3]; + + // Optional: a color matrix, followed by 3 1D "M" curves. + // If matrix_channels == 0, this matrix and these curves are skipped, + // Otherwise, matrix_channels must be 3. + uint32_t matrix_channels; + skcms_Matrix3x4 matrix; + skcms_Curve matrix_curves[3]; + + // Optional: an N-dimensional CLUT, followed by N 1D "A" curves. + // If output_channels == 0, this CLUT and these curves are skipped, + // Otherwise, output_channels must be in [1, 4]. + uint32_t output_channels; + uint8_t grid_points[4]; + const uint8_t* grid_8; + const uint8_t* grid_16; + skcms_Curve output_curves[4]; +} skcms_B2A; + +typedef struct skcms_CICP { + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint8_t video_full_range_flag; +} skcms_CICP; + +typedef struct skcms_ICCProfile { + const uint8_t* buffer; + + uint32_t size; + uint32_t data_color_space; + uint32_t pcs; + uint32_t tag_count; + + // skcms_Parse() will set commonly-used fields for you when possible: + + // If we can parse red, green and blue transfer curves from the profile, + // trc will be set to those three curves, and has_trc will be true. + bool has_trc; + skcms_Curve trc[3]; + + // If this profile's gamut can be represented by a 3x3 transform to XYZD50, + // skcms_Parse() sets toXYZD50 to that transform and has_toXYZD50 to true. + bool has_toXYZD50; + skcms_Matrix3x3 toXYZD50; + + // If the profile has a valid A2B0 or A2B1 tag, skcms_Parse() sets A2B to + // that data, and has_A2B to true. skcms_ParseWithA2BPriority() does the + // same following any user-provided prioritization of A2B0, A2B1, or A2B2. + bool has_A2B; + skcms_A2B A2B; + + // If the profile has a valid B2A0 or B2A1 tag, skcms_Parse() sets B2A to + // that data, and has_B2A to true. skcms_ParseWithA2BPriority() does the + // same following any user-provided prioritization of B2A0, B2A1, or B2A2. + bool has_B2A; + skcms_B2A B2A; + + // If the profile has a valid CICP tag, skcms_Parse() sets CICP to that data, + // and has_CICP to true. + bool has_CICP; + skcms_CICP CICP; +} skcms_ICCProfile; + +// The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it. +SKCMS_API const skcms_ICCProfile* skcms_sRGB_profile(void); +// Ditto for XYZD50, the most common profile connection space. +SKCMS_API const skcms_ICCProfile* skcms_XYZD50_profile(void); + +SKCMS_API const skcms_TransferFunction* skcms_sRGB_TransferFunction(void); +SKCMS_API const skcms_TransferFunction* skcms_sRGB_Inverse_TransferFunction(void); +SKCMS_API const skcms_TransferFunction* skcms_Identity_TransferFunction(void); + +// Practical equality test for two skcms_ICCProfiles. +// The implementation is subject to change, but it will always try to answer +// "can I substitute A for B?" and "can I skip transforming from A to B?". +SKCMS_API bool skcms_ApproximatelyEqualProfiles(const skcms_ICCProfile* A, + const skcms_ICCProfile* B); + +// Practical test that answers: Is curve roughly the inverse of inv_tf? Typically used by passing +// the inverse of a known parametric transfer function (like sRGB), to determine if a particular +// curve is very close to sRGB. +SKCMS_API bool skcms_AreApproximateInverses(const skcms_Curve* curve, + const skcms_TransferFunction* inv_tf); + +// Similar to above, answering the question for all three TRC curves of the given profile. Again, +// passing skcms_sRGB_InverseTransferFunction as inv_tf will answer the question: +// "Does this profile have a transfer function that is very close to sRGB?" +SKCMS_API bool skcms_TRCs_AreApproximateInverse(const skcms_ICCProfile* profile, + const skcms_TransferFunction* inv_tf); + +// Parse an ICC profile and return true if possible, otherwise return false. +// Selects an A2B profile (if present) according to priority list (each entry 0-2). +// The buffer is not copied; it must remain valid as long as the skcms_ICCProfile will be used. +SKCMS_API bool skcms_ParseWithA2BPriority(const void*, size_t, + const int priority[], int priorities, + skcms_ICCProfile*); + +static inline bool skcms_Parse(const void* buf, size_t len, skcms_ICCProfile* profile) { + // For continuity of existing user expectations, + // prefer A2B0 (perceptual) over A2B1 (relative colormetric), and ignore A2B2 (saturation). + const int priority[] = {0,1}; + return skcms_ParseWithA2BPriority(buf, len, + priority, sizeof(priority)/sizeof(*priority), + profile); +} + +SKCMS_API bool skcms_ApproximateCurve(const skcms_Curve* curve, + skcms_TransferFunction* approx, + float* max_error); + +SKCMS_API bool skcms_GetCHAD(const skcms_ICCProfile*, skcms_Matrix3x3*); +SKCMS_API bool skcms_GetWTPT(const skcms_ICCProfile*, float xyz[3]); + +// These are common ICC signature values +enum { + // data_color_space + skcms_Signature_CMYK = 0x434D594B, + skcms_Signature_Gray = 0x47524159, + skcms_Signature_RGB = 0x52474220, + + // pcs + skcms_Signature_Lab = 0x4C616220, + skcms_Signature_XYZ = 0x58595A20, +}; + +typedef enum skcms_PixelFormat { + skcms_PixelFormat_A_8, + skcms_PixelFormat_A_8_, + skcms_PixelFormat_G_8, + skcms_PixelFormat_G_8_, + skcms_PixelFormat_RGBA_8888_Palette8, + skcms_PixelFormat_BGRA_8888_Palette8, + + skcms_PixelFormat_RGB_565, + skcms_PixelFormat_BGR_565, + + skcms_PixelFormat_ABGR_4444, + skcms_PixelFormat_ARGB_4444, + + skcms_PixelFormat_RGB_888, + skcms_PixelFormat_BGR_888, + skcms_PixelFormat_RGBA_8888, + skcms_PixelFormat_BGRA_8888, + skcms_PixelFormat_RGBA_8888_sRGB, // Automatic sRGB encoding / decoding. + skcms_PixelFormat_BGRA_8888_sRGB, // (Generally used with linear transfer functions.) + + skcms_PixelFormat_RGBA_1010102, + skcms_PixelFormat_BGRA_1010102, + + skcms_PixelFormat_RGB_161616LE, // Little-endian. Pointers must be 16-bit aligned. + skcms_PixelFormat_BGR_161616LE, + skcms_PixelFormat_RGBA_16161616LE, + skcms_PixelFormat_BGRA_16161616LE, + + skcms_PixelFormat_RGB_161616BE, // Big-endian. Pointers must be 16-bit aligned. + skcms_PixelFormat_BGR_161616BE, + skcms_PixelFormat_RGBA_16161616BE, + skcms_PixelFormat_BGRA_16161616BE, + + skcms_PixelFormat_RGB_hhh_Norm, // 1-5-10 half-precision float in [0,1] + skcms_PixelFormat_BGR_hhh_Norm, // Pointers must be 16-bit aligned. + skcms_PixelFormat_RGBA_hhhh_Norm, + skcms_PixelFormat_BGRA_hhhh_Norm, + + skcms_PixelFormat_RGB_hhh, // 1-5-10 half-precision float. + skcms_PixelFormat_BGR_hhh, // Pointers must be 16-bit aligned. + skcms_PixelFormat_RGBA_hhhh, + skcms_PixelFormat_BGRA_hhhh, + + skcms_PixelFormat_RGB_fff, // 1-8-23 single-precision float (the normal kind). + skcms_PixelFormat_BGR_fff, // Pointers must be 32-bit aligned. + skcms_PixelFormat_RGBA_ffff, + skcms_PixelFormat_BGRA_ffff, + + skcms_PixelFormat_RGB_101010x_XR, // Note: This is located here to signal no clamping. + skcms_PixelFormat_BGR_101010x_XR, // Compatible with MTLPixelFormatBGR10_XR. +} skcms_PixelFormat; + +// We always store any alpha channel linearly. In the chart below, tf-1() is the inverse +// transfer function for the given color profile (applying the transfer function linearizes). + +// We treat opaque as a strong requirement, not just a performance hint: we will ignore +// any source alpha and treat it as 1.0, and will make sure that any destination alpha +// channel is filled with the equivalent of 1.0. + +// We used to offer multiple types of premultiplication, but now just one, PremulAsEncoded. +// This is the premul you're probably used to working with. + +typedef enum skcms_AlphaFormat { + skcms_AlphaFormat_Opaque, // alpha is always opaque + // tf-1(r), tf-1(g), tf-1(b), 1.0 + skcms_AlphaFormat_Unpremul, // alpha and color are unassociated + // tf-1(r), tf-1(g), tf-1(b), a + skcms_AlphaFormat_PremulAsEncoded, // premultiplied while encoded + // tf-1(r)*a, tf-1(g)*a, tf-1(b)*a, a +} skcms_AlphaFormat; + +// Convert npixels pixels from src format and color profile to dst format and color profile +// and return true, otherwise return false. It is safe to alias dst == src if dstFmt == srcFmt. +SKCMS_API bool skcms_Transform(const void* src, + skcms_PixelFormat srcFmt, + skcms_AlphaFormat srcAlpha, + const skcms_ICCProfile* srcProfile, + void* dst, + skcms_PixelFormat dstFmt, + skcms_AlphaFormat dstAlpha, + const skcms_ICCProfile* dstProfile, + size_t npixels); + +// As skcms_Transform(), supporting srcFmts with a palette. +SKCMS_API bool skcms_TransformWithPalette(const void* src, + skcms_PixelFormat srcFmt, + skcms_AlphaFormat srcAlpha, + const skcms_ICCProfile* srcProfile, + void* dst, + skcms_PixelFormat dstFmt, + skcms_AlphaFormat dstAlpha, + const skcms_ICCProfile* dstProfile, + size_t npixels, + const void* palette); + +// If profile can be used as a destination in skcms_Transform, return true. Otherwise, attempt to +// rewrite it with approximations where reasonable. If successful, return true. If no reasonable +// approximation exists, leave the profile unchanged and return false. +SKCMS_API bool skcms_MakeUsableAsDestination(skcms_ICCProfile* profile); + +// If profile can be used as a destination with a single parametric transfer function (ie for +// rasterization), return true. Otherwise, attempt to rewrite it with approximations where +// reasonable. If successful, return true. If no reasonable approximation exists, leave the +// profile unchanged and return false. +SKCMS_API bool skcms_MakeUsableAsDestinationWithSingleCurve(skcms_ICCProfile* profile); + +// Returns a matrix to adapt XYZ color from given the whitepoint to D50. +SKCMS_API bool skcms_AdaptToXYZD50(float wx, float wy, + skcms_Matrix3x3* toXYZD50); + +// Returns a matrix to convert RGB color into XYZ adapted to D50, given the +// primaries and whitepoint of the RGB model. +SKCMS_API bool skcms_PrimariesToXYZD50(float rx, float ry, + float gx, float gy, + float bx, float by, + float wx, float wy, + skcms_Matrix3x3* toXYZD50); + +// Call before your first call to skcms_Transform() to skip runtime CPU detection. +SKCMS_API void skcms_DisableRuntimeCPUDetection(void); + +// Utilities for programmatically constructing profiles +static inline void skcms_Init(skcms_ICCProfile* p) { + memset(p, 0, sizeof(*p)); + p->data_color_space = skcms_Signature_RGB; + p->pcs = skcms_Signature_XYZ; +} + +static inline void skcms_SetTransferFunction(skcms_ICCProfile* p, + const skcms_TransferFunction* tf) { + p->has_trc = true; + for (int i = 0; i < 3; ++i) { + p->trc[i].table_entries = 0; + p->trc[i].parametric = *tf; + } +} + +static inline void skcms_SetXYZD50(skcms_ICCProfile* p, const skcms_Matrix3x3* m) { + p->has_toXYZD50 = true; + p->toXYZD50 = *m; +} + +#ifdef __cplusplus +} +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/skcms_internal.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/skcms_internal.h new file mode 100644 index 00000000000000..cc6d578ba07497 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/skcms_internal.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#pragma once + +// skcms_internal.h contains APIs shared by skcms' internals and its test tools. +// Please don't use this header from outside the skcms repo. + +#include "skcms.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// ~~~~ General Helper Macros ~~~~ + #define ARRAY_COUNT(arr) (int)(sizeof((arr)) / sizeof(*(arr))) + + typedef struct skcms_ICCTag { + uint32_t signature; + uint32_t type; + uint32_t size; + const uint8_t* buf; + } skcms_ICCTag; + + void skcms_GetTagByIndex (const skcms_ICCProfile*, uint32_t idx, skcms_ICCTag*); + bool skcms_GetTagBySignature(const skcms_ICCProfile*, uint32_t sig, skcms_ICCTag*); + + float skcms_MaxRoundtripError(const skcms_Curve* curve, const skcms_TransferFunction* inv_tf); + + // 252 of a random shuffle of all possible bytes. + // 252 is evenly divisible by 3 and 4. Only 192, 10, 241, and 43 are missing. + // Used for ICC profile equivalence testing. + extern const uint8_t skcms_252_random_bytes[252]; + +// ~~~~ Portable Math ~~~~ + static inline float floorf_(float x) { + float roundtrip = (float)((int)x); + return roundtrip > x ? roundtrip - 1 : roundtrip; + } + static inline float fabsf_(float x) { return x < 0 ? -x : x; } + float powf_(float, float); + +// ~~~~ Does this pixel format need a palette pointer to be usable? ~~~~ + static inline bool needs_palette(skcms_PixelFormat fmt) { + return (fmt >> 1) == (skcms_PixelFormat_RGBA_8888_Palette8 >> 1); + } + +#ifdef __cplusplus +} +#endif diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/src/Transform_inl.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/src/Transform_inl.h new file mode 100644 index 00000000000000..350f6a20a6c6be --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skcms/src/Transform_inl.h @@ -0,0 +1,1628 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// Intentionally NO #pragma once... included multiple times. + +// This file is included from skcms.cc in a namespace with some pre-defines: +// - N: depth of all vectors, 1,4,8, or 16 (preprocessor define) +// - V: a template to create a vector of N T's. + +using F = V; // Called F for historic reasons... maybe rename C? +using I32 = V; +using U64 = V; +using U32 = V; +using U16 = V; +using U8 = V; + + +#if defined(__GNUC__) && !defined(__clang__) + // Once again, GCC is kind of weird, not allowing vector = scalar directly. + static constexpr F F0 = F() + 0.0f, + F1 = F() + 1.0f, + FInfBits = F() + 0x7f800000; // equals 2139095040, the bit pattern of +Inf +#else + static constexpr F F0 = 0.0f, + F1 = 1.0f, + FInfBits = 0x7f800000; // equals 2139095040, the bit pattern of +Inf +#endif + +// Instead of checking __AVX__ below, we'll check USING_AVX. +// This lets skcms.cc set USING_AVX to force us in even if the compiler's not set that way. +// Same deal for __F16C__ and __AVX2__ ~~~> USING_AVX_F16C, USING_AVX2. + +#if !defined(USING_AVX) && N == 8 && defined(__AVX__) + #define USING_AVX +#endif +#if !defined(USING_AVX_F16C) && defined(USING_AVX) && defined(__F16C__) + #define USING AVX_F16C +#endif +#if !defined(USING_AVX2) && defined(USING_AVX) && defined(__AVX2__) + #define USING_AVX2 +#endif +#if !defined(USING_AVX512F) && N == 16 && defined(__AVX512F__) && defined(__AVX512DQ__) + #define USING_AVX512F +#endif + +// Similar to the AVX+ features, we define USING_NEON and USING_NEON_F16C. +// This is more for organizational clarity... skcms.cc doesn't force these. +#if N > 1 && defined(__ARM_NEON) + #define USING_NEON + #if __ARM_FP & 2 + #define USING_NEON_F16C + #endif + #if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(SKCMS_OPT_INTO_NEON_FP16) + #define USING_NEON_FP16 + #endif +#endif + +// These -Wvector-conversion warnings seem to trigger in very bogus situations, +// like vst3q_f32() expecting a 16x char rather than a 4x float vector. :/ +#if defined(USING_NEON) && defined(__clang__) + #pragma clang diagnostic ignored "-Wvector-conversion" +#endif + +// GCC & Clang (but not clang-cl) warn returning U64 on x86 is larger than a register. +// You'd see warnings like, "using AVX even though AVX is not enabled". +// We stifle these warnings; our helpers that return U64 are always inlined. +#if defined(__SSE__) && defined(__GNUC__) + #if !defined(__has_warning) + #pragma GCC diagnostic ignored "-Wpsabi" + #elif __has_warning("-Wpsabi") + #pragma GCC diagnostic ignored "-Wpsabi" + #endif +#endif + +#if defined(__clang__) + #define FALLTHROUGH [[clang::fallthrough]] +#else + #define FALLTHROUGH +#endif + +// We tag most helper functions as SI, to enforce good code generation +// but also work around what we think is a bug in GCC: when targeting 32-bit +// x86, GCC tends to pass U16 (4x uint16_t vector) function arguments in the +// MMX mm0 register, which seems to mess with unrelated code that later uses +// x87 FP instructions (MMX's mm0 is an alias for x87's st0 register). +// +// It helps codegen to call __builtin_memcpy() when we know the byte count at compile time. +#if defined(__clang__) || defined(__GNUC__) + #define SI static inline __attribute__((always_inline)) +#else + #define SI static inline +#endif + +template +SI T load(const P* ptr) { + T val; + small_memcpy(&val, ptr, sizeof(val)); + return val; +} +template +SI void store(P* ptr, const T& val) { + small_memcpy(ptr, &val, sizeof(val)); +} + +// (T)v is a cast when N == 1 and a bit-pun when N>1, +// so we use cast(v) to actually cast or bit_pun(v) to bit-pun. +template +SI D cast(const S& v) { +#if N == 1 + return (D)v; +#elif defined(__clang__) + return __builtin_convertvector(v, D); +#else + D d; + for (int i = 0; i < N; i++) { + d[i] = v[i]; + } + return d; +#endif +} + +template +SI D bit_pun(const S& v) { + static_assert(sizeof(D) == sizeof(v), ""); + return load(&v); +} + +// When we convert from float to fixed point, it's very common to want to round, +// and for some reason compilers generate better code when converting to int32_t. +// To serve both those ends, we use this function to_fixed() instead of direct cast(). +#if defined(USING_NEON_FP16) + // NEON's got a F16 -> U16 instruction, so this should be fine without going via I16. + SI U16 to_fixed(F f) { return cast(f + 0.5f); } +#else + SI U32 to_fixed(F f) { return (U32)cast(f + 0.5f); } +#endif + + +// Sometimes we do something crazy on one branch of a conditonal, +// like divide by zero or convert a huge float to an integer, +// but then harmlessly select the other side. That trips up N==1 +// sanitizer builds, so we make if_then_else() a macro to avoid +// evaluating the unused side. + +#if N == 1 + #define if_then_else(cond, t, e) ((cond) ? (t) : (e)) +#else + template + SI T if_then_else(C cond, T t, T e) { + return bit_pun( ( cond & bit_pun(t)) | + (~cond & bit_pun(e)) ); + } +#endif + + +SI F F_from_Half(U16 half) { +#if defined(USING_NEON_FP16) + return bit_pun(half); +#elif defined(USING_NEON_F16C) + return vcvt_f32_f16((float16x4_t)half); +#elif defined(USING_AVX512F) + return (F)_mm512_cvtph_ps((__m256i)half); +#elif defined(USING_AVX_F16C) + typedef int16_t __attribute__((vector_size(16))) I16; + return __builtin_ia32_vcvtph2ps256((I16)half); +#else + U32 wide = cast(half); + // A half is 1-5-10 sign-exponent-mantissa, with 15 exponent bias. + U32 s = wide & 0x8000, + em = wide ^ s; + + // Constructing the float is easy if the half is not denormalized. + F norm = bit_pun( (s<<16) + (em<<13) + ((127-15)<<23) ); + + // Simply flush all denorm half floats to zero. + return if_then_else(em < 0x0400, F0, norm); +#endif +} + +#if defined(__clang__) + // The -((127-15)<<10) underflows that side of the math when + // we pass a denorm half float. It's harmless... we'll take the 0 side anyway. + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif +SI U16 Half_from_F(F f) { +#if defined(USING_NEON_FP16) + return bit_pun(f); +#elif defined(USING_NEON_F16C) + return (U16)vcvt_f16_f32(f); +#elif defined(USING_AVX512F) + return (U16)_mm512_cvtps_ph((__m512 )f, _MM_FROUND_CUR_DIRECTION ); +#elif defined(USING_AVX_F16C) + return (U16)__builtin_ia32_vcvtps2ph256(f, 0x04/*_MM_FROUND_CUR_DIRECTION*/); +#else + // A float is 1-8-23 sign-exponent-mantissa, with 127 exponent bias. + U32 sem = bit_pun(f), + s = sem & 0x80000000, + em = sem ^ s; + + // For simplicity we flush denorm half floats (including all denorm floats) to zero. + return cast(if_then_else(em < 0x38800000, (U32)F0 + , (s>>16) + (em>>13) - ((127-15)<<10))); +#endif +} + +// Swap high and low bytes of 16-bit lanes, converting between big-endian and little-endian. +#if defined(USING_NEON_FP16) + SI U16 swap_endian_16(U16 v) { + return (U16)vrev16q_u8((uint8x16_t) v); + } +#elif defined(USING_NEON) + SI U16 swap_endian_16(U16 v) { + return (U16)vrev16_u8((uint8x8_t) v); + } +#endif + +SI U64 swap_endian_16x4(const U64& rgba) { + return (rgba & 0x00ff00ff00ff00ff) << 8 + | (rgba & 0xff00ff00ff00ff00) >> 8; +} + +#if defined(USING_NEON_FP16) + SI F min_(F x, F y) { return (F)vminq_f16((float16x8_t)x, (float16x8_t)y); } + SI F max_(F x, F y) { return (F)vmaxq_f16((float16x8_t)x, (float16x8_t)y); } +#elif defined(USING_NEON) + SI F min_(F x, F y) { return (F)vminq_f32((float32x4_t)x, (float32x4_t)y); } + SI F max_(F x, F y) { return (F)vmaxq_f32((float32x4_t)x, (float32x4_t)y); } +#else + SI F min_(F x, F y) { return if_then_else(x > y, y, x); } + SI F max_(F x, F y) { return if_then_else(x < y, y, x); } +#endif + +SI F floor_(F x) { +#if N == 1 + return floorf_(x); +#elif defined(USING_NEON_FP16) + return vrndmq_f16(x); +#elif defined(__aarch64__) + return vrndmq_f32(x); +#elif defined(USING_AVX512F) + // Clang's _mm512_floor_ps() passes its mask as -1, not (__mmask16)-1, + // and integer santizer catches that this implicit cast changes the + // value from -1 to 65535. We'll cast manually to work around it. + // Read this as `return _mm512_floor_ps(x)`. + return _mm512_mask_floor_ps(x, (__mmask16)-1, x); +#elif defined(USING_AVX) + return __builtin_ia32_roundps256(x, 0x01/*_MM_FROUND_FLOOR*/); +#elif defined(__SSE4_1__) + return _mm_floor_ps(x); +#else + // Round trip through integers with a truncating cast. + F roundtrip = cast(cast(x)); + // If x is negative, truncating gives the ceiling instead of the floor. + return roundtrip - if_then_else(roundtrip > x, F1, F0); + + // This implementation fails for values of x that are outside + // the range an integer can represent. We expect most x to be small. +#endif +} + +SI F approx_log2(F x) { +#if defined(USING_NEON_FP16) + // TODO(mtklein) + return x; +#else + // The first approximation of log2(x) is its exponent 'e', minus 127. + I32 bits = bit_pun(x); + + F e = cast(bits) * (1.0f / (1<<23)); + + // If we use the mantissa too we can refine the error signficantly. + F m = bit_pun( (bits & 0x007fffff) | 0x3f000000 ); + + return e - 124.225514990f + - 1.498030302f*m + - 1.725879990f/(0.3520887068f + m); +#endif +} + +SI F approx_log(F x) { + const float ln2 = 0.69314718f; + return ln2 * approx_log2(x); +} + +SI F approx_exp2(F x) { +#if defined(USING_NEON_FP16) + // TODO(mtklein) + return x; +#else + F fract = x - floor_(x); + + F fbits = (1.0f * (1<<23)) * (x + 121.274057500f + - 1.490129070f*fract + + 27.728023300f/(4.84252568f - fract)); + I32 bits = cast(min_(max_(fbits, F0), FInfBits)); + + return bit_pun(bits); +#endif +} + +SI F approx_pow(F x, float y) { + return if_then_else((x == F0) | (x == F1), x + , approx_exp2(approx_log2(x) * y)); +} + +SI F approx_exp(F x) { + const float log2_e = 1.4426950408889634074f; + return approx_exp2(log2_e * x); +} + +// Return tf(x). +SI F apply_tf(const skcms_TransferFunction* tf, F x) { +#if defined(USING_NEON_FP16) + // TODO(mtklein) + (void)tf; + return x; +#else + // Peel off the sign bit and set x = |x|. + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + + // The transfer function has a linear part up to d, exponential at d and after. + F v = if_then_else(x < tf->d, tf->c*x + tf->f + , approx_pow(tf->a*x + tf->b, tf->g) + tf->e); + + // Tack the sign bit back on. + return bit_pun(sign | bit_pun(v)); +#endif +} + +SI F apply_pq(const skcms_TransferFunction* tf, F x) { +#if defined(USING_NEON_FP16) + // TODO(mtklein) + (void)tf; + return x; +#else + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + + F v = approx_pow(max_(tf->a + tf->b * approx_pow(x, tf->c), F0) + / (tf->d + tf->e * approx_pow(x, tf->c)), + tf->f); + + return bit_pun(sign | bit_pun(v)); +#endif +} + +SI F apply_hlg(const skcms_TransferFunction* tf, F x) { +#if defined(USING_NEON_FP16) + // TODO(mtklein) + (void)tf; + return x; +#else + const float R = tf->a, G = tf->b, + a = tf->c, b = tf->d, c = tf->e, + K = tf->f + 1; + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + + F v = if_then_else(x*R <= 1, approx_pow(x*R, G) + , approx_exp((x-c)*a) + b); + + return K*bit_pun(sign | bit_pun(v)); +#endif +} + +SI F apply_hlginv(const skcms_TransferFunction* tf, F x) { +#if defined(USING_NEON_FP16) + // TODO(mtklein) + (void)tf; + return x; +#else + const float R = tf->a, G = tf->b, + a = tf->c, b = tf->d, c = tf->e, + K = tf->f + 1; + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + x /= K; + + F v = if_then_else(x <= 1, R * approx_pow(x, G) + , a * approx_log(x - b) + c); + + return bit_pun(sign | bit_pun(v)); +#endif +} + + +// Strided loads and stores of N values, starting from p. +template +SI T load_3(const P* p) { +#if N == 1 + return (T)p[0]; +#elif N == 4 + return T{p[ 0],p[ 3],p[ 6],p[ 9]}; +#elif N == 8 + return T{p[ 0],p[ 3],p[ 6],p[ 9], p[12],p[15],p[18],p[21]}; +#elif N == 16 + return T{p[ 0],p[ 3],p[ 6],p[ 9], p[12],p[15],p[18],p[21], + p[24],p[27],p[30],p[33], p[36],p[39],p[42],p[45]}; +#endif +} + +template +SI T load_4(const P* p) { +#if N == 1 + return (T)p[0]; +#elif N == 4 + return T{p[ 0],p[ 4],p[ 8],p[12]}; +#elif N == 8 + return T{p[ 0],p[ 4],p[ 8],p[12], p[16],p[20],p[24],p[28]}; +#elif N == 16 + return T{p[ 0],p[ 4],p[ 8],p[12], p[16],p[20],p[24],p[28], + p[32],p[36],p[40],p[44], p[48],p[52],p[56],p[60]}; +#endif +} + +template +SI void store_3(P* p, const T& v) { +#if N == 1 + p[0] = v; +#elif N == 4 + p[ 0] = v[ 0]; p[ 3] = v[ 1]; p[ 6] = v[ 2]; p[ 9] = v[ 3]; +#elif N == 8 + p[ 0] = v[ 0]; p[ 3] = v[ 1]; p[ 6] = v[ 2]; p[ 9] = v[ 3]; + p[12] = v[ 4]; p[15] = v[ 5]; p[18] = v[ 6]; p[21] = v[ 7]; +#elif N == 16 + p[ 0] = v[ 0]; p[ 3] = v[ 1]; p[ 6] = v[ 2]; p[ 9] = v[ 3]; + p[12] = v[ 4]; p[15] = v[ 5]; p[18] = v[ 6]; p[21] = v[ 7]; + p[24] = v[ 8]; p[27] = v[ 9]; p[30] = v[10]; p[33] = v[11]; + p[36] = v[12]; p[39] = v[13]; p[42] = v[14]; p[45] = v[15]; +#endif +} + +template +SI void store_4(P* p, const T& v) { +#if N == 1 + p[0] = v; +#elif N == 4 + p[ 0] = v[ 0]; p[ 4] = v[ 1]; p[ 8] = v[ 2]; p[12] = v[ 3]; +#elif N == 8 + p[ 0] = v[ 0]; p[ 4] = v[ 1]; p[ 8] = v[ 2]; p[12] = v[ 3]; + p[16] = v[ 4]; p[20] = v[ 5]; p[24] = v[ 6]; p[28] = v[ 7]; +#elif N == 16 + p[ 0] = v[ 0]; p[ 4] = v[ 1]; p[ 8] = v[ 2]; p[12] = v[ 3]; + p[16] = v[ 4]; p[20] = v[ 5]; p[24] = v[ 6]; p[28] = v[ 7]; + p[32] = v[ 8]; p[36] = v[ 9]; p[40] = v[10]; p[44] = v[11]; + p[48] = v[12]; p[52] = v[13]; p[56] = v[14]; p[60] = v[15]; +#endif +} + + +SI U8 gather_8(const uint8_t* p, I32 ix) { +#if N == 1 + U8 v = p[ix]; +#elif N == 4 + U8 v = { p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]] }; +#elif N == 8 + U8 v = { p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]], + p[ix[4]], p[ix[5]], p[ix[6]], p[ix[7]] }; +#elif N == 16 + U8 v = { p[ix[ 0]], p[ix[ 1]], p[ix[ 2]], p[ix[ 3]], + p[ix[ 4]], p[ix[ 5]], p[ix[ 6]], p[ix[ 7]], + p[ix[ 8]], p[ix[ 9]], p[ix[10]], p[ix[11]], + p[ix[12]], p[ix[13]], p[ix[14]], p[ix[15]] }; +#endif + return v; +} + +SI U16 gather_16(const uint8_t* p, I32 ix) { + // Load the i'th 16-bit value from p. + auto load_16 = [p](int i) { + return load(p + 2*i); + }; +#if N == 1 + U16 v = load_16(ix); +#elif N == 4 + U16 v = { load_16(ix[0]), load_16(ix[1]), load_16(ix[2]), load_16(ix[3]) }; +#elif N == 8 + U16 v = { load_16(ix[0]), load_16(ix[1]), load_16(ix[2]), load_16(ix[3]), + load_16(ix[4]), load_16(ix[5]), load_16(ix[6]), load_16(ix[7]) }; +#elif N == 16 + U16 v = { load_16(ix[ 0]), load_16(ix[ 1]), load_16(ix[ 2]), load_16(ix[ 3]), + load_16(ix[ 4]), load_16(ix[ 5]), load_16(ix[ 6]), load_16(ix[ 7]), + load_16(ix[ 8]), load_16(ix[ 9]), load_16(ix[10]), load_16(ix[11]), + load_16(ix[12]), load_16(ix[13]), load_16(ix[14]), load_16(ix[15]) }; +#endif + return v; +} + +SI U32 gather_32(const uint8_t* p, I32 ix) { + // Load the i'th 32-bit value from p. + auto load_32 = [p](int i) { + return load(p + 4*i); + }; +#if N == 1 + U32 v = load_32(ix); +#elif N == 4 + U32 v = { load_32(ix[0]), load_32(ix[1]), load_32(ix[2]), load_32(ix[3]) }; +#elif N == 8 + U32 v = { load_32(ix[0]), load_32(ix[1]), load_32(ix[2]), load_32(ix[3]), + load_32(ix[4]), load_32(ix[5]), load_32(ix[6]), load_32(ix[7]) }; +#elif N == 16 + U32 v = { load_32(ix[ 0]), load_32(ix[ 1]), load_32(ix[ 2]), load_32(ix[ 3]), + load_32(ix[ 4]), load_32(ix[ 5]), load_32(ix[ 6]), load_32(ix[ 7]), + load_32(ix[ 8]), load_32(ix[ 9]), load_32(ix[10]), load_32(ix[11]), + load_32(ix[12]), load_32(ix[13]), load_32(ix[14]), load_32(ix[15]) }; +#endif + // TODO: AVX2 and AVX-512 gathers (c.f. gather_24). + return v; +} + +SI U32 gather_24(const uint8_t* p, I32 ix) { + // First, back up a byte. Any place we're gathering from has a safe junk byte to read + // in front of it, either a previous table value, or some tag metadata. + p -= 1; + + // Load the i'th 24-bit value from p, and 1 extra byte. + auto load_24_32 = [p](int i) { + return load(p + 3*i); + }; + + // Now load multiples of 4 bytes (a junk byte, then r,g,b). +#if N == 1 + U32 v = load_24_32(ix); +#elif N == 4 + U32 v = { load_24_32(ix[0]), load_24_32(ix[1]), load_24_32(ix[2]), load_24_32(ix[3]) }; +#elif N == 8 && !defined(USING_AVX2) + U32 v = { load_24_32(ix[0]), load_24_32(ix[1]), load_24_32(ix[2]), load_24_32(ix[3]), + load_24_32(ix[4]), load_24_32(ix[5]), load_24_32(ix[6]), load_24_32(ix[7]) }; +#elif N == 8 + (void)load_24_32; + // The gather instruction here doesn't need any particular alignment, + // but the intrinsic takes a const int*. + const int* p4 = bit_pun(p); + I32 zero = { 0, 0, 0, 0, 0, 0, 0, 0}, + mask = {-1,-1,-1,-1, -1,-1,-1,-1}; + #if defined(__clang__) + U32 v = (U32)__builtin_ia32_gatherd_d256(zero, p4, 3*ix, mask, 1); + #elif defined(__GNUC__) + U32 v = (U32)__builtin_ia32_gathersiv8si(zero, p4, 3*ix, mask, 1); + #endif +#elif N == 16 + (void)load_24_32; + // The intrinsic is supposed to take const void* now, but it takes const int*, just like AVX2. + // And AVX-512 swapped the order of arguments. :/ + const int* p4 = bit_pun(p); + U32 v = (U32)_mm512_i32gather_epi32((__m512i)(3*ix), p4, 1); +#endif + + // Shift off the junk byte, leaving r,g,b in low 24 bits (and zero in the top 8). + return v >> 8; +} + +#if !defined(__arm__) + SI void gather_48(const uint8_t* p, I32 ix, U64* v) { + // As in gather_24(), with everything doubled. + p -= 2; + + // Load the i'th 48-bit value from p, and 2 extra bytes. + auto load_48_64 = [p](int i) { + return load(p + 6*i); + }; + + #if N == 1 + *v = load_48_64(ix); + #elif N == 4 + *v = U64{ + load_48_64(ix[0]), load_48_64(ix[1]), load_48_64(ix[2]), load_48_64(ix[3]), + }; + #elif N == 8 && !defined(USING_AVX2) + *v = U64{ + load_48_64(ix[0]), load_48_64(ix[1]), load_48_64(ix[2]), load_48_64(ix[3]), + load_48_64(ix[4]), load_48_64(ix[5]), load_48_64(ix[6]), load_48_64(ix[7]), + }; + #elif N == 8 + (void)load_48_64; + typedef int32_t __attribute__((vector_size(16))) Half_I32; + typedef long long __attribute__((vector_size(32))) Half_I64; + + // The gather instruction here doesn't need any particular alignment, + // but the intrinsic takes a const long long*. + const long long int* p8 = bit_pun(p); + + Half_I64 zero = { 0, 0, 0, 0}, + mask = {-1,-1,-1,-1}; + + ix *= 6; + Half_I32 ix_lo = { ix[0], ix[1], ix[2], ix[3] }, + ix_hi = { ix[4], ix[5], ix[6], ix[7] }; + + #if defined(__clang__) + Half_I64 lo = (Half_I64)__builtin_ia32_gatherd_q256(zero, p8, ix_lo, mask, 1), + hi = (Half_I64)__builtin_ia32_gatherd_q256(zero, p8, ix_hi, mask, 1); + #elif defined(__GNUC__) + Half_I64 lo = (Half_I64)__builtin_ia32_gathersiv4di(zero, p8, ix_lo, mask, 1), + hi = (Half_I64)__builtin_ia32_gathersiv4di(zero, p8, ix_hi, mask, 1); + #endif + store((char*)v + 0, lo); + store((char*)v + 32, hi); + #elif N == 16 + (void)load_48_64; + const long long int* p8 = bit_pun(p); + __m512i lo = _mm512_i32gather_epi64(_mm512_extracti32x8_epi32((__m512i)(6*ix), 0), p8, 1), + hi = _mm512_i32gather_epi64(_mm512_extracti32x8_epi32((__m512i)(6*ix), 1), p8, 1); + store((char*)v + 0, lo); + store((char*)v + 64, hi); + #endif + + *v >>= 16; + } +#endif + +SI F F_from_U8(U8 v) { + return cast(v) * (1/255.0f); +} + +SI F F_from_U16_BE(U16 v) { + // All 16-bit ICC values are big-endian, so we byte swap before converting to float. + // MSVC catches the "loss" of data here in the portable path, so we also make sure to mask. + U16 lo = (v >> 8), + hi = (v << 8) & 0xffff; + return cast(lo|hi) * (1/65535.0f); +} + +SI U16 U16_from_F(F v) { + // 65535 == inf in FP16, so promote to FP32 before converting. + return cast(cast>(v) * 65535 + 0.5f); +} + +SI F minus_1_ulp(F v) { +#if defined(USING_NEON_FP16) + return bit_pun( bit_pun(v) - 1 ); +#else + return bit_pun( bit_pun(v) - 1 ); +#endif +} + +SI F table(const skcms_Curve* curve, F v) { + // Clamp the input to [0,1], then scale to a table index. + F ix = max_(F0, min_(v, F1)) * (float)(curve->table_entries - 1); + + // We'll look up (equal or adjacent) entries at lo and hi, then lerp by t between the two. + I32 lo = cast( ix ), + hi = cast(minus_1_ulp(ix+1.0f)); + F t = ix - cast(lo); // i.e. the fractional part of ix. + + // TODO: can we load l and h simultaneously? Each entry in 'h' is either + // the same as in 'l' or adjacent. We have a rough idea that's it'd always be safe + // to read adjacent entries and perhaps underflow the table by a byte or two + // (it'd be junk, but always safe to read). Not sure how to lerp yet. + F l,h; + if (curve->table_8) { + l = F_from_U8(gather_8(curve->table_8, lo)); + h = F_from_U8(gather_8(curve->table_8, hi)); + } else { + l = F_from_U16_BE(gather_16(curve->table_16, lo)); + h = F_from_U16_BE(gather_16(curve->table_16, hi)); + } + return l + (h-l)*t; +} + +SI void sample_clut_8(const uint8_t* grid_8, I32 ix, F* r, F* g, F* b) { + U32 rgb = gather_24(grid_8, ix); + + *r = cast((rgb >> 0) & 0xff) * (1/255.0f); + *g = cast((rgb >> 8) & 0xff) * (1/255.0f); + *b = cast((rgb >> 16) & 0xff) * (1/255.0f); +} + +SI void sample_clut_8(const uint8_t* grid_8, I32 ix, F* r, F* g, F* b, F* a) { + // TODO: don't forget to optimize gather_32(). + U32 rgba = gather_32(grid_8, ix); + + *r = cast((rgba >> 0) & 0xff) * (1/255.0f); + *g = cast((rgba >> 8) & 0xff) * (1/255.0f); + *b = cast((rgba >> 16) & 0xff) * (1/255.0f); + *a = cast((rgba >> 24) & 0xff) * (1/255.0f); +} + +SI void sample_clut_16(const uint8_t* grid_16, I32 ix, F* r, F* g, F* b) { +#if defined(__arm__) + // This is up to 2x faster on 32-bit ARM than the #else-case fast path. + *r = F_from_U16_BE(gather_16(grid_16, 3*ix+0)); + *g = F_from_U16_BE(gather_16(grid_16, 3*ix+1)); + *b = F_from_U16_BE(gather_16(grid_16, 3*ix+2)); +#else + // This strategy is much faster for 64-bit builds, and fine for 32-bit x86 too. + U64 rgb; + gather_48(grid_16, ix, &rgb); + rgb = swap_endian_16x4(rgb); + + *r = cast((rgb >> 0) & 0xffff) * (1/65535.0f); + *g = cast((rgb >> 16) & 0xffff) * (1/65535.0f); + *b = cast((rgb >> 32) & 0xffff) * (1/65535.0f); +#endif +} + +SI void sample_clut_16(const uint8_t* grid_16, I32 ix, F* r, F* g, F* b, F* a) { + // TODO: gather_64()-based fast path? + *r = F_from_U16_BE(gather_16(grid_16, 4*ix+0)); + *g = F_from_U16_BE(gather_16(grid_16, 4*ix+1)); + *b = F_from_U16_BE(gather_16(grid_16, 4*ix+2)); + *a = F_from_U16_BE(gather_16(grid_16, 4*ix+3)); +} + +static void clut(uint32_t input_channels, uint32_t output_channels, + const uint8_t grid_points[4], const uint8_t* grid_8, const uint8_t* grid_16, + F* r, F* g, F* b, F* a) { + + const int dim = (int)input_channels; + assert (0 < dim && dim <= 4); + assert (output_channels == 3 || + output_channels == 4); + + // For each of these arrays, think foo[2*dim], but we use foo[8] since we know dim <= 4. + I32 index [8]; // Index contribution by dimension, first low from 0, then high from 4. + F weight[8]; // Weight for each contribution, again first low, then high. + + // O(dim) work first: calculate index,weight from r,g,b,a. + const F inputs[] = { *r,*g,*b,*a }; + for (int i = dim-1, stride = 1; i >= 0; i--) { + // x is where we logically want to sample the grid in the i-th dimension. + F x = inputs[i] * (float)(grid_points[i] - 1); + + // But we can't index at floats. lo and hi are the two integer grid points surrounding x. + I32 lo = cast( x ), // i.e. trunc(x) == floor(x) here. + hi = cast(minus_1_ulp(x+1.0f)); + // Notice how we fold in the accumulated stride across previous dimensions here. + index[i+0] = lo * stride; + index[i+4] = hi * stride; + stride *= grid_points[i]; + + // We'll interpolate between those two integer grid points by t. + F t = x - cast(lo); // i.e. fract(x) + weight[i+0] = 1-t; + weight[i+4] = t; + } + + *r = *g = *b = F0; + if (output_channels == 4) { + *a = F0; + } + + // We'll sample 2^dim == 1<input_channels, a2b->output_channels, + a2b->grid_points, a2b->grid_8, a2b->grid_16, + r,g,b,&a); +} +static void clut(const skcms_B2A* b2a, F* r, F* g, F* b, F* a) { + clut(b2a->input_channels, b2a->output_channels, + b2a->grid_points, b2a->grid_8, b2a->grid_16, + r,g,b,a); +} + +static void exec_ops(const Op* ops, const void** args, + const char* src, char* dst, int i) { + F r = F0, g = F0, b = F0, a = F1; + while (true) { + switch (*ops++) { + case Op_load_a8:{ + a = F_from_U8(load(src + 1*i)); + } break; + + case Op_load_g8:{ + r = g = b = F_from_U8(load(src + 1*i)); + } break; + + case Op_load_4444:{ + U16 abgr = load(src + 2*i); + + r = cast((abgr >> 12) & 0xf) * (1/15.0f); + g = cast((abgr >> 8) & 0xf) * (1/15.0f); + b = cast((abgr >> 4) & 0xf) * (1/15.0f); + a = cast((abgr >> 0) & 0xf) * (1/15.0f); + } break; + + case Op_load_565:{ + U16 rgb = load(src + 2*i); + + r = cast(rgb & (uint16_t)(31<< 0)) * (1.0f / (31<< 0)); + g = cast(rgb & (uint16_t)(63<< 5)) * (1.0f / (63<< 5)); + b = cast(rgb & (uint16_t)(31<<11)) * (1.0f / (31<<11)); + } break; + + case Op_load_888:{ + const uint8_t* rgb = (const uint8_t*)(src + 3*i); + #if defined(USING_NEON_FP16) + // See the explanation under USING_NEON below. This is that doubled up. + uint8x16x3_t v = {{ vdupq_n_u8(0), vdupq_n_u8(0), vdupq_n_u8(0) }}; + v = vld3q_lane_u8(rgb+ 0, v, 0); + v = vld3q_lane_u8(rgb+ 3, v, 2); + v = vld3q_lane_u8(rgb+ 6, v, 4); + v = vld3q_lane_u8(rgb+ 9, v, 6); + + v = vld3q_lane_u8(rgb+12, v, 8); + v = vld3q_lane_u8(rgb+15, v, 10); + v = vld3q_lane_u8(rgb+18, v, 12); + v = vld3q_lane_u8(rgb+21, v, 14); + + r = cast((U16)v.val[0]) * (1/255.0f); + g = cast((U16)v.val[1]) * (1/255.0f); + b = cast((U16)v.val[2]) * (1/255.0f); + #elif defined(USING_NEON) + // There's no uint8x4x3_t or vld3 load for it, so we'll load each rgb pixel one at + // a time. Since we're doing that, we might as well load them into 16-bit lanes. + // (We'd even load into 32-bit lanes, but that's not possible on ARMv7.) + uint8x8x3_t v = {{ vdup_n_u8(0), vdup_n_u8(0), vdup_n_u8(0) }}; + v = vld3_lane_u8(rgb+0, v, 0); + v = vld3_lane_u8(rgb+3, v, 2); + v = vld3_lane_u8(rgb+6, v, 4); + v = vld3_lane_u8(rgb+9, v, 6); + + // Now if we squint, those 3 uint8x8_t we constructed are really U16s, easy to + // convert to F. (Again, U32 would be even better here if drop ARMv7 or split + // ARMv7 and ARMv8 impls.) + r = cast((U16)v.val[0]) * (1/255.0f); + g = cast((U16)v.val[1]) * (1/255.0f); + b = cast((U16)v.val[2]) * (1/255.0f); + #else + r = cast(load_3(rgb+0) ) * (1/255.0f); + g = cast(load_3(rgb+1) ) * (1/255.0f); + b = cast(load_3(rgb+2) ) * (1/255.0f); + #endif + } break; + + case Op_load_8888:{ + U32 rgba = load(src + 4*i); + + r = cast((rgba >> 0) & 0xff) * (1/255.0f); + g = cast((rgba >> 8) & 0xff) * (1/255.0f); + b = cast((rgba >> 16) & 0xff) * (1/255.0f); + a = cast((rgba >> 24) & 0xff) * (1/255.0f); + } break; + + case Op_load_8888_palette8:{ + const uint8_t* palette = (const uint8_t*) *args++; + I32 ix = cast(load(src + 1*i)); + U32 rgba = gather_32(palette, ix); + + r = cast((rgba >> 0) & 0xff) * (1/255.0f); + g = cast((rgba >> 8) & 0xff) * (1/255.0f); + b = cast((rgba >> 16) & 0xff) * (1/255.0f); + a = cast((rgba >> 24) & 0xff) * (1/255.0f); + } break; + + case Op_load_1010102:{ + U32 rgba = load(src + 4*i); + + r = cast((rgba >> 0) & 0x3ff) * (1/1023.0f); + g = cast((rgba >> 10) & 0x3ff) * (1/1023.0f); + b = cast((rgba >> 20) & 0x3ff) * (1/1023.0f); + a = cast((rgba >> 30) & 0x3 ) * (1/ 3.0f); + } break; + + case Op_load_101010x_XR:{ + static constexpr float min = -0.752941f; + static constexpr float max = 1.25098f; + static constexpr float range = max - min; + U32 rgba = load(src + 4*i); + r = cast((rgba >> 0) & 0x3ff) * (1/1023.0f) * range + min; + g = cast((rgba >> 10) & 0x3ff) * (1/1023.0f) * range + min; + b = cast((rgba >> 20) & 0x3ff) * (1/1023.0f) * range + min; + } break; + + case Op_load_161616LE:{ + uintptr_t ptr = (uintptr_t)(src + 6*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgb = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x3_t v = vld3q_u16(rgb); + r = cast((U16)v.val[0]) * (1/65535.0f); + g = cast((U16)v.val[1]) * (1/65535.0f); + b = cast((U16)v.val[2]) * (1/65535.0f); + #elif defined(USING_NEON) + uint16x4x3_t v = vld3_u16(rgb); + r = cast((U16)v.val[0]) * (1/65535.0f); + g = cast((U16)v.val[1]) * (1/65535.0f); + b = cast((U16)v.val[2]) * (1/65535.0f); + #else + r = cast(load_3(rgb+0)) * (1/65535.0f); + g = cast(load_3(rgb+1)) * (1/65535.0f); + b = cast(load_3(rgb+2)) * (1/65535.0f); + #endif + } break; + + case Op_load_16161616LE:{ + uintptr_t ptr = (uintptr_t)(src + 8*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgba = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x4_t v = vld4q_u16(rgba); + r = cast((U16)v.val[0]) * (1/65535.0f); + g = cast((U16)v.val[1]) * (1/65535.0f); + b = cast((U16)v.val[2]) * (1/65535.0f); + a = cast((U16)v.val[3]) * (1/65535.0f); + #elif defined(USING_NEON) + uint16x4x4_t v = vld4_u16(rgba); + r = cast((U16)v.val[0]) * (1/65535.0f); + g = cast((U16)v.val[1]) * (1/65535.0f); + b = cast((U16)v.val[2]) * (1/65535.0f); + a = cast((U16)v.val[3]) * (1/65535.0f); + #else + U64 px = load(rgba); + + r = cast((px >> 0) & 0xffff) * (1/65535.0f); + g = cast((px >> 16) & 0xffff) * (1/65535.0f); + b = cast((px >> 32) & 0xffff) * (1/65535.0f); + a = cast((px >> 48) & 0xffff) * (1/65535.0f); + #endif + } break; + + case Op_load_161616BE:{ + uintptr_t ptr = (uintptr_t)(src + 6*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgb = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x3_t v = vld3q_u16(rgb); + r = cast(swap_endian_16((U16)v.val[0])) * (1/65535.0f); + g = cast(swap_endian_16((U16)v.val[1])) * (1/65535.0f); + b = cast(swap_endian_16((U16)v.val[2])) * (1/65535.0f); + #elif defined(USING_NEON) + uint16x4x3_t v = vld3_u16(rgb); + r = cast(swap_endian_16((U16)v.val[0])) * (1/65535.0f); + g = cast(swap_endian_16((U16)v.val[1])) * (1/65535.0f); + b = cast(swap_endian_16((U16)v.val[2])) * (1/65535.0f); + #else + U32 R = load_3(rgb+0), + G = load_3(rgb+1), + B = load_3(rgb+2); + // R,G,B are big-endian 16-bit, so byte swap them before converting to float. + r = cast((R & 0x00ff)<<8 | (R & 0xff00)>>8) * (1/65535.0f); + g = cast((G & 0x00ff)<<8 | (G & 0xff00)>>8) * (1/65535.0f); + b = cast((B & 0x00ff)<<8 | (B & 0xff00)>>8) * (1/65535.0f); + #endif + } break; + + case Op_load_16161616BE:{ + uintptr_t ptr = (uintptr_t)(src + 8*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgba = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x4_t v = vld4q_u16(rgba); + r = cast(swap_endian_16((U16)v.val[0])) * (1/65535.0f); + g = cast(swap_endian_16((U16)v.val[1])) * (1/65535.0f); + b = cast(swap_endian_16((U16)v.val[2])) * (1/65535.0f); + a = cast(swap_endian_16((U16)v.val[3])) * (1/65535.0f); + #elif defined(USING_NEON) + uint16x4x4_t v = vld4_u16(rgba); + r = cast(swap_endian_16((U16)v.val[0])) * (1/65535.0f); + g = cast(swap_endian_16((U16)v.val[1])) * (1/65535.0f); + b = cast(swap_endian_16((U16)v.val[2])) * (1/65535.0f); + a = cast(swap_endian_16((U16)v.val[3])) * (1/65535.0f); + #else + U64 px = swap_endian_16x4(load(rgba)); + + r = cast((px >> 0) & 0xffff) * (1/65535.0f); + g = cast((px >> 16) & 0xffff) * (1/65535.0f); + b = cast((px >> 32) & 0xffff) * (1/65535.0f); + a = cast((px >> 48) & 0xffff) * (1/65535.0f); + #endif + } break; + + case Op_load_hhh:{ + uintptr_t ptr = (uintptr_t)(src + 6*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgb = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x3_t v = vld3q_u16(rgb); + U16 R = (U16)v.val[0], + G = (U16)v.val[1], + B = (U16)v.val[2]; + #elif defined(USING_NEON) + uint16x4x3_t v = vld3_u16(rgb); + U16 R = (U16)v.val[0], + G = (U16)v.val[1], + B = (U16)v.val[2]; + #else + U16 R = load_3(rgb+0), + G = load_3(rgb+1), + B = load_3(rgb+2); + #endif + r = F_from_Half(R); + g = F_from_Half(G); + b = F_from_Half(B); + } break; + + case Op_load_hhhh:{ + uintptr_t ptr = (uintptr_t)(src + 8*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgba = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x4_t v = vld4q_u16(rgba); + U16 R = (U16)v.val[0], + G = (U16)v.val[1], + B = (U16)v.val[2], + A = (U16)v.val[3]; + #elif defined(USING_NEON) + uint16x4x4_t v = vld4_u16(rgba); + U16 R = (U16)v.val[0], + G = (U16)v.val[1], + B = (U16)v.val[2], + A = (U16)v.val[3]; + #else + U64 px = load(rgba); + U16 R = cast((px >> 0) & 0xffff), + G = cast((px >> 16) & 0xffff), + B = cast((px >> 32) & 0xffff), + A = cast((px >> 48) & 0xffff); + #endif + r = F_from_Half(R); + g = F_from_Half(G); + b = F_from_Half(B); + a = F_from_Half(A); + } break; + + case Op_load_fff:{ + uintptr_t ptr = (uintptr_t)(src + 12*i); + assert( (ptr & 3) == 0 ); // src must be 4-byte aligned for this + const float* rgb = (const float*)ptr; // cast to const float* to be safe. + #if defined(USING_NEON_FP16) + float32x4x3_t lo = vld3q_f32(rgb + 0), + hi = vld3q_f32(rgb + 12); + r = (F)vcombine_f16(vcvt_f16_f32(lo.val[0]), vcvt_f16_f32(hi.val[0])); + g = (F)vcombine_f16(vcvt_f16_f32(lo.val[1]), vcvt_f16_f32(hi.val[1])); + b = (F)vcombine_f16(vcvt_f16_f32(lo.val[2]), vcvt_f16_f32(hi.val[2])); + #elif defined(USING_NEON) + float32x4x3_t v = vld3q_f32(rgb); + r = (F)v.val[0]; + g = (F)v.val[1]; + b = (F)v.val[2]; + #else + r = load_3(rgb+0); + g = load_3(rgb+1); + b = load_3(rgb+2); + #endif + } break; + + case Op_load_ffff:{ + uintptr_t ptr = (uintptr_t)(src + 16*i); + assert( (ptr & 3) == 0 ); // src must be 4-byte aligned for this + const float* rgba = (const float*)ptr; // cast to const float* to be safe. + #if defined(USING_NEON_FP16) + float32x4x4_t lo = vld4q_f32(rgba + 0), + hi = vld4q_f32(rgba + 16); + r = (F)vcombine_f16(vcvt_f16_f32(lo.val[0]), vcvt_f16_f32(hi.val[0])); + g = (F)vcombine_f16(vcvt_f16_f32(lo.val[1]), vcvt_f16_f32(hi.val[1])); + b = (F)vcombine_f16(vcvt_f16_f32(lo.val[2]), vcvt_f16_f32(hi.val[2])); + a = (F)vcombine_f16(vcvt_f16_f32(lo.val[3]), vcvt_f16_f32(hi.val[3])); + #elif defined(USING_NEON) + float32x4x4_t v = vld4q_f32(rgba); + r = (F)v.val[0]; + g = (F)v.val[1]; + b = (F)v.val[2]; + a = (F)v.val[3]; + #else + r = load_4(rgba+0); + g = load_4(rgba+1); + b = load_4(rgba+2); + a = load_4(rgba+3); + #endif + } break; + + case Op_swap_rb:{ + F t = r; + r = b; + b = t; + } break; + + case Op_clamp:{ + r = max_(F0, min_(r, F1)); + g = max_(F0, min_(g, F1)); + b = max_(F0, min_(b, F1)); + a = max_(F0, min_(a, F1)); + } break; + + case Op_invert:{ + r = F1 - r; + g = F1 - g; + b = F1 - b; + a = F1 - a; + } break; + + case Op_force_opaque:{ + a = F1; + } break; + + case Op_premul:{ + r *= a; + g *= a; + b *= a; + } break; + + case Op_unpremul:{ + F scale = if_then_else(F1 / a < INFINITY_, F1 / a, F0); + r *= scale; + g *= scale; + b *= scale; + } break; + + case Op_matrix_3x3:{ + const skcms_Matrix3x3* matrix = (const skcms_Matrix3x3*) *args++; + const float* m = &matrix->vals[0][0]; + + F R = m[0]*r + m[1]*g + m[2]*b, + G = m[3]*r + m[4]*g + m[5]*b, + B = m[6]*r + m[7]*g + m[8]*b; + + r = R; + g = G; + b = B; + } break; + + case Op_matrix_3x4:{ + const skcms_Matrix3x4* matrix = (const skcms_Matrix3x4*) *args++; + const float* m = &matrix->vals[0][0]; + + F R = m[0]*r + m[1]*g + m[ 2]*b + m[ 3], + G = m[4]*r + m[5]*g + m[ 6]*b + m[ 7], + B = m[8]*r + m[9]*g + m[10]*b + m[11]; + + r = R; + g = G; + b = B; + } break; + + case Op_lab_to_xyz:{ + // The L*a*b values are in r,g,b, but normalized to [0,1]. Reconstruct them: + F L = r * 100.0f, + A = g * 255.0f - 128.0f, + B = b * 255.0f - 128.0f; + + // Convert to CIE XYZ. + F Y = (L + 16.0f) * (1/116.0f), + X = Y + A*(1/500.0f), + Z = Y - B*(1/200.0f); + + X = if_then_else(X*X*X > 0.008856f, X*X*X, (X - (16/116.0f)) * (1/7.787f)); + Y = if_then_else(Y*Y*Y > 0.008856f, Y*Y*Y, (Y - (16/116.0f)) * (1/7.787f)); + Z = if_then_else(Z*Z*Z > 0.008856f, Z*Z*Z, (Z - (16/116.0f)) * (1/7.787f)); + + // Adjust to XYZD50 illuminant, and stuff back into r,g,b for the next op. + r = X * 0.9642f; + g = Y ; + b = Z * 0.8249f; + } break; + + // As above, in reverse. + case Op_xyz_to_lab:{ + F X = r * (1/0.9642f), + Y = g, + Z = b * (1/0.8249f); + + X = if_then_else(X > 0.008856f, approx_pow(X, 1/3.0f), X*7.787f + (16/116.0f)); + Y = if_then_else(Y > 0.008856f, approx_pow(Y, 1/3.0f), Y*7.787f + (16/116.0f)); + Z = if_then_else(Z > 0.008856f, approx_pow(Z, 1/3.0f), Z*7.787f + (16/116.0f)); + + F L = Y*116.0f - 16.0f, + A = (X-Y)*500.0f, + B = (Y-Z)*200.0f; + + r = L * (1/100.f); + g = (A + 128.0f) * (1/255.0f); + b = (B + 128.0f) * (1/255.0f); + } break; + + case Op_tf_r:{ r = apply_tf((const skcms_TransferFunction*)*args++, r); } break; + case Op_tf_g:{ g = apply_tf((const skcms_TransferFunction*)*args++, g); } break; + case Op_tf_b:{ b = apply_tf((const skcms_TransferFunction*)*args++, b); } break; + case Op_tf_a:{ a = apply_tf((const skcms_TransferFunction*)*args++, a); } break; + + case Op_pq_r:{ r = apply_pq((const skcms_TransferFunction*)*args++, r); } break; + case Op_pq_g:{ g = apply_pq((const skcms_TransferFunction*)*args++, g); } break; + case Op_pq_b:{ b = apply_pq((const skcms_TransferFunction*)*args++, b); } break; + case Op_pq_a:{ a = apply_pq((const skcms_TransferFunction*)*args++, a); } break; + + case Op_hlg_r:{ r = apply_hlg((const skcms_TransferFunction*)*args++, r); } break; + case Op_hlg_g:{ g = apply_hlg((const skcms_TransferFunction*)*args++, g); } break; + case Op_hlg_b:{ b = apply_hlg((const skcms_TransferFunction*)*args++, b); } break; + case Op_hlg_a:{ a = apply_hlg((const skcms_TransferFunction*)*args++, a); } break; + + case Op_hlginv_r:{ r = apply_hlginv((const skcms_TransferFunction*)*args++, r); } break; + case Op_hlginv_g:{ g = apply_hlginv((const skcms_TransferFunction*)*args++, g); } break; + case Op_hlginv_b:{ b = apply_hlginv((const skcms_TransferFunction*)*args++, b); } break; + case Op_hlginv_a:{ a = apply_hlginv((const skcms_TransferFunction*)*args++, a); } break; + + case Op_table_r: { r = table((const skcms_Curve*)*args++, r); } break; + case Op_table_g: { g = table((const skcms_Curve*)*args++, g); } break; + case Op_table_b: { b = table((const skcms_Curve*)*args++, b); } break; + case Op_table_a: { a = table((const skcms_Curve*)*args++, a); } break; + + case Op_clut_A2B: { + const skcms_A2B* a2b = (const skcms_A2B*) *args++; + clut(a2b, &r,&g,&b,a); + + if (a2b->input_channels == 4) { + // CMYK is opaque. + a = F1; + } + } break; + + case Op_clut_B2A: { + const skcms_B2A* b2a = (const skcms_B2A*) *args++; + clut(b2a, &r,&g,&b,&a); + } break; + + // Notice, from here on down the store_ ops all return, ending the loop. + + case Op_store_a8: { + store(dst + 1*i, cast(to_fixed(a * 255))); + } return; + + case Op_store_g8: { + // g should be holding luminance (Y) (r,g,b ~~~> X,Y,Z) + store(dst + 1*i, cast(to_fixed(g * 255))); + } return; + + case Op_store_4444: { + store(dst + 2*i, cast(to_fixed(r * 15) << 12) + | cast(to_fixed(g * 15) << 8) + | cast(to_fixed(b * 15) << 4) + | cast(to_fixed(a * 15) << 0)); + } return; + + case Op_store_565: { + store(dst + 2*i, cast(to_fixed(r * 31) << 0 ) + | cast(to_fixed(g * 63) << 5 ) + | cast(to_fixed(b * 31) << 11 )); + } return; + + case Op_store_888: { + uint8_t* rgb = (uint8_t*)dst + 3*i; + #if defined(USING_NEON_FP16) + // See the explanation under USING_NEON below. This is that doubled up. + U16 R = to_fixed(r * 255), + G = to_fixed(g * 255), + B = to_fixed(b * 255); + + uint8x16x3_t v = {{ (uint8x16_t)R, (uint8x16_t)G, (uint8x16_t)B }}; + vst3q_lane_u8(rgb+ 0, v, 0); + vst3q_lane_u8(rgb+ 3, v, 2); + vst3q_lane_u8(rgb+ 6, v, 4); + vst3q_lane_u8(rgb+ 9, v, 6); + + vst3q_lane_u8(rgb+12, v, 8); + vst3q_lane_u8(rgb+15, v, 10); + vst3q_lane_u8(rgb+18, v, 12); + vst3q_lane_u8(rgb+21, v, 14); + #elif defined(USING_NEON) + // Same deal as load_888 but in reverse... we'll store using uint8x8x3_t, but + // get there via U16 to save some instructions converting to float. And just + // like load_888, we'd prefer to go via U32 but for ARMv7 support. + U16 R = cast(to_fixed(r * 255)), + G = cast(to_fixed(g * 255)), + B = cast(to_fixed(b * 255)); + + uint8x8x3_t v = {{ (uint8x8_t)R, (uint8x8_t)G, (uint8x8_t)B }}; + vst3_lane_u8(rgb+0, v, 0); + vst3_lane_u8(rgb+3, v, 2); + vst3_lane_u8(rgb+6, v, 4); + vst3_lane_u8(rgb+9, v, 6); + #else + store_3(rgb+0, cast(to_fixed(r * 255)) ); + store_3(rgb+1, cast(to_fixed(g * 255)) ); + store_3(rgb+2, cast(to_fixed(b * 255)) ); + #endif + } return; + + case Op_store_8888: { + store(dst + 4*i, cast(to_fixed(r * 255)) << 0 + | cast(to_fixed(g * 255)) << 8 + | cast(to_fixed(b * 255)) << 16 + | cast(to_fixed(a * 255)) << 24); + } return; + + case Op_store_101010x_XR: { + static constexpr float min = -0.752941f; + static constexpr float max = 1.25098f; + static constexpr float range = max - min; + store(dst + 4*i, cast(to_fixed(((r - min) / range) * 1023)) << 0 + | cast(to_fixed(((g - min) / range) * 1023)) << 10 + | cast(to_fixed(((b - min) / range) * 1023)) << 20); + return; + } + case Op_store_1010102: { + store(dst + 4*i, cast(to_fixed(r * 1023)) << 0 + | cast(to_fixed(g * 1023)) << 10 + | cast(to_fixed(b * 1023)) << 20 + | cast(to_fixed(a * 3)) << 30); + } return; + + case Op_store_161616LE: { + uintptr_t ptr = (uintptr_t)(dst + 6*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgb = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x3_t v = {{ + (uint16x8_t)U16_from_F(r), + (uint16x8_t)U16_from_F(g), + (uint16x8_t)U16_from_F(b), + }}; + vst3q_u16(rgb, v); + #elif defined(USING_NEON) + uint16x4x3_t v = {{ + (uint16x4_t)U16_from_F(r), + (uint16x4_t)U16_from_F(g), + (uint16x4_t)U16_from_F(b), + }}; + vst3_u16(rgb, v); + #else + store_3(rgb+0, U16_from_F(r)); + store_3(rgb+1, U16_from_F(g)); + store_3(rgb+2, U16_from_F(b)); + #endif + + } return; + + case Op_store_16161616LE: { + uintptr_t ptr = (uintptr_t)(dst + 8*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgba = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x4_t v = {{ + (uint16x8_t)U16_from_F(r), + (uint16x8_t)U16_from_F(g), + (uint16x8_t)U16_from_F(b), + (uint16x8_t)U16_from_F(a), + }}; + vst4q_u16(rgba, v); + #elif defined(USING_NEON) + uint16x4x4_t v = {{ + (uint16x4_t)U16_from_F(r), + (uint16x4_t)U16_from_F(g), + (uint16x4_t)U16_from_F(b), + (uint16x4_t)U16_from_F(a), + }}; + vst4_u16(rgba, v); + #else + U64 px = cast(to_fixed(r * 65535)) << 0 + | cast(to_fixed(g * 65535)) << 16 + | cast(to_fixed(b * 65535)) << 32 + | cast(to_fixed(a * 65535)) << 48; + store(rgba, px); + #endif + } return; + + case Op_store_161616BE: { + uintptr_t ptr = (uintptr_t)(dst + 6*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgb = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x3_t v = {{ + (uint16x8_t)swap_endian_16(U16_from_F(r)), + (uint16x8_t)swap_endian_16(U16_from_F(g)), + (uint16x8_t)swap_endian_16(U16_from_F(b)), + }}; + vst3q_u16(rgb, v); + #elif defined(USING_NEON) + uint16x4x3_t v = {{ + (uint16x4_t)swap_endian_16(cast(U16_from_F(r))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(g))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(b))), + }}; + vst3_u16(rgb, v); + #else + U32 R = to_fixed(r * 65535), + G = to_fixed(g * 65535), + B = to_fixed(b * 65535); + store_3(rgb+0, cast((R & 0x00ff) << 8 | (R & 0xff00) >> 8) ); + store_3(rgb+1, cast((G & 0x00ff) << 8 | (G & 0xff00) >> 8) ); + store_3(rgb+2, cast((B & 0x00ff) << 8 | (B & 0xff00) >> 8) ); + #endif + + } return; + + case Op_store_16161616BE: { + uintptr_t ptr = (uintptr_t)(dst + 8*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgba = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + #if defined(USING_NEON_FP16) + uint16x8x4_t v = {{ + (uint16x8_t)swap_endian_16(U16_from_F(r)), + (uint16x8_t)swap_endian_16(U16_from_F(g)), + (uint16x8_t)swap_endian_16(U16_from_F(b)), + (uint16x8_t)swap_endian_16(U16_from_F(a)), + }}; + vst4q_u16(rgba, v); + #elif defined(USING_NEON) + uint16x4x4_t v = {{ + (uint16x4_t)swap_endian_16(cast(U16_from_F(r))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(g))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(b))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(a))), + }}; + vst4_u16(rgba, v); + #else + U64 px = cast(to_fixed(r * 65535)) << 0 + | cast(to_fixed(g * 65535)) << 16 + | cast(to_fixed(b * 65535)) << 32 + | cast(to_fixed(a * 65535)) << 48; + store(rgba, swap_endian_16x4(px)); + #endif + } return; + + case Op_store_hhh: { + uintptr_t ptr = (uintptr_t)(dst + 6*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgb = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + + U16 R = Half_from_F(r), + G = Half_from_F(g), + B = Half_from_F(b); + #if defined(USING_NEON_FP16) + uint16x8x3_t v = {{ + (uint16x8_t)R, + (uint16x8_t)G, + (uint16x8_t)B, + }}; + vst3q_u16(rgb, v); + #elif defined(USING_NEON) + uint16x4x3_t v = {{ + (uint16x4_t)R, + (uint16x4_t)G, + (uint16x4_t)B, + }}; + vst3_u16(rgb, v); + #else + store_3(rgb+0, R); + store_3(rgb+1, G); + store_3(rgb+2, B); + #endif + } return; + + case Op_store_hhhh: { + uintptr_t ptr = (uintptr_t)(dst + 8*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgba = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + + U16 R = Half_from_F(r), + G = Half_from_F(g), + B = Half_from_F(b), + A = Half_from_F(a); + #if defined(USING_NEON_FP16) + uint16x8x4_t v = {{ + (uint16x8_t)R, + (uint16x8_t)G, + (uint16x8_t)B, + (uint16x8_t)A, + }}; + vst4q_u16(rgba, v); + #elif defined(USING_NEON) + uint16x4x4_t v = {{ + (uint16x4_t)R, + (uint16x4_t)G, + (uint16x4_t)B, + (uint16x4_t)A, + }}; + vst4_u16(rgba, v); + #else + store(rgba, cast(R) << 0 + | cast(G) << 16 + | cast(B) << 32 + | cast(A) << 48); + #endif + + } return; + + case Op_store_fff: { + uintptr_t ptr = (uintptr_t)(dst + 12*i); + assert( (ptr & 3) == 0 ); // The dst pointer must be 4-byte aligned + float* rgb = (float*)ptr; // for this cast to float* to be safe. + #if defined(USING_NEON_FP16) + float32x4x3_t lo = {{ + vcvt_f32_f16(vget_low_f16(r)), + vcvt_f32_f16(vget_low_f16(g)), + vcvt_f32_f16(vget_low_f16(b)), + }}, hi = {{ + vcvt_f32_f16(vget_high_f16(r)), + vcvt_f32_f16(vget_high_f16(g)), + vcvt_f32_f16(vget_high_f16(b)), + }}; + vst3q_f32(rgb + 0, lo); + vst3q_f32(rgb + 12, hi); + #elif defined(USING_NEON) + float32x4x3_t v = {{ + (float32x4_t)r, + (float32x4_t)g, + (float32x4_t)b, + }}; + vst3q_f32(rgb, v); + #else + store_3(rgb+0, r); + store_3(rgb+1, g); + store_3(rgb+2, b); + #endif + } return; + + case Op_store_ffff: { + uintptr_t ptr = (uintptr_t)(dst + 16*i); + assert( (ptr & 3) == 0 ); // The dst pointer must be 4-byte aligned + float* rgba = (float*)ptr; // for this cast to float* to be safe. + #if defined(USING_NEON_FP16) + float32x4x4_t lo = {{ + vcvt_f32_f16(vget_low_f16(r)), + vcvt_f32_f16(vget_low_f16(g)), + vcvt_f32_f16(vget_low_f16(b)), + vcvt_f32_f16(vget_low_f16(a)), + }}, hi = {{ + vcvt_f32_f16(vget_high_f16(r)), + vcvt_f32_f16(vget_high_f16(g)), + vcvt_f32_f16(vget_high_f16(b)), + vcvt_f32_f16(vget_high_f16(a)), + }}; + vst4q_f32(rgba + 0, lo); + vst4q_f32(rgba + 16, hi); + #elif defined(USING_NEON) + float32x4x4_t v = {{ + (float32x4_t)r, + (float32x4_t)g, + (float32x4_t)b, + (float32x4_t)a, + }}; + vst4q_f32(rgba, v); + #else + store_4(rgba+0, r); + store_4(rgba+1, g); + store_4(rgba+2, b); + store_4(rgba+3, a); + #endif + } return; + } + } +} + + +static void run_program(const Op* program, const void** arguments, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp) { + int i = 0; + while (n >= N) { + exec_ops(program, arguments, src, dst, i); + i += N; + n -= N; + } + if (n > 0) { + char tmp[4*4*N] = {0}; + + memcpy(tmp, (const char*)src + (size_t)i*src_bpp, (size_t)n*src_bpp); + exec_ops(program, arguments, tmp, tmp, 0); + memcpy((char*)dst + (size_t)i*dst_bpp, tmp, (size_t)n*dst_bpp); + } +} + +// Clean up any #defines we may have set so that we can be #included again. +#if defined(USING_AVX) + #undef USING_AVX +#endif +#if defined(USING_AVX_F16C) + #undef USING_AVX_F16C +#endif +#if defined(USING_AVX2) + #undef USING_AVX2 +#endif +#if defined(USING_AVX512F) + #undef USING_AVX512F +#endif + +#if defined(USING_NEON) + #undef USING_NEON +#endif +#if defined(USING_NEON_F16C) + #undef USING_NEON_F16C +#endif +#if defined(USING_NEON_FP16) + #undef USING_NEON_FP16 +#endif + +#undef FALLTHROUGH diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/DartTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/DartTypes.h new file mode 100644 index 00000000000000..289a9ffd99fea9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/DartTypes.h @@ -0,0 +1,153 @@ +// Copyright 2019 Google LLC. + +#ifndef DartTypes_DEFINED +#define DartTypes_DEFINED + +#include "include/core/SkRect.h" +#include "include/core/SkTypes.h" + +#include +#include +#include + +namespace skia { +namespace textlayout { + +enum Affinity { kUpstream, kDownstream }; + +enum class RectHeightStyle { + // Provide tight bounding boxes that fit heights per run. + kTight, + + // The height of the boxes will be the maximum height of all runs in the + // line. All rects in the same line will be the same height. + kMax, + + // Extends the top and/or bottom edge of the bounds to fully cover any line + // spacing. The top edge of each line should be the same as the bottom edge + // of the line above. There should be no gaps in vertical coverage given any + // ParagraphStyle line_height. + // + // The top and bottom of each rect will cover half of the + // space above and half of the space below the line. + kIncludeLineSpacingMiddle, + // The line spacing will be added to the top of the rect. + kIncludeLineSpacingTop, + // The line spacing will be added to the bottom of the rect. + kIncludeLineSpacingBottom, + // + kStrut +}; + +enum class RectWidthStyle { + // Provide tight bounding boxes that fit widths to the runs of each line + // independently. + kTight, + + // Extends the width of the last rect of each line to match the position of + // the widest rect over all the lines. + kMax +}; + +enum class TextAlign { + kLeft, + kRight, + kCenter, + kJustify, + kStart, + kEnd, +}; + +enum class TextDirection { + kRtl, + kLtr, +}; + +struct PositionWithAffinity { + int32_t position; + Affinity affinity; + + PositionWithAffinity() : position(0), affinity(kDownstream) {} + PositionWithAffinity(int32_t p, Affinity a) : position(p), affinity(a) {} +}; + +struct TextBox { + SkRect rect; + TextDirection direction; + + TextBox(SkRect r, TextDirection d) : rect(r), direction(d) {} +}; + +// ------------------------------------------------------------------- +// --- Reversed iterable + +template +UnaryFunction directional_for_each(C& c, bool forwards, UnaryFunction f) { + return forwards + ? std::for_each(std::begin(c), std::end(c), f) + : std::for_each(std::rbegin(c), std::rend(c), f); +} + +const size_t EMPTY_INDEX = std::numeric_limits::max(); +template struct SkRange { + SkRange() : start(), end() {} + SkRange(T s, T e) : start(s), end(e) {} + + using SignedT = std::make_signed_t; + + T start, end; + + bool operator==(const SkRange& other) const { + return start == other.start && end == other.end; + } + + T width() const { return end - start; } + + void Shift(SignedT delta) { + start += delta; + end += delta; + } + + bool contains(SkRange other) const { + return start <= other.start && end >= other.end; + } + + bool intersects(SkRange other) const { + return std::max(start, other.start) <= std::min(end, other.end); + } + + SkRange intersection(SkRange other) const { + return SkRange(std::max(start, other.start), std::min(end, other.end)); + } + + bool empty() const { + return start == EMPTY_INDEX && end == EMPTY_INDEX; + } +}; + +const SkRange EMPTY_RANGE = SkRange(EMPTY_INDEX, EMPTY_INDEX); + + +enum class TextBaseline { + kAlphabetic, + kIdeographic, +}; + +enum TextHeightBehavior { + kAll = 0x0, + kDisableFirstAscent = 0x1, + kDisableLastDescent = 0x2, + kDisableAll = 0x1 | 0x2, +}; + +enum class LineMetricStyle : uint8_t { + // Use ascent, descent, etc from a fixed baseline. + Typographic, + // Use ascent, descent, etc like css with the leading split and with height adjustments + CSS +}; + +} // namespace textlayout +} // namespace skia + +#endif // DartTypes_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/FontArguments.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/FontArguments.h new file mode 100644 index 00000000000000..9560c0f18ca9f8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/FontArguments.h @@ -0,0 +1,46 @@ +// Copyright 2019 Google LLC. +#ifndef FontArguments_DEFINED +#define FontArguments_DEFINED + +#include +#include +#include "include/core/SkFontArguments.h" +#include "include/core/SkTypeface.h" + +namespace skia { +namespace textlayout { + +class FontArguments { +public: + FontArguments(const SkFontArguments&); + FontArguments(const FontArguments&) = default; + FontArguments(FontArguments&&) = default; + + FontArguments& operator=(const FontArguments&) = default; + FontArguments& operator=(FontArguments&&) = default; + + sk_sp CloneTypeface(sk_sp typeface) const; + + friend bool operator==(const FontArguments& a, const FontArguments& b); + friend bool operator!=(const FontArguments& a, const FontArguments& b); + friend struct std::hash; + +private: + FontArguments() = delete; + + int fCollectionIndex; + std::vector fCoordinates; + int fPaletteIndex; + std::vector fPaletteOverrides; +}; + +} // namespace textlayout +} // namespace skia + +namespace std { + template<> struct hash { + size_t operator()(const skia::textlayout::FontArguments& args) const; + }; +} + +#endif // FontArguments_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/FontCollection.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/FontCollection.h new file mode 100644 index 00000000000000..bc895f99c6e81e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/FontCollection.h @@ -0,0 +1,84 @@ +// Copyright 2019 Google LLC. +#ifndef FontCollection_DEFINED +#define FontCollection_DEFINED + +#include +#include +#include +#include "include/core/SkFontMgr.h" +#include "include/core/SkRefCnt.h" +#include "modules/skparagraph/include/FontArguments.h" +#include "modules/skparagraph/include/ParagraphCache.h" +#include "modules/skparagraph/include/TextStyle.h" +#include "src/core/SkTHash.h" + +namespace skia { +namespace textlayout { + +class TextStyle; +class Paragraph; +class FontCollection : public SkRefCnt { +public: + FontCollection(); + + size_t getFontManagersCount() const; + + void setAssetFontManager(sk_sp fontManager); + void setDynamicFontManager(sk_sp fontManager); + void setTestFontManager(sk_sp fontManager); + void setDefaultFontManager(sk_sp fontManager); + void setDefaultFontManager(sk_sp fontManager, const char defaultFamilyName[]); + void setDefaultFontManager(sk_sp fontManager, const std::vector& defaultFamilyNames); + + sk_sp getFallbackManager() const { return fDefaultFontManager; } + + std::vector> findTypefaces(const std::vector& familyNames, SkFontStyle fontStyle); + std::vector> findTypefaces(const std::vector& familyNames, SkFontStyle fontStyle, const std::optional& fontArgs); + + sk_sp defaultFallback(SkUnichar unicode, SkFontStyle fontStyle, const SkString& locale); + sk_sp defaultFallback(); + + void disableFontFallback(); + void enableFontFallback(); + bool fontFallbackEnabled() { return fEnableFontFallback; } + + ParagraphCache* getParagraphCache() { return &fParagraphCache; } + + void clearCaches(); + +private: + std::vector> getFontManagerOrder() const; + + sk_sp matchTypeface(const SkString& familyName, SkFontStyle fontStyle); + + struct FamilyKey { + FamilyKey(const std::vector& familyNames, SkFontStyle style, const std::optional& args) + : fFamilyNames(familyNames), fFontStyle(style), fFontArguments(args) {} + + FamilyKey() {} + + std::vector fFamilyNames; + SkFontStyle fFontStyle; + std::optional fFontArguments; + + bool operator==(const FamilyKey& other) const; + + struct Hasher { + size_t operator()(const FamilyKey& key) const; + }; + }; + + bool fEnableFontFallback; + skia_private::THashMap>, FamilyKey::Hasher> fTypefaces; + sk_sp fDefaultFontManager; + sk_sp fAssetFontManager; + sk_sp fDynamicFontManager; + sk_sp fTestFontManager; + + std::vector fDefaultFamilyNames; + ParagraphCache fParagraphCache; +}; +} // namespace textlayout +} // namespace skia + +#endif // FontCollection_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/Metrics.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/Metrics.h new file mode 100644 index 00000000000000..4b8581ef7f55d4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/Metrics.h @@ -0,0 +1,98 @@ +// Copyright 2019 Google LLC. +#ifndef Metrics_DEFINED +#define Metrics_DEFINED + +#include +#include "modules/skparagraph/include/TextStyle.h" + +namespace skia { +namespace textlayout { +class StyleMetrics { +public: + StyleMetrics(const TextStyle* style) : text_style(style) {} + + StyleMetrics(const TextStyle* style, SkFontMetrics& metrics) + : text_style(style), font_metrics(metrics) {} + + const TextStyle* text_style; + + // SkFontMetrics contains the following metrics: + // + // * Top distance to reserve above baseline + // * Ascent distance to reserve below baseline + // * Descent extent below baseline + // * Bottom extent below baseline + // * Leading distance to add between lines + // * AvgCharWidth average character width + // * MaxCharWidth maximum character width + // * XMin minimum x + // * XMax maximum x + // * XHeight height of lower-case 'x' + // * CapHeight height of an upper-case letter + // * UnderlineThickness underline thickness + // * UnderlinePosition underline position relative to baseline + // * StrikeoutThickness strikeout thickness + // * StrikeoutPosition strikeout position relative to baseline + SkFontMetrics font_metrics; +}; + +class LineMetrics { +public: + LineMetrics() { } + + LineMetrics(size_t start, + size_t end, + size_t end_excluding_whitespace, + size_t end_including_newline, + bool hard_break) + : fStartIndex(start) + , fEndIndex(end) + , fEndExcludingWhitespaces(end_excluding_whitespace) + , fEndIncludingNewline(end_including_newline) + , fHardBreak(hard_break) {} + // The following fields are used in the layout process itself. + + // The indexes in the text buffer the line begins and ends. + size_t fStartIndex = 0; + size_t fEndIndex = 0; + size_t fEndExcludingWhitespaces = 0; + size_t fEndIncludingNewline = 0; + bool fHardBreak = false; + + // The following fields are tracked after or during layout to provide to + // the user as well as for computing bounding boxes. + + // The final computed ascent and descent for the line. This can be impacted by + // the strut, height, scaling, as well as outlying runs that are very tall. + // + // The top edge is `baseline - ascent` and the bottom edge is `baseline + + // descent`. Ascent and descent are provided as positive numbers. Raw numbers + // for specific runs of text can be obtained in run_metrics_map. These values + // are the cumulative metrics for the entire line. + double fAscent = SK_ScalarMax; + double fDescent = SK_ScalarMin; + double fUnscaledAscent = SK_ScalarMax; + // Total height of the paragraph including the current line. + // + // The height of the current line is `round(ascent + descent)`. + double fHeight = 0.0; + // Width of the line. + double fWidth = 0.0; + // The left edge of the line. The right edge can be obtained with `left + + // width` + double fLeft = 0.0; + // The y position of the baseline for this line from the top of the paragraph. + double fBaseline = 0.0; + // Zero indexed line number + size_t fLineNumber = 0; + + // Mapping between text index ranges and the FontMetrics associated with + // them. The first run will be keyed under start_index. The metrics here + // are before layout and are the base values we calculate from. + std::map fLineMetrics; +}; + +} // namespace textlayout +} // namespace skia + +#endif // Metrics_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/Paragraph.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/Paragraph.h new file mode 100644 index 00000000000000..c78b0798412a1e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/Paragraph.h @@ -0,0 +1,181 @@ +// Copyright 2019 Google LLC. +#ifndef Paragraph_DEFINED +#define Paragraph_DEFINED + +#include "modules/skparagraph/include/FontCollection.h" +#include "modules/skparagraph/include/Metrics.h" +#include "modules/skparagraph/include/ParagraphStyle.h" +#include "modules/skparagraph/include/TextStyle.h" + +class SkCanvas; + +namespace skia { +namespace textlayout { + +class ParagraphPainter; + +class Paragraph { + +public: + Paragraph(ParagraphStyle style, sk_sp fonts); + + virtual ~Paragraph() = default; + + SkScalar getMaxWidth() { return fWidth; } + + SkScalar getHeight() { return fHeight; } + + SkScalar getMinIntrinsicWidth() { return fMinIntrinsicWidth; } + + SkScalar getMaxIntrinsicWidth() { return fMaxIntrinsicWidth; } + + SkScalar getAlphabeticBaseline() { return fAlphabeticBaseline; } + + SkScalar getIdeographicBaseline() { return fIdeographicBaseline; } + + SkScalar getLongestLine() { return fLongestLine; } + + bool didExceedMaxLines() { return fExceededMaxLines; } + + virtual void layout(SkScalar width) = 0; + + virtual void paint(SkCanvas* canvas, SkScalar x, SkScalar y) = 0; + + virtual void paint(ParagraphPainter* painter, SkScalar x, SkScalar y) = 0; + + // Returns a vector of bounding boxes that enclose all text between + // start and end glyph indexes, including start and excluding end + virtual std::vector getRectsForRange(unsigned start, + unsigned end, + RectHeightStyle rectHeightStyle, + RectWidthStyle rectWidthStyle) = 0; + + virtual std::vector getRectsForPlaceholders() = 0; + + // Returns the index of the glyph that corresponds to the provided coordinate, + // with the top left corner as the origin, and +y direction as down + virtual PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) = 0; + + // Finds the first and last glyphs that define a word containing + // the glyph at index offset + virtual SkRange getWordBoundary(unsigned offset) = 0; + + virtual void getLineMetrics(std::vector&) = 0; + + virtual size_t lineNumber() = 0; + + virtual void markDirty() = 0; + + // This function will return the number of unresolved glyphs or + // -1 if not applicable (has not been shaped yet - valid case) + virtual int32_t unresolvedGlyphs() = 0; + + // Experimental API that allows fast way to update some of "immutable" paragraph attributes + // but not the text itself + virtual void updateTextAlign(TextAlign textAlign) = 0; + virtual void updateFontSize(size_t from, size_t to, SkScalar fontSize) = 0; + virtual void updateForegroundPaint(size_t from, size_t to, SkPaint paint) = 0; + virtual void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) = 0; + + enum VisitorFlags { + kWhiteSpace_VisitorFlag = 1 << 0, + }; + struct VisitorInfo { + const SkFont& font; + SkPoint origin; + SkScalar advanceX; + int count; + const uint16_t* glyphs; // count values + const SkPoint* positions; // count values + const uint32_t* utf8Starts; // count+1 values + unsigned flags; + }; + + // lineNumber begins at 0. If info is null, this signals the end of that line. + using Visitor = std::function; + virtual void visit(const Visitor&) = 0; + + // Editing API + virtual int getLineNumberAt(TextIndex codeUnitIndex) const = 0; + + /* Returns line metrics info for the line + * + * @param lineNumber a line number + * @param lineMetrics an address to return the info (in case of null just skipped) + * @return true if the line is found; false if not + */ + virtual bool getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const = 0; + + /* Returns the visible text on the line (excluding a possible ellipsis) + * + * @param lineNumber a line number + * @param includeSpaces indicates if the whitespaces should be included + * @return the range of the text that is shown in the line + */ + virtual TextRange getActualTextRange(int lineNumber, bool includeSpaces) const = 0; + + struct GlyphClusterInfo { + SkRect fBounds; + TextRange fClusterTextRange; + TextDirection fGlyphClusterPosition; + }; + + /** Finds a glyph cluster for text index + * + * @param codeUnitIndex a text index + * @param glyphInfo a glyph cluster info filled if not null + * @return true if glyph cluster was found; false if not + */ + virtual bool getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) = 0; + + /** Finds the closest glyph cluster for a visual text position + * + * @param dx x coordinate + * @param dy y coordinate + * @param glyphInfo a glyph cluster info filled if not null + * @return + */ + virtual bool getClosestGlyphClusterAt(SkScalar dx, + SkScalar dy, + GlyphClusterInfo* glyphInfo) = 0; + + struct FontInfo { + FontInfo(const SkFont font, const TextRange textRange) + : fFont(font), fTextRange(textRange) { } + virtual ~FontInfo() = default; + FontInfo(const FontInfo& ) = default; + SkFont fFont; + TextRange fTextRange; + }; + + /** Returns the font that is used to shape the text at the position + * + * @param codeUnitIndex text index + * @return font info or an empty font info if the text is not found + */ + virtual SkFont getFontAt(TextIndex codeUnitIndex) const = 0; + + /** Returns the information about all the fonts used to shape the paragraph text + * + * @return a list of fonts and text ranges + */ + virtual std::vector getFonts() const = 0; + +protected: + sk_sp fFontCollection; + ParagraphStyle fParagraphStyle; + + // Things for Flutter + SkScalar fAlphabeticBaseline; + SkScalar fIdeographicBaseline; + SkScalar fHeight; + SkScalar fWidth; + SkScalar fMaxIntrinsicWidth; + SkScalar fMinIntrinsicWidth; + SkScalar fLongestLine; + bool fExceededMaxLines; +}; +} // namespace textlayout +} // namespace skia + +#endif // Paragraph_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphBuilder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphBuilder.h new file mode 100644 index 00000000000000..a76d4b0bb3172d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphBuilder.h @@ -0,0 +1,69 @@ +// Copyright 2019 Google LLC. +#ifndef ParagraphBuilder_DEFINED +#define ParagraphBuilder_DEFINED + +#include +#include +#include +#include +#include "modules/skparagraph/include/FontCollection.h" +#include "modules/skparagraph/include/Paragraph.h" +#include "modules/skparagraph/include/ParagraphStyle.h" +#include "modules/skparagraph/include/TextStyle.h" + +namespace skia { +namespace textlayout { + +class ParagraphBuilder { +public: + ParagraphBuilder(const ParagraphStyle&, sk_sp) { } + + virtual ~ParagraphBuilder() = default; + + // Push a style to the stack. The corresponding text added with AddText will + // use the top-most style. + virtual void pushStyle(const TextStyle& style) = 0; + + // Remove a style from the stack. Useful to apply different styles to chunks + // of text such as bolding. + // Example: + // builder.PushStyle(normal_style); + // builder.AddText("Hello this is normal. "); + // + // builder.PushStyle(bold_style); + // builder.AddText("And this is BOLD. "); + // + // builder.Pop(); + // builder.AddText(" Back to normal again."); + virtual void pop() = 0; + + virtual TextStyle peekStyle() = 0; + + // Adds UTF16-encoded text to the builder. Forms the proper runs to use the upper-most style + // on the style_stack. + virtual void addText(const std::u16string& text) = 0; + + // Adds UTF8-encoded text to the builder, using the top-most style on the style_stack. + virtual void addText(const char* text) = 0; + virtual void addText(const char* text, size_t len) = 0; + + // Pushes the information required to leave an open space, where Flutter may + // draw a custom placeholder into. + // Internally, this method adds a single object replacement character (0xFFFC) + virtual void addPlaceholder(const PlaceholderStyle& placeholderStyle) = 0; + + // Constructs a SkParagraph object that can be used to layout and paint the text to a SkCanvas. + virtual std::unique_ptr Build() = 0; + + // Resets this builder to its initial state, discarding any text, styles, placeholders that have + // been added, but keeping the initial ParagraphStyle. + virtual void Reset() = 0; + + // Just until we fix all the google3 code + static std::unique_ptr make(const ParagraphStyle& style, + sk_sp fontCollection); +}; +} // namespace textlayout +} // namespace skia + +#endif // ParagraphBuilder_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphCache.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphCache.h new file mode 100644 index 00000000000000..45652ae79912cf --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphCache.h @@ -0,0 +1,67 @@ +// Copyright 2019 Google LLC. +#ifndef ParagraphCache_DEFINED +#define ParagraphCache_DEFINED + +#include "include/private/base/SkMutex.h" +#include "src/core/SkLRUCache.h" +#include // std::function + +#define PARAGRAPH_CACHE_STATS + +namespace skia { +namespace textlayout { + +class ParagraphImpl; +class ParagraphCacheKey; +class ParagraphCacheValue; + +class ParagraphCache { +public: + ParagraphCache(); + ~ParagraphCache(); + + void abandon(); + void reset(); + bool updateParagraph(ParagraphImpl* paragraph); + bool findParagraph(ParagraphImpl* paragraph); + + // For testing + void setChecker(std::function checker) { + fChecker = std::move(checker); + } + void printStatistics(); + void turnOn(bool value) { fCacheIsOn = value; } + int count() { return fLRUCacheMap.count(); } + + bool isPossiblyTextEditing(ParagraphImpl* paragraph); + + private: + + struct Entry; + void updateFrom(const ParagraphImpl* paragraph, Entry* entry); + void updateTo(ParagraphImpl* paragraph, const Entry* entry); + + mutable SkMutex fParagraphMutex; + std::function fChecker; + + static const int kMaxEntries = 128; + + struct KeyHash { + uint32_t operator()(const ParagraphCacheKey& key) const; + }; + + SkLRUCache, KeyHash> fLRUCacheMap; + bool fCacheIsOn; + ParagraphCacheValue* fLastCachedValue; + +#ifdef PARAGRAPH_CACHE_STATS + int fTotalRequests; + int fCacheMisses; + int fHashMisses; // cache hit but hash table missed +#endif +}; + +} // namespace textlayout +} // namespace skia + +#endif // ParagraphCache_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphPainter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphPainter.h new file mode 100644 index 00000000000000..56388e64f17bd5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphPainter.h @@ -0,0 +1,63 @@ +// Copyright 2019 Google LLC. +#ifndef ParagraphPainter_DEFINED +#define ParagraphPainter_DEFINED + +#include "include/core/SkPaint.h" +#include "include/core/SkTextBlob.h" + +#include +#include + +namespace skia { +namespace textlayout { + +class ParagraphPainter { +public: + typedef int PaintID; + typedef std::variant SkPaintOrID; + + struct DashPathEffect { + DashPathEffect(SkScalar onLength, SkScalar offLength); + + SkScalar fOnLength; + SkScalar fOffLength; + }; + + class DecorationStyle { + public: + DecorationStyle(); + DecorationStyle(SkColor color, SkScalar strokeWidth, + std::optional dashPathEffect); + + SkColor getColor() const { return fColor; } + SkScalar getStrokeWidth() const { return fStrokeWidth; } + std::optional getDashPathEffect() const { return fDashPathEffect; } + const SkPaint& skPaint() const { return fPaint; } + + private: + SkColor fColor; + SkScalar fStrokeWidth; + std::optional fDashPathEffect; + SkPaint fPaint; + }; + + virtual ~ParagraphPainter() = default; + + virtual void drawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y, const SkPaintOrID& paint) = 0; + virtual void drawTextShadow(const sk_sp& blob, SkScalar x, SkScalar y, SkColor color, SkScalar blurSigma) = 0; + virtual void drawRect(const SkRect& rect, const SkPaintOrID& paint) = 0; + virtual void drawFilledRect(const SkRect& rect, const DecorationStyle& decorStyle) = 0; + virtual void drawPath(const SkPath& path, const DecorationStyle& decorStyle) = 0; + virtual void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const DecorationStyle& decorStyle) = 0; + + virtual void clipRect(const SkRect& rect) = 0; + virtual void translate(SkScalar dx, SkScalar dy) = 0; + + virtual void save() = 0; + virtual void restore() = 0; +}; + +} // namespace textlayout +} // namespace skia + +#endif // ParagraphPainter_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphStyle.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphStyle.h new file mode 100644 index 00000000000000..5139571ddb0bae --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/ParagraphStyle.h @@ -0,0 +1,143 @@ +// Copyright 2019 Google LLC. +#ifndef ParagraphStyle_DEFINED +#define ParagraphStyle_DEFINED + +#include "include/core/SkFontStyle.h" +#include "include/core/SkScalar.h" +#include "include/core/SkString.h" +#include "modules/skparagraph/include/DartTypes.h" +#include "modules/skparagraph/include/TextStyle.h" + +#include +#include +#include +#include +#include +#include + +namespace skia { +namespace textlayout { + +struct StrutStyle { + StrutStyle(); + + const std::vector& getFontFamilies() const { return fFontFamilies; } + void setFontFamilies(std::vector families) { fFontFamilies = std::move(families); } + + SkFontStyle getFontStyle() const { return fFontStyle; } + void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; } + + SkScalar getFontSize() const { return fFontSize; } + void setFontSize(SkScalar size) { fFontSize = size; } + + void setHeight(SkScalar height) { fHeight = height; } + SkScalar getHeight() const { return fHeight; } + + void setLeading(SkScalar Leading) { fLeading = Leading; } + SkScalar getLeading() const { return fLeading; } + + bool getStrutEnabled() const { return fEnabled; } + void setStrutEnabled(bool v) { fEnabled = v; } + + bool getForceStrutHeight() const { return fForceHeight; } + void setForceStrutHeight(bool v) { fForceHeight = v; } + + bool getHeightOverride() const { return fHeightOverride; } + void setHeightOverride(bool v) { fHeightOverride = v; } + + void setHalfLeading(bool halfLeading) { fHalfLeading = halfLeading; } + bool getHalfLeading() const { return fHalfLeading; } + + bool operator==(const StrutStyle& rhs) const { + return this->fEnabled == rhs.fEnabled && + this->fHeightOverride == rhs.fHeightOverride && + this->fForceHeight == rhs.fForceHeight && + this->fHalfLeading == rhs.fHalfLeading && + nearlyEqual(this->fLeading, rhs.fLeading) && + nearlyEqual(this->fHeight, rhs.fHeight) && + nearlyEqual(this->fFontSize, rhs.fFontSize) && + this->fFontStyle == rhs.fFontStyle && + this->fFontFamilies == rhs.fFontFamilies; + } + +private: + + std::vector fFontFamilies; + SkFontStyle fFontStyle; + SkScalar fFontSize; + SkScalar fHeight; + SkScalar fLeading; + bool fForceHeight; + bool fEnabled; + bool fHeightOverride; + // true: half leading. + // false: scale ascent/descent with fHeight. + bool fHalfLeading; +}; + +struct ParagraphStyle { + ParagraphStyle(); + + bool operator==(const ParagraphStyle& rhs) const { + return this->fHeight == rhs.fHeight && + this->fEllipsis == rhs.fEllipsis && + this->fEllipsisUtf16 == rhs.fEllipsisUtf16 && + this->fTextDirection == rhs.fTextDirection && this->fTextAlign == rhs.fTextAlign && + this->fDefaultTextStyle == rhs.fDefaultTextStyle && + this->fReplaceTabCharacters == rhs.fReplaceTabCharacters; + } + + const StrutStyle& getStrutStyle() const { return fStrutStyle; } + void setStrutStyle(StrutStyle strutStyle) { fStrutStyle = std::move(strutStyle); } + + const TextStyle& getTextStyle() const { return fDefaultTextStyle; } + void setTextStyle(const TextStyle& textStyle) { fDefaultTextStyle = textStyle; } + + TextDirection getTextDirection() const { return fTextDirection; } + void setTextDirection(TextDirection direction) { fTextDirection = direction; } + + TextAlign getTextAlign() const { return fTextAlign; } + void setTextAlign(TextAlign align) { fTextAlign = align; } + + size_t getMaxLines() const { return fLinesLimit; } + void setMaxLines(size_t maxLines) { fLinesLimit = maxLines; } + + SkString getEllipsis() const { return fEllipsis; } + std::u16string getEllipsisUtf16() const { return fEllipsisUtf16; } + void setEllipsis(const std::u16string& ellipsis) { fEllipsisUtf16 = ellipsis; } + void setEllipsis(const SkString& ellipsis) { fEllipsis = ellipsis; } + + SkScalar getHeight() const { return fHeight; } + void setHeight(SkScalar height) { fHeight = height; } + + TextHeightBehavior getTextHeightBehavior() const { return fTextHeightBehavior; } + void setTextHeightBehavior(TextHeightBehavior v) { fTextHeightBehavior = v; } + + bool unlimited_lines() const { + return fLinesLimit == std::numeric_limits::max(); + } + bool ellipsized() const { return !fEllipsis.isEmpty() || !fEllipsisUtf16.empty(); } + TextAlign effective_align() const; + bool hintingIsOn() const { return fHintingIsOn; } + void turnHintingOff() { fHintingIsOn = false; } + + bool getReplaceTabCharacters() const { return fReplaceTabCharacters; } + void setReplaceTabCharacters(bool value) { fReplaceTabCharacters = value; } + +private: + StrutStyle fStrutStyle; + TextStyle fDefaultTextStyle; + TextAlign fTextAlign; + TextDirection fTextDirection; + size_t fLinesLimit; + std::u16string fEllipsisUtf16; + SkString fEllipsis; + SkScalar fHeight; + TextHeightBehavior fTextHeightBehavior; + bool fHintingIsOn; + bool fReplaceTabCharacters; +}; +} // namespace textlayout +} // namespace skia + +#endif // ParagraphStyle_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TextShadow.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TextShadow.h new file mode 100644 index 00000000000000..e2f860992d2d11 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TextShadow.h @@ -0,0 +1,30 @@ +// Copyright 2019 Google LLC. +#ifndef TextShadow_DEFINED +#define TextShadow_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkPoint.h" + +namespace skia { +namespace textlayout { + +class TextShadow { +public: + SkColor fColor = SK_ColorBLACK; + SkPoint fOffset; + double fBlurSigma = 0.0; + + TextShadow(); + + TextShadow(SkColor color, SkPoint offset, double blurSigma); + + bool operator==(const TextShadow& other) const; + + bool operator!=(const TextShadow& other) const; + + bool hasShadow() const; +}; +} // namespace textlayout +} // namespace skia + +#endif // TextShadow_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TextStyle.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TextStyle.h new file mode 100644 index 00000000000000..e6f0ae46302d91 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TextStyle.h @@ -0,0 +1,375 @@ +// Copyright 2019 Google LLC. +#ifndef TextStyle_DEFINED +#define TextStyle_DEFINED + +#include +#include +#include "include/core/SkColor.h" +#include "include/core/SkFont.h" +#include "include/core/SkFontMetrics.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkPaint.h" +#include "include/core/SkScalar.h" +#include "modules/skparagraph/include/DartTypes.h" +#include "modules/skparagraph/include/FontArguments.h" +#include "modules/skparagraph/include/ParagraphPainter.h" +#include "modules/skparagraph/include/TextShadow.h" + +// TODO: Make it external so the other platforms (Android) could use it +#define DEFAULT_FONT_FAMILY "sans-serif" + +namespace skia { +namespace textlayout { + +static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) { + if (SkScalarIsFinite(x)) { + return SkScalarNearlyZero(x, tolerance); + } + return false; +} + +static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) { + if (SkScalarIsFinite(x) && SkScalarIsFinite(x)) { + return SkScalarNearlyEqual(x, y, tolerance); + } + // Inf == Inf, anything else is false + return x == y; +} + +// Multiple decorations can be applied at once. Ex: Underline and overline is +// (0x1 | 0x2) +enum TextDecoration { + kNoDecoration = 0x0, + kUnderline = 0x1, + kOverline = 0x2, + kLineThrough = 0x4, +}; +constexpr TextDecoration AllTextDecorations[] = { + kNoDecoration, + kUnderline, + kOverline, + kLineThrough, +}; + +enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy }; + +enum TextDecorationMode { kGaps, kThrough }; + +enum StyleType { + kNone, + kAllAttributes, + kFont, + kForeground, + kBackground, + kShadow, + kDecorations, + kLetterSpacing, + kWordSpacing +}; + +struct Decoration { + TextDecoration fType; + TextDecorationMode fMode; + SkColor fColor; + TextDecorationStyle fStyle; + SkScalar fThicknessMultiplier; + + bool operator==(const Decoration& other) const { + return this->fType == other.fType && + this->fMode == other.fMode && + this->fColor == other.fColor && + this->fStyle == other.fStyle && + this->fThicknessMultiplier == other.fThicknessMultiplier; + } +}; + +/// Where to vertically align the placeholder relative to the surrounding text. +enum class PlaceholderAlignment { + /// Match the baseline of the placeholder with the baseline. + kBaseline, + + /// Align the bottom edge of the placeholder with the baseline such that the + /// placeholder sits on top of the baseline. + kAboveBaseline, + + /// Align the top edge of the placeholder with the baseline specified in + /// such that the placeholder hangs below the baseline. + kBelowBaseline, + + /// Align the top edge of the placeholder with the top edge of the font. + /// When the placeholder is very tall, the extra space will hang from + /// the top and extend through the bottom of the line. + kTop, + + /// Align the bottom edge of the placeholder with the top edge of the font. + /// When the placeholder is very tall, the extra space will rise from + /// the bottom and extend through the top of the line. + kBottom, + + /// Align the middle of the placeholder with the middle of the text. When the + /// placeholder is very tall, the extra space will grow equally from + /// the top and bottom of the line. + kMiddle, +}; + +struct FontFeature { + FontFeature(const SkString name, int value) : fName(name), fValue(value) {} + bool operator==(const FontFeature& that) const { + return fName == that.fName && fValue == that.fValue; + } + SkString fName; + int fValue; +}; + +struct PlaceholderStyle { + PlaceholderStyle() = default; + PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment, + TextBaseline baseline, SkScalar offset) + : fWidth(width) + , fHeight(height) + , fAlignment(alignment) + , fBaseline(baseline) + , fBaselineOffset(offset) {} + + bool equals(const PlaceholderStyle&) const; + + SkScalar fWidth = 0; + SkScalar fHeight = 0; + PlaceholderAlignment fAlignment = PlaceholderAlignment::kBaseline; + TextBaseline fBaseline = TextBaseline::kAlphabetic; + // Distance from the top edge of the rect to the baseline position. This + // baseline will be aligned against the alphabetic baseline of the surrounding + // text. + // + // Positive values drop the baseline lower (positions the rect higher) and + // small or negative values will cause the rect to be positioned underneath + // the line. When baseline == height, the bottom edge of the rect will rest on + // the alphabetic baseline. + SkScalar fBaselineOffset = 0; +}; + +class TextStyle { +public: + TextStyle() = default; + TextStyle(const TextStyle& other) = default; + TextStyle& operator=(const TextStyle& other) = default; + + TextStyle cloneForPlaceholder(); + + bool equals(const TextStyle& other) const; + bool equalsByFonts(const TextStyle& that) const; + bool matchOneAttribute(StyleType styleType, const TextStyle& other) const; + bool operator==(const TextStyle& rhs) const { return this->equals(rhs); } + + // Colors + SkColor getColor() const { return fColor; } + void setColor(SkColor color) { fColor = color; } + + bool hasForeground() const { return fHasForeground; } + SkPaint getForeground() const { + const SkPaint* paint = std::get_if(&fForeground); + return paint ? *paint : SkPaint(); + } + ParagraphPainter::SkPaintOrID getForegroundPaintOrID() const { + return fForeground; + } + void setForegroundColor(SkPaint paint) { + fHasForeground = true; + fForeground = std::move(paint); + } + // Set the foreground to a paint ID. This is intended for use by clients + // that implement a custom ParagraphPainter that can not accept an SkPaint. + void setForegroundPaintID(ParagraphPainter::PaintID paintID) { + fHasForeground = true; + fForeground = paintID; + } + void clearForegroundColor() { fHasForeground = false; } + + bool hasBackground() const { return fHasBackground; } + SkPaint getBackground() const { + const SkPaint* paint = std::get_if(&fBackground); + return paint ? *paint : SkPaint(); + } + ParagraphPainter::SkPaintOrID getBackgroundPaintOrID() const { + return fBackground; + } + void setBackgroundColor(SkPaint paint) { + fHasBackground = true; + fBackground = std::move(paint); + } + void setBackgroundPaintID(ParagraphPainter::PaintID paintID) { + fHasBackground = true; + fBackground = paintID; + } + void clearBackgroundColor() { fHasBackground = false; } + + // Decorations + Decoration getDecoration() const { return fDecoration; } + TextDecoration getDecorationType() const { return fDecoration.fType; } + TextDecorationMode getDecorationMode() const { return fDecoration.fMode; } + SkColor getDecorationColor() const { return fDecoration.fColor; } + TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; } + SkScalar getDecorationThicknessMultiplier() const { + return fDecoration.fThicknessMultiplier; + } + void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; } + void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; } + void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; } + void setDecorationColor(SkColor color) { fDecoration.fColor = color; } + void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; } + + // Weight/Width/Slant + SkFontStyle getFontStyle() const { return fFontStyle; } + void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; } + + // Shadows + size_t getShadowNumber() const { return fTextShadows.size(); } + std::vector getShadows() const { return fTextShadows; } + void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); } + void resetShadows() { fTextShadows.clear(); } + + // Font features + size_t getFontFeatureNumber() const { return fFontFeatures.size(); } + std::vector getFontFeatures() const { return fFontFeatures; } + void addFontFeature(const SkString& fontFeature, int value) + { fFontFeatures.emplace_back(fontFeature, value); } + void resetFontFeatures() { fFontFeatures.clear(); } + + // Font arguments + const std::optional& getFontArguments() const { return fFontArguments; } + // The contents of the SkFontArguments will be copied into the TextStyle, + // and the SkFontArguments can be safely deleted after setFontArguments returns. + void setFontArguments(const std::optional& args); + + SkScalar getFontSize() const { return fFontSize; } + void setFontSize(SkScalar size) { fFontSize = size; } + + const std::vector& getFontFamilies() const { return fFontFamilies; } + void setFontFamilies(std::vector families) { + fFontFamilies = std::move(families); + } + + SkScalar getBaselineShift() const { return fBaselineShift; } + void setBaselineShift(SkScalar baselineShift) { fBaselineShift = baselineShift; } + + void setHeight(SkScalar height) { fHeight = height; } + SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; } + + void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; } + bool getHeightOverride() const { return fHeightOverride; } + + void setHalfLeading(bool halfLeading) { fHalfLeading = halfLeading; } + bool getHalfLeading() const { return fHalfLeading; } + + void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; } + SkScalar getLetterSpacing() const { return fLetterSpacing; } + + void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; } + SkScalar getWordSpacing() const { return fWordSpacing; } + + SkTypeface* getTypeface() const { return fTypeface.get(); } + sk_sp refTypeface() const { return fTypeface; } + void setTypeface(sk_sp typeface) { fTypeface = std::move(typeface); } + + SkString getLocale() const { return fLocale; } + void setLocale(const SkString& locale) { fLocale = locale; } + + TextBaseline getTextBaseline() const { return fTextBaseline; } + void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; } + + void getFontMetrics(SkFontMetrics* metrics) const; + + bool isPlaceholder() const { return fIsPlaceholder; } + void setPlaceholder() { fIsPlaceholder = true; } + +private: + static const std::vector* kDefaultFontFamilies; + + Decoration fDecoration = { + TextDecoration::kNoDecoration, + // TODO: switch back to kGaps when (if) switching flutter to skparagraph + TextDecorationMode::kThrough, + // It does not make sense to draw a transparent object, so we use this as a default + // value to indicate no decoration color was set. + SK_ColorTRANSPARENT, TextDecorationStyle::kSolid, + // Thickness is applied as a multiplier to the default thickness of the font. + 1.0f}; + + SkFontStyle fFontStyle; + + std::vector fFontFamilies = *kDefaultFontFamilies; + + SkScalar fFontSize = 14.0; + SkScalar fHeight = 1.0; + bool fHeightOverride = false; + SkScalar fBaselineShift = 0.0f; + // true: half leading. + // false: scale ascent/descent with fHeight. + bool fHalfLeading = false; + SkString fLocale = {}; + SkScalar fLetterSpacing = 0.0; + SkScalar fWordSpacing = 0.0; + + TextBaseline fTextBaseline = TextBaseline::kAlphabetic; + + SkColor fColor = SK_ColorWHITE; + bool fHasBackground = false; + ParagraphPainter::SkPaintOrID fBackground; + bool fHasForeground = false; + ParagraphPainter::SkPaintOrID fForeground; + + std::vector fTextShadows; + + sk_sp fTypeface; + bool fIsPlaceholder = false; + + std::vector fFontFeatures; + + std::optional fFontArguments; +}; + +typedef size_t TextIndex; +typedef SkRange TextRange; +const SkRange EMPTY_TEXT = EMPTY_RANGE; + +struct Block { + Block() = default; + Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {} + Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {} + + void add(TextRange tail) { + SkASSERT(fRange.end == tail.start); + fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width()); + } + + TextRange fRange = EMPTY_RANGE; + TextStyle fStyle; +}; + + +typedef size_t BlockIndex; +typedef SkRange BlockRange; +const size_t EMPTY_BLOCK = EMPTY_INDEX; +const SkRange EMPTY_BLOCKS = EMPTY_RANGE; + +struct Placeholder { + Placeholder() = default; + Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle, + BlockRange blocksBefore, TextRange textBefore) + : fRange(start, end) + , fStyle(style) + , fTextStyle(textStyle) + , fBlocksBefore(blocksBefore) + , fTextBefore(textBefore) {} + + TextRange fRange = EMPTY_RANGE; + PlaceholderStyle fStyle; + TextStyle fTextStyle; + BlockRange fBlocksBefore; + TextRange fTextBefore; +}; + +} // namespace textlayout +} // namespace skia + +#endif // TextStyle_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TypefaceFontProvider.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TypefaceFontProvider.h new file mode 100644 index 00000000000000..c51110cd4fea9b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skparagraph/include/TypefaceFontProvider.h @@ -0,0 +1,81 @@ +// Copyright 2019 Google LLC. +#ifndef TypefaceFontProvider_DEFINED +#define TypefaceFontProvider_DEFINED + +#include "include/private/base/SkTArray.h" +#include "src/core/SkTHash.h" +#include +#include +#include +#include "include/core/SkFontMgr.h" +#include "include/core/SkStream.h" +#include "include/core/SkString.h" + +namespace skia { +namespace textlayout { + +class TypefaceFontStyleSet : public SkFontStyleSet { +public: + explicit TypefaceFontStyleSet(const SkString& familyName); + + int count() override; + void getStyle(int index, SkFontStyle*, SkString* name) override; + sk_sp createTypeface(int index) override; + sk_sp matchStyle(const SkFontStyle& pattern) override; + + SkString getFamilyName() const { return fFamilyName; } + SkString getAlias() const { return fAlias; } + void appendTypeface(sk_sp typeface); + +private: + skia_private::TArray> fStyles; + SkString fFamilyName; + SkString fAlias; +}; + +class TypefaceFontProvider : public SkFontMgr { +public: + size_t registerTypeface(sk_sp typeface); + size_t registerTypeface(sk_sp typeface, const SkString& alias); + + int onCountFamilies() const override; + + void onGetFamilyName(int index, SkString* familyName) const override; + + sk_sp onMatchFamily(const char familyName[]) const override; + + sk_sp onCreateStyleSet(int) const override { return nullptr; } + sk_sp onMatchFamilyStyle(const char[], const SkFontStyle&) const override { + return nullptr; + } + sk_sp onMatchFamilyStyleCharacter(const char[], const SkFontStyle&, + const char*[], int, + SkUnichar) const override { + return nullptr; + } + + sk_sp onMakeFromData(sk_sp, int) const override { return nullptr; } + sk_sp onMakeFromStreamIndex(std::unique_ptr, int) const override { + return nullptr; + } + sk_sp onMakeFromStreamArgs(std::unique_ptr, + const SkFontArguments&) const override { + return nullptr; + } + sk_sp onMakeFromFile(const char[], int) const override { + return nullptr; + } + + sk_sp onLegacyMakeTypeface(const char[], SkFontStyle) const override { + return nullptr; + } + +private: + skia_private::THashMap> fRegisteredFamilies; + skia_private::TArray fFamilyNames; +}; + +} // namespace textlayout +} // namespace skia + +#endif // TypefaceFontProvider_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skresources/include/SkResources.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skresources/include/SkResources.h new file mode 100644 index 00000000000000..a0f44a83be1167 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/skresources/include/SkResources.h @@ -0,0 +1,268 @@ +/* + * Copyright 2019 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkResources_DEFINED +#define SkResources_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkString.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkMutex.h" +#include "src/core/SkTHash.h" + +#include + +class SkAnimCodecPlayer; +class SkImage; + +namespace skresources { + +/** + * Image asset proxy interface. + */ +class SK_API ImageAsset : public SkRefCnt { +public: + /** + * Returns true if the image asset is animated. + */ + virtual bool isMultiFrame() = 0; + + /** + * DEPRECATED: override getFrameData() instead. + * + * Returns the SkImage for a given frame. + * + * If the image asset is static, getFrame() is only called once, at animation load time. + * Otherwise, this gets invoked every time the animation time is adjusted (on every seek). + * + * Embedders should cache and serve the same SkImage whenever possible, for efficiency. + * + * @param t Frame time code, in seconds, relative to the image layer timeline origin + * (in-point). + */ + virtual sk_sp getFrame(float t); + + // Describes how the frame image is to be scaled to the animation-declared asset size. + enum class SizeFit { + // See SkMatrix::ScaleToFit + kFill = SkMatrix::kFill_ScaleToFit, + kStart = SkMatrix::kStart_ScaleToFit, + kCenter = SkMatrix::kCenter_ScaleToFit, + kEnd = SkMatrix::kEnd_ScaleToFit, + + // No scaling. + kNone, + }; + + struct FrameData { + // SkImage payload. + sk_sp image; + // Resampling parameters. + SkSamplingOptions sampling; + // Additional image transform to be applied before AE scaling rules. + SkMatrix matrix = SkMatrix::I(); + // Strategy for image size -> AE asset size scaling. + SizeFit scaling = SizeFit::kCenter; + }; + + /** + * Returns the payload for a given frame. + * + * If the image asset is static, getFrameData() is only called once, at animation load time. + * Otherwise, this gets invoked every time the animation time is adjusted (on every seek). + * + * Embedders should cache and serve the same SkImage whenever possible, for efficiency. + * + * @param t Frame time code, in seconds, relative to the image layer timeline origin + * (in-point). + */ + virtual FrameData getFrameData(float t); +}; + +class MultiFrameImageAsset final : public ImageAsset { +public: + /** + * By default, images are decoded on-the-fly, at rasterization time. + * Large images may cause jank as decoding is expensive (and can thrash internal caches). + * + * Pass |predecode| true to force-decode all images upfront, at the cost of potentially more RAM + * and slower animation build times. + */ + static sk_sp Make(sk_sp, bool predecode = false); + + bool isMultiFrame() override; + + sk_sp getFrame(float t) override; + +private: + explicit MultiFrameImageAsset(std::unique_ptr, bool predecode); + + sk_sp generateFrame(float t); + + std::unique_ptr fPlayer; + sk_sp fCachedFrame; + bool fPreDecode; + + using INHERITED = ImageAsset; +}; + +/** + * External track (e.g. audio playback) interface. + * + * Used to wrap data payload and playback controllers. + */ +class ExternalTrackAsset : public SkRefCnt { +public: + /** + * Playback control callback, emitted for each corresponding Animation::seek(). + * + * @param t Frame time code, in seconds, relative to the layer's timeline origin + * (in-point). + * + * Negative |t| values are used to signal off state (stop playback outside layer span). + */ + virtual void seek(float t) = 0; +}; + +/** + * ResourceProvider is an interface that lets rich-content modules defer loading of external + * resources (images, fonts, etc.) to embedding clients. + */ +class SK_API ResourceProvider : public SkRefCnt { +public: + /** + * Load a generic resource (currently only nested animations) specified by |path| + |name|, + * and return as an SkData. + */ + virtual sk_sp load(const char[] /* resource_path */, + const char[] /* resource_name */) const { + return nullptr; + } + + /** + * Load an image asset specified by |path| + |name|, and returns the corresponding + * ImageAsset proxy. + */ + virtual sk_sp loadImageAsset(const char[] /* resource_path */, + const char[] /* resource_name */, + const char[] /* resource_id */) const { + return nullptr; + } + + /** + * Load an external audio track specified by |path|/|name|/|id|. + */ + virtual sk_sp loadAudioAsset(const char[] /* resource_path */, + const char[] /* resource_name */, + const char[] /* resource_id */) { + return nullptr; + } + + /** + * DEPRECATED: implement loadTypeface() instead. + * + * Load an external font and return as SkData. + * + * @param name font name ("fName" Lottie property) + * @param url web font URL ("fPath" Lottie property) + * + * -- Note -- + * + * This mechanism assumes monolithic fonts (single data blob). Some web font providers may + * serve multiple font blobs, segmented for various unicode ranges, depending on user agent + * capabilities (woff, woff2). In that case, the embedder would need to advertise no user + * agent capabilities when fetching the URL, in order to receive full font data. + */ + virtual sk_sp loadFont(const char[] /* name */, + const char[] /* url */) const { + return nullptr; + } + + /** + * Load an external font and return as SkTypeface. + * + * @param name font name + * @param url web font URL + */ + virtual sk_sp loadTypeface(const char[] /* name */, + const char[] /* url */) const { + return nullptr; + } +}; + +class FileResourceProvider final : public ResourceProvider { +public: + static sk_sp Make(SkString base_dir, bool predecode = false); + + sk_sp load(const char resource_path[], const char resource_name[]) const override; + + sk_sp loadImageAsset(const char[], const char[], const char[]) const override; + +private: + FileResourceProvider(SkString, bool); + + const SkString fDir; + const bool fPredecode; + + using INHERITED = ResourceProvider; +}; + +class ResourceProviderProxyBase : public ResourceProvider { +protected: + explicit ResourceProviderProxyBase(sk_sp); + + sk_sp load(const char[], const char[]) const override; + sk_sp loadImageAsset(const char[], const char[], const char[]) const override; + sk_sp loadTypeface(const char[], const char[]) const override; + sk_sp loadFont(const char[], const char[]) const override; + sk_sp loadAudioAsset(const char[], const char[], const char[]) override; + +private: + const sk_sp fProxy; +}; + +class SK_API CachingResourceProvider final : public ResourceProviderProxyBase { +public: + static sk_sp Make(sk_sp rp) { + return rp ? sk_sp(new CachingResourceProvider(std::move(rp))) + : nullptr; + } + +private: + explicit CachingResourceProvider(sk_sp); + + sk_sp loadImageAsset(const char[], const char[], const char[]) const override; + + mutable SkMutex fMutex; + mutable skia_private::THashMap> fImageCache; + + using INHERITED = ResourceProviderProxyBase; +}; + +class DataURIResourceProviderProxy final : public ResourceProviderProxyBase { +public: + static sk_sp Make(sk_sp rp, + bool predecode = false); + +private: + DataURIResourceProviderProxy(sk_sp, bool); + + sk_sp loadImageAsset(const char[], const char[], const char[]) const override; + sk_sp loadTypeface(const char[], const char[]) const override; + + const bool fPredecode; + + using INHERITED = ResourceProviderProxyBase; +}; + +} // namespace skresources + +#endif // SkResources_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGAttribute.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGAttribute.h new file mode 100644 index 00000000000000..8e4d56caee2212 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGAttribute.h @@ -0,0 +1,113 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGAttribute_DEFINED +#define SkSVGAttribute_DEFINED + +#include "modules/svg/include/SkSVGTypes.h" +#include "src/base/SkTLazy.h" + +class SkSVGRenderContext; + +enum class SkSVGAttribute { + kClipRule, + kColor, + kColorInterpolation, + kColorInterpolationFilters, + kCx, // , , : center x position + kCy, // , , : center y position + kFill, + kFillOpacity, + kFillRule, + kFilter, + kFilterUnits, + kFontFamily, + kFontSize, + kFontStyle, + kFontWeight, + kFx, // : focal point x position + kFy, // : focal point y position + kGradientUnits, + kGradientTransform, + kHeight, + kHref, + kOpacity, + kPoints, + kPreserveAspectRatio, + kR, // , : radius + kRx, // ,: horizontal (corner) radius + kRy, // ,: vertical (corner) radius + kSpreadMethod, + kStroke, + kStrokeDashArray, + kStrokeDashOffset, + kStrokeOpacity, + kStrokeLineCap, + kStrokeLineJoin, + kStrokeMiterLimit, + kStrokeWidth, + kTransform, + kText, + kTextAnchor, + kViewBox, + kVisibility, + kWidth, + kX, + kX1, // : first endpoint x + kX2, // : second endpoint x + kY, + kY1, // : first endpoint y + kY2, // : second endpoint y + + kUnknown, +}; + +struct SkSVGPresentationAttributes { + static SkSVGPresentationAttributes MakeInitial(); + + // TODO: SkSVGProperty adds an extra ptr per attribute; refactor to reduce overhead. + + SkSVGProperty fFill; + SkSVGProperty fFillOpacity; + SkSVGProperty fFillRule; + SkSVGProperty fClipRule; + + SkSVGProperty fStroke; + SkSVGProperty fStrokeDashArray; + SkSVGProperty fStrokeDashOffset; + SkSVGProperty fStrokeLineCap; + SkSVGProperty fStrokeLineJoin; + SkSVGProperty fStrokeMiterLimit; + SkSVGProperty fStrokeOpacity; + SkSVGProperty fStrokeWidth; + + SkSVGProperty fVisibility; + + SkSVGProperty fColor; + SkSVGProperty fColorInterpolation; + SkSVGProperty fColorInterpolationFilters; + + SkSVGProperty fFontFamily; + SkSVGProperty fFontStyle; + SkSVGProperty fFontSize; + SkSVGProperty fFontWeight; + SkSVGProperty fTextAnchor; + + // uninherited + SkSVGProperty fOpacity; + SkSVGProperty fClipPath; + SkSVGProperty fDisplay; + SkSVGProperty fMask; + SkSVGProperty fFilter; + SkSVGProperty fStopColor; + SkSVGProperty fStopOpacity; + SkSVGProperty fFloodColor; + SkSVGProperty fFloodOpacity; + SkSVGProperty fLightingColor; +}; + +#endif // SkSVGAttribute_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGAttributeParser.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGAttributeParser.h new file mode 100644 index 00000000000000..9513232218668a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGAttributeParser.h @@ -0,0 +1,160 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGAttributeParser_DEFINED +#define SkSVGAttributeParser_DEFINED + +#include + +#include "include/private/base/SkNoncopyable.h" +#include "modules/svg/include/SkSVGTypes.h" +#include "src/base/SkTLazy.h" + +class SkSVGAttributeParser : public SkNoncopyable { +public: + SkSVGAttributeParser(const char[]); + + bool parseInteger(SkSVGIntegerType*); + bool parseViewBox(SkSVGViewBoxType*); + bool parsePreserveAspectRatio(SkSVGPreserveAspectRatio*); + + // TODO: Migrate all parse*() functions to this style (and delete the old version) + // so they can be used by parse(): + bool parse(SkSVGIntegerType* v) { return parseInteger(v); } + + template using ParseResult = SkTLazy; + + template static ParseResult parse(const char* value) { + ParseResult result; + T parsedValue; + if (SkSVGAttributeParser(value).parse(&parsedValue)) { + result.set(std::move(parsedValue)); + } + return result; + } + + template + static ParseResult parse(const char* expectedName, + const char* name, + const char* value) { + if (!strcmp(name, expectedName)) { + return parse(value); + } + + return ParseResult(); + } + + template + static ParseResult parseProperty(const char* expectedName, + const char* name, + const char* value) { + if (strcmp(name, expectedName) != 0) { + return ParseResult(); + } + + if (!strcmp(value, "inherit")) { + PropertyT result(SkSVGPropertyState::kInherit); + return ParseResult(&result); + } + + auto pr = parse(value); + if (pr.isValid()) { + PropertyT result(*pr); + return ParseResult(&result); + } + + return ParseResult(); + } + +private: + class RestoreCurPos { + public: + explicit RestoreCurPos(SkSVGAttributeParser* self) + : fSelf(self), fCurPos(self->fCurPos) {} + + ~RestoreCurPos() { + if (fSelf) { + fSelf->fCurPos = this->fCurPos; + } + } + + void clear() { fSelf = nullptr; } + private: + SkSVGAttributeParser* fSelf; + const char* fCurPos; + + RestoreCurPos( const RestoreCurPos&) = delete; + RestoreCurPos& operator=(const RestoreCurPos&) = delete; + }; + + // Stack-only + void* operator new(size_t) = delete; + void* operator new(size_t, void*) = delete; + + template + bool parse(T*); + + template + bool advanceWhile(F func); + + bool matchStringToken(const char* token, const char** newPos = nullptr) const; + bool matchHexToken(const char** newPos) const; + + bool parseWSToken(); + bool parseEOSToken(); + bool parseSepToken(); + bool parseCommaWspToken(); + bool parseExpectedStringToken(const char*); + bool parseScalarToken(SkScalar*); + bool parseInt32Token(int32_t*); + bool parseEscape(SkUnichar*); + bool parseIdentToken(SkString*); + bool parseLengthUnitToken(SkSVGLength::Unit*); + bool parseNamedColorToken(SkColor*); + bool parseHexColorToken(SkColor*); + bool parseColorComponentToken(int32_t*); + bool parseColorToken(SkColor*); + bool parseRGBColorToken(SkColor*); + bool parseSVGColor(SkSVGColor*, SkSVGColor::Vars&&); + bool parseSVGColorType(SkSVGColorType*); + bool parseFuncIRI(SkSVGFuncIRI*); + + // Transform helpers + bool parseMatrixToken(SkMatrix*); + bool parseTranslateToken(SkMatrix*); + bool parseScaleToken(SkMatrix*); + bool parseRotateToken(SkMatrix*); + bool parseSkewXToken(SkMatrix*); + bool parseSkewYToken(SkMatrix*); + + // Parses a sequence of 'WS* WS* ()', where the nested sequence + // is handled by the passed functor. + template + bool parseParenthesized(const char* prefix, Func, T* result); + + template + bool parseList(std::vector*); + + template + bool parseEnumMap(const TArray& arr, T* result) { + for (size_t i = 0; i < std::size(arr); ++i) { + if (this->parseExpectedStringToken(std::get<0>(arr[i]))) { + *result = std::get<1>(arr[i]); + return true; + } + } + return false; + } + + // The current position in the input string. + const char* fCurPos; + const char* fEndPos; + + using INHERITED = SkNoncopyable; +}; + +#endif // SkSVGAttributeParser_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGCircle.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGCircle.h new file mode 100644 index 00000000000000..d7e3f20540f81f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGCircle.h @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGCircle_DEFINED +#define SkSVGCircle_DEFINED + +#include "modules/svg/include/SkSVGShape.h" +#include "modules/svg/include/SkSVGTypes.h" + +struct SkPoint; + +class SkSVGCircle final : public SkSVGShape { +public: + static sk_sp Make() { return sk_sp(new SkSVGCircle()); } + + SVG_ATTR(Cx, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Cy, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(R , SkSVGLength, SkSVGLength(0)) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + +private: + SkSVGCircle(); + + // resolve and return the center and radius values + std::tuple resolve(const SkSVGLengthContext&) const; + + using INHERITED = SkSVGShape; +}; + +#endif // SkSVGCircle_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGClipPath.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGClipPath.h new file mode 100644 index 00000000000000..832c9a36ac041a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGClipPath.h @@ -0,0 +1,35 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGClipPath_DEFINED +#define SkSVGClipPath_DEFINED + +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGClipPath final : public SkSVGHiddenContainer { +public: + static sk_sp Make() { + return sk_sp(new SkSVGClipPath()); + } + + SVG_ATTR(ClipPathUnits, SkSVGObjectBoundingBoxUnits, + SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kUserSpaceOnUse)) + +private: + friend class SkSVGRenderContext; + + SkSVGClipPath(); + + bool parseAndSetAttribute(const char*, const char*) override; + + SkPath resolveClip(const SkSVGRenderContext&) const; + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGClipPath_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGContainer.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGContainer.h new file mode 100644 index 00000000000000..e5e9516c32e683 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGContainer.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGContainer_DEFINED +#define SkSVGContainer_DEFINED + +#include "include/private/base/SkTArray.h" +#include "modules/svg/include/SkSVGTransformableNode.h" + +class SkSVGContainer : public SkSVGTransformableNode { +public: + void appendChild(sk_sp) override; + +protected: + explicit SkSVGContainer(SkSVGTag); + + void onRender(const SkSVGRenderContext&) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + + bool hasChildren() const final; + + // TODO: add some sort of child iterator, and hide the container. + skia_private::STArray<1, sk_sp, true> fChildren; + +private: + using INHERITED = SkSVGTransformableNode; +}; + +#endif // SkSVGContainer_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGDOM.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGDOM.h new file mode 100644 index 00000000000000..f0bd467d28aee9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGDOM.h @@ -0,0 +1,100 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGDOM_DEFINED +#define SkSVGDOM_DEFINED + +#include "include/core/SkFontMgr.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/private/base/SkTemplates.h" +#include "modules/skresources/include/SkResources.h" +#include "modules/svg/include/SkSVGIDMapper.h" + +class SkCanvas; +class SkDOM; +class SkStream; +class SkSVGNode; +struct SkSVGPresentationContext; +class SkSVGSVG; + +class SkSVGDOM : public SkRefCnt { +public: + class Builder final { + public: + /** + * Specify a font manager for loading SVG fonts. + */ + Builder& setFontManager(sk_sp); + + /** + * Specify a resource provider for loading images etc. + */ + Builder& setResourceProvider(sk_sp); + + sk_sp make(SkStream&) const; + + private: + sk_sp fFontMgr; + sk_sp fResourceProvider; + }; + + static sk_sp MakeFromStream(SkStream& str) { + return Builder().make(str); + } + + /** + * Returns the root (outermost) SVG element. + */ + SkSVGSVG* getRoot() const { return fRoot.get(); } + + /** + * Specify a "container size" for the SVG dom. + * + * This is used to resolve the initial viewport when the root SVG width/height are specified + * in relative units. + * + * If the root dimensions are in absolute units, then the container size has no effect since + * the initial viewport is fixed. + */ + void setContainerSize(const SkSize&); + + /** + * DEPRECATED: use getRoot()->intrinsicSize() to query the root element intrinsic size. + * + * Returns the SVG dom container size. + * + * If the client specified a container size via setContainerSize(), then the same size is + * returned. + * + * When unspecified by clients, this returns the intrinsic size of the root element, as defined + * by its width/height attributes. If either width or height is specified in relative units + * (e.g. "100%"), then the corresponding intrinsic size dimension is zero. + */ + const SkSize& containerSize() const; + + // Returns the node with the given id, or nullptr if not found. + sk_sp* findNodeById(const char* id); + + void render(SkCanvas*) const; + + /** Render the node with the given id as if it were the only child of the root. */ + void renderNode(SkCanvas*, SkSVGPresentationContext&, const char* id) const; + +private: + SkSVGDOM(sk_sp, sk_sp, sk_sp, + SkSVGIDMapper&&); + + const sk_sp fRoot; + const sk_sp fFontMgr; + const sk_sp fResourceProvider; + const SkSVGIDMapper fIDMapper; + + SkSize fContainerSize; +}; + +#endif // SkSVGDOM_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGDefs.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGDefs.h new file mode 100644 index 00000000000000..46fbf43f9f3dd2 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGDefs.h @@ -0,0 +1,23 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGDefs_DEFINED +#define SkSVGDefs_DEFINED + +#include "modules/svg/include/SkSVGHiddenContainer.h" + +class SkSVGDefs : public SkSVGHiddenContainer { +public: + static sk_sp Make() { return sk_sp(new SkSVGDefs()); } + +private: + SkSVGDefs() : INHERITED(SkSVGTag::kDefs) {} + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGDefs_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGEllipse.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGEllipse.h new file mode 100644 index 00000000000000..940d1719de363d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGEllipse.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGEllipse_DEFINED +#define SkSVGEllipse_DEFINED + +#include "modules/svg/include/SkSVGShape.h" +#include "modules/svg/include/SkSVGTypes.h" + +struct SkRect; + +class SkSVGEllipse final : public SkSVGShape { +public: + static sk_sp Make() { return sk_sp(new SkSVGEllipse()); } + + SVG_ATTR(Cx, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Cy, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Rx, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Ry, SkSVGLength, SkSVGLength(0)) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + +private: + SkSVGEllipse(); + + SkRect resolve(const SkSVGLengthContext&) const; + + using INHERITED = SkSVGShape; +}; + +#endif // SkSVGEllipse_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFe.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFe.h new file mode 100644 index 00000000000000..1b0f90acae853b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFe.h @@ -0,0 +1,85 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFe_DEFINED +#define SkSVGFe_DEFINED + +#include + +#include "modules/svg/include/SkSVGHiddenContainer.h" + +class SkImageFilter; +class SkSVGFilterContext; + +class SkSVGFe : public SkSVGHiddenContainer { +public: + static bool IsFilterEffect(const sk_sp& node) { + switch (node->tag()) { + case SkSVGTag::kFeBlend: + case SkSVGTag::kFeColorMatrix: + case SkSVGTag::kFeComposite: + case SkSVGTag::kFeDiffuseLighting: + case SkSVGTag::kFeDisplacementMap: + case SkSVGTag::kFeFlood: + case SkSVGTag::kFeGaussianBlur: + case SkSVGTag::kFeImage: + case SkSVGTag::kFeMorphology: + case SkSVGTag::kFeOffset: + case SkSVGTag::kFeSpecularLighting: + case SkSVGTag::kFeTurbulence: + return true; + default: + return false; + } + } + + sk_sp makeImageFilter(const SkSVGRenderContext& ctx, + const SkSVGFilterContext& fctx) const; + + // https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveSubRegion + SkRect resolveFilterSubregion(const SkSVGRenderContext&, const SkSVGFilterContext&) const; + + /** + * Resolves the colorspace within which this filter effect should be applied. + * Spec: https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperties + * 'color-interpolation-filters' property. + */ + virtual SkSVGColorspace resolveColorspace(const SkSVGRenderContext&, + const SkSVGFilterContext&) const; + + /** Propagates any inherited presentation attributes in the given context. */ + void applyProperties(SkSVGRenderContext*) const; + + SVG_ATTR(In, SkSVGFeInputType, SkSVGFeInputType()) + SVG_ATTR(Result, SkSVGStringType, SkSVGStringType()) + SVG_OPTIONAL_ATTR(X, SkSVGLength) + SVG_OPTIONAL_ATTR(Y, SkSVGLength) + SVG_OPTIONAL_ATTR(Width, SkSVGLength) + SVG_OPTIONAL_ATTR(Height, SkSVGLength) + +protected: + explicit SkSVGFe(SkSVGTag t) : INHERITED(t) {} + + virtual sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const = 0; + + virtual std::vector getInputs() const = 0; + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + /** + * Resolves the rect specified by the x, y, width and height attributes (if specified) on this + * filter effect. These attributes are resolved according to the given length context and + * the value of 'primitiveUnits' on the parent element. + */ + SkRect resolveBoundaries(const SkSVGRenderContext&, const SkSVGFilterContext&) const; + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGFe_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeBlend.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeBlend.h new file mode 100644 index 00000000000000..36d1f0f996dc74 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeBlend.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeBlend_DEFINED +#define SkSVGFeBlend_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeBlend : public SkSVGFe { +public: + enum class Mode { + kNormal, + kMultiply, + kScreen, + kDarken, + kLighten, + }; + + static sk_sp Make() { return sk_sp(new SkSVGFeBlend()); } + + SVG_ATTR(Mode, Mode, Mode::kNormal) + SVG_ATTR(In2, SkSVGFeInputType, SkSVGFeInputType()) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { + return {this->getIn(), this->getIn2()}; + } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeBlend() : INHERITED(SkSVGTag::kFeBlend) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeBlend_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeColorMatrix.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeColorMatrix.h new file mode 100644 index 00000000000000..28d67b7c22d1cd --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeColorMatrix.h @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeColorMatrix_DEFINED +#define SkSVGFeColorMatrix_DEFINED + +#include "include/effects/SkColorMatrix.h" +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeColorMatrix final : public SkSVGFe { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeColorMatrix()); + } + + SVG_ATTR(Type, SkSVGFeColorMatrixType, SkSVGFeColorMatrixType(SkSVGFeColorMatrixType::kMatrix)) + SVG_ATTR(Values, SkSVGFeColorMatrixValues, SkSVGFeColorMatrixValues()) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {this->getIn()}; } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeColorMatrix() : INHERITED(SkSVGTag::kFeColorMatrix) {} + + SkColorMatrix makeMatrixForType() const; + + static SkColorMatrix MakeSaturate(SkSVGNumberType s); + + static SkColorMatrix MakeHueRotate(SkSVGNumberType degrees); + + static SkColorMatrix MakeLuminanceToAlpha(); + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeColorMatrix_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeComposite.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeComposite.h new file mode 100644 index 00000000000000..df64e75da2834e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeComposite.h @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeComposite_DEFINED +#define SkSVGFeComposite_DEFINED + +#include "include/core/SkBlendMode.h" +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeComposite final : public SkSVGFe { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeComposite()); + } + + SVG_ATTR(In2, SkSVGFeInputType, SkSVGFeInputType()) + SVG_ATTR(K1, SkSVGNumberType, SkSVGNumberType(0)) + SVG_ATTR(K2, SkSVGNumberType, SkSVGNumberType(0)) + SVG_ATTR(K3, SkSVGNumberType, SkSVGNumberType(0)) + SVG_ATTR(K4, SkSVGNumberType, SkSVGNumberType(0)) + SVG_ATTR(Operator, SkSVGFeCompositeOperator, SkSVGFeCompositeOperator::kOver) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { + return {this->getIn(), this->getIn2()}; + } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeComposite() : INHERITED(SkSVGTag::kFeComposite) {} + + static SkBlendMode BlendModeForOperator(SkSVGFeCompositeOperator); + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeComposite_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeDisplacementMap.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeDisplacementMap.h new file mode 100644 index 00000000000000..33c98fec70867c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeDisplacementMap.h @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeDisplacementMap_DEFINED +#define SkSVGFeDisplacementMap_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeDisplacementMap : public SkSVGFe { +public: + using ChannelSelector = SkColorChannel; + + static sk_sp Make() { + return sk_sp(new SkSVGFeDisplacementMap()); + } + + SkSVGColorspace resolveColorspace(const SkSVGRenderContext&, + const SkSVGFilterContext&) const final; + + SVG_ATTR(In2 , SkSVGFeInputType, SkSVGFeInputType()) + SVG_ATTR(XChannelSelector, ChannelSelector , ChannelSelector::kA) + SVG_ATTR(YChannelSelector, ChannelSelector , ChannelSelector::kA) + SVG_ATTR(Scale , SkSVGNumberType , SkSVGNumberType(0)) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { + return {this->getIn(), this->getIn2()}; + } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeDisplacementMap() : INHERITED(SkSVGTag::kFeDisplacementMap) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeDisplacementMap_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeFlood.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeFlood.h new file mode 100644 index 00000000000000..3625094abbdc64 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeFlood.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeFlood_DEFINED +#define SkSVGFeFlood_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeFlood : public SkSVGFe { +public: + static sk_sp Make() { return sk_sp(new SkSVGFeFlood()); } + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {}; } + +private: + SkSVGFeFlood() : INHERITED(SkSVGTag::kFeFlood) {} + + SkColor resolveFloodColor(const SkSVGRenderContext&) const; + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeFlood_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeGaussianBlur.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeGaussianBlur.h new file mode 100644 index 00000000000000..2db505940caa5c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeGaussianBlur.h @@ -0,0 +1,41 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeGaussianBlur_DEFINED +#define SkSVGFeGaussianBlur_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeGaussianBlur : public SkSVGFe { +public: + struct StdDeviation { + SkSVGNumberType fX; + SkSVGNumberType fY; + }; + + static sk_sp Make() { + return sk_sp(new SkSVGFeGaussianBlur()); + } + + SVG_ATTR(StdDeviation, StdDeviation, StdDeviation({0, 0})) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {this->getIn()}; } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeGaussianBlur() : INHERITED(SkSVGTag::kFeGaussianBlur) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeGaussianBlur_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeImage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeImage.h new file mode 100644 index 00000000000000..c51f046b327f1c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeImage.h @@ -0,0 +1,35 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeImage_DEFINED +#define SkSVGFeImage_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeImage : public SkSVGFe { +public: + static sk_sp Make() { return sk_sp(new SkSVGFeImage()); } + + SVG_ATTR(Href , SkSVGIRI , SkSVGIRI()) + SVG_ATTR(PreserveAspectRatio, SkSVGPreserveAspectRatio, SkSVGPreserveAspectRatio()) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {}; } + +private: + SkSVGFeImage() : INHERITED(SkSVGTag::kFeImage) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeImage_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeLightSource.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeLightSource.h new file mode 100644 index 00000000000000..643c150001083d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeLightSource.h @@ -0,0 +1,89 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeLightSource_DEFINED +#define SkSVGFeLightSource_DEFINED + +#include "include/core/SkPoint3.h" +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeLightSource : public SkSVGHiddenContainer { +public: + void appendChild(sk_sp) final { + SkDebugf("cannot append child nodes to an SVG light source.\n"); + } + +protected: + explicit SkSVGFeLightSource(SkSVGTag tag) : INHERITED(tag) {} + +private: + using INHERITED = SkSVGHiddenContainer; +}; + +class SkSVGFeDistantLight final : public SkSVGFeLightSource { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeDistantLight()); + } + + SkPoint3 computeDirection() const; + + SVG_ATTR(Azimuth , SkSVGNumberType, 0) + SVG_ATTR(Elevation, SkSVGNumberType, 0) + +private: + SkSVGFeDistantLight() : INHERITED(SkSVGTag::kFeDistantLight) {} + + bool parseAndSetAttribute(const char*, const char*) override; + + using INHERITED = SkSVGFeLightSource; +}; + +class SkSVGFePointLight final : public SkSVGFeLightSource { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFePointLight()); + } + + SVG_ATTR(X, SkSVGNumberType, 0) + SVG_ATTR(Y, SkSVGNumberType, 0) + SVG_ATTR(Z, SkSVGNumberType, 0) + +private: + SkSVGFePointLight() : INHERITED(SkSVGTag::kFePointLight) {} + + bool parseAndSetAttribute(const char*, const char*) override; + + using INHERITED = SkSVGFeLightSource; +}; + +class SkSVGFeSpotLight final : public SkSVGFeLightSource { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeSpotLight()); + } + + SVG_ATTR(X , SkSVGNumberType, 0) + SVG_ATTR(Y , SkSVGNumberType, 0) + SVG_ATTR(Z , SkSVGNumberType, 0) + SVG_ATTR(PointsAtX , SkSVGNumberType, 0) + SVG_ATTR(PointsAtY , SkSVGNumberType, 0) + SVG_ATTR(PointsAtZ , SkSVGNumberType, 0) + SVG_ATTR(SpecularExponent, SkSVGNumberType, 1) + + SVG_OPTIONAL_ATTR(LimitingConeAngle, SkSVGNumberType) + +private: + SkSVGFeSpotLight() : INHERITED(SkSVGTag::kFeSpotLight) {} + + bool parseAndSetAttribute(const char*, const char*) override; + + using INHERITED = SkSVGFeLightSource; +}; + +#endif // SkSVGFeLightSource_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeLighting.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeLighting.h new file mode 100644 index 00000000000000..1de1e4c4ed6a38 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeLighting.h @@ -0,0 +1,121 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeLighting_DEFINED +#define SkSVGFeLighting_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeDistantLight; +class SkSVGFePointLight; +class SkSVGFeSpotLight; + +class SkSVGFeLighting : public SkSVGFe { +public: + struct KernelUnitLength { + SkSVGNumberType fDx; + SkSVGNumberType fDy; + }; + + SVG_ATTR(SurfaceScale, SkSVGNumberType, 1) + SVG_OPTIONAL_ATTR(KernelUnitLength, KernelUnitLength) + +protected: + explicit SkSVGFeLighting(SkSVGTag t) : INHERITED(t) {} + + std::vector getInputs() const final { return {this->getIn()}; } + + bool parseAndSetAttribute(const char*, const char*) override; + + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const final; + + virtual sk_sp makeDistantLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFeDistantLight*) const = 0; + + virtual sk_sp makePointLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFePointLight*) const = 0; + + virtual sk_sp makeSpotLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFeSpotLight*) const = 0; + + SkColor resolveLightingColor(const SkSVGRenderContext&) const; + + SkPoint3 resolveXYZ(const SkSVGRenderContext&, + const SkSVGFilterContext&, + SkSVGNumberType, + SkSVGNumberType, + SkSVGNumberType) const; + +private: + using INHERITED = SkSVGFe; +}; + +class SkSVGFeSpecularLighting final : public SkSVGFeLighting { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeSpecularLighting()); + } + + SVG_ATTR(SpecularConstant, SkSVGNumberType, 1) + SVG_ATTR(SpecularExponent, SkSVGNumberType, 1) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + sk_sp makeDistantLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFeDistantLight*) const final; + + sk_sp makePointLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFePointLight*) const final; + + sk_sp makeSpotLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFeSpotLight*) const final; + +private: + SkSVGFeSpecularLighting() : INHERITED(SkSVGTag::kFeSpecularLighting) {} + + using INHERITED = SkSVGFeLighting; +}; + +class SkSVGFeDiffuseLighting final : public SkSVGFeLighting { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeDiffuseLighting()); + } + + SVG_ATTR(DiffuseConstant, SkSVGNumberType, 1) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + sk_sp makeDistantLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFeDistantLight*) const final; + + sk_sp makePointLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFePointLight*) const final; + + sk_sp makeSpotLight(const SkSVGRenderContext&, + const SkSVGFilterContext&, + const SkSVGFeSpotLight*) const final; + +private: + SkSVGFeDiffuseLighting() : INHERITED(SkSVGTag::kFeDiffuseLighting) {} + + using INHERITED = SkSVGFeLighting; +}; + +#endif // SkSVGFeLighting_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeMorphology.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeMorphology.h new file mode 100644 index 00000000000000..172460f72ec01e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeMorphology.h @@ -0,0 +1,47 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeMorphology_DEFINED +#define SkSVGFeMorphology_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeMorphology : public SkSVGFe { +public: + struct Radius { + SkSVGNumberType fX; + SkSVGNumberType fY; + }; + + enum class Operator { + kErode, + kDilate, + }; + + static sk_sp Make() { + return sk_sp(new SkSVGFeMorphology()); + } + + SVG_ATTR(Operator, Operator, Operator::kErode) + SVG_ATTR(Radius , Radius , Radius({0, 0})) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {this->getIn()}; } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeMorphology() : INHERITED(SkSVGTag::kFeMorphology) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeMorphology_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeOffset.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeOffset.h new file mode 100644 index 00000000000000..318194f2800931 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeOffset.h @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeOffset_DEFINED +#define SkSVGFeOffset_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeOffset : public SkSVGFe { +public: + static sk_sp Make() { return sk_sp(new SkSVGFeOffset()); } + + SVG_ATTR(Dx, SkSVGNumberType, SkSVGNumberType(0)) + SVG_ATTR(Dy, SkSVGNumberType, SkSVGNumberType(0)) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {this->getIn()}; } + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGFeOffset() : INHERITED(SkSVGTag::kFeOffset) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeOffset_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeTurbulence.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeTurbulence.h new file mode 100644 index 00000000000000..e55de5ebdae263 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFeTurbulence.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFeTurbulence_DEFINED +#define SkSVGFeTurbulence_DEFINED + +#include "modules/svg/include/SkSVGFe.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFeTurbulence : public SkSVGFe { +public: + static sk_sp Make() { + return sk_sp(new SkSVGFeTurbulence()); + } + + SVG_ATTR(BaseFrequency, SkSVGFeTurbulenceBaseFrequency, SkSVGFeTurbulenceBaseFrequency({})) + SVG_ATTR(NumOctaves, SkSVGIntegerType, SkSVGIntegerType(1)) + SVG_ATTR(Seed, SkSVGNumberType, SkSVGNumberType(0)) + SVG_ATTR(TurbulenceType, + SkSVGFeTurbulenceType, + SkSVGFeTurbulenceType(SkSVGFeTurbulenceType::Type::kTurbulence)) + +protected: + sk_sp onMakeImageFilter(const SkSVGRenderContext&, + const SkSVGFilterContext&) const override; + + std::vector getInputs() const override { return {}; } + + bool parseAndSetAttribute(const char*, const char*) override; +private: + SkSVGFeTurbulence() : INHERITED(SkSVGTag::kFeTurbulence) {} + + using INHERITED = SkSVGFe; +}; + +#endif // SkSVGFeTurbulence_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFilter.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFilter.h new file mode 100644 index 00000000000000..288f8d4b6a31e5 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFilter.h @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFilter_DEFINED +#define SkSVGFilter_DEFINED + +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGFilter final : public SkSVGHiddenContainer { +public: + static sk_sp Make() { return sk_sp(new SkSVGFilter()); } + + sk_sp buildFilterDAG(const SkSVGRenderContext&) const; + + SVG_ATTR(X, SkSVGLength, SkSVGLength(-10, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Y, SkSVGLength, SkSVGLength(-10, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Width, SkSVGLength, SkSVGLength(120, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Height, SkSVGLength, SkSVGLength(120, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(FilterUnits, + SkSVGObjectBoundingBoxUnits, + SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kObjectBoundingBox)) + SVG_ATTR(PrimitiveUnits, + SkSVGObjectBoundingBoxUnits, + SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kUserSpaceOnUse)) + +private: + SkSVGFilter() : INHERITED(SkSVGTag::kFilter) {} + + bool parseAndSetAttribute(const char*, const char*) override; + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGFilter_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFilterContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFilterContext.h new file mode 100644 index 00000000000000..dcd938d1e18385 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGFilterContext.h @@ -0,0 +1,69 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGFilterContext_DEFINED +#define SkSVGFilterContext_DEFINED + +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkString.h" +#include "modules/svg/include/SkSVGTypes.h" +#include "src/core/SkTHash.h" + +class SkImageFilter; +class SkSVGFeInputType; +class SkSVGRenderContext; + +class SkSVGFilterContext { +public: + SkSVGFilterContext(const SkRect& filterEffectsRegion, + const SkSVGObjectBoundingBoxUnits& primitiveUnits) + : fFilterEffectsRegion(filterEffectsRegion) + , fPrimitiveUnits(primitiveUnits) + , fPreviousResult({nullptr, filterEffectsRegion, SkSVGColorspace::kSRGB}) {} + + const SkRect& filterEffectsRegion() const { return fFilterEffectsRegion; } + + const SkRect& filterPrimitiveSubregion(const SkSVGFeInputType&) const; + + const SkSVGObjectBoundingBoxUnits& primitiveUnits() const { return fPrimitiveUnits; } + + void registerResult(const SkSVGStringType&, const sk_sp&, const SkRect&, SkSVGColorspace); + + void setPreviousResult(const sk_sp&, const SkRect&, SkSVGColorspace); + + bool previousResultIsSourceGraphic() const; + + SkSVGColorspace resolveInputColorspace(const SkSVGRenderContext&, + const SkSVGFeInputType&) const; + + sk_sp resolveInput(const SkSVGRenderContext&, const SkSVGFeInputType&) const; + + sk_sp resolveInput(const SkSVGRenderContext&, const SkSVGFeInputType&, SkSVGColorspace) const; + +private: + struct Result { + sk_sp fImageFilter; + SkRect fFilterSubregion; + SkSVGColorspace fColorspace; + }; + + const Result* findResultById(const SkSVGStringType&) const; + + std::tuple, SkSVGColorspace> getInput(const SkSVGRenderContext&, + const SkSVGFeInputType&) const; + + SkRect fFilterEffectsRegion; + + SkSVGObjectBoundingBoxUnits fPrimitiveUnits; + + skia_private::THashMap fResults; + + Result fPreviousResult; +}; + +#endif // SkSVGFilterContext_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGG.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGG.h new file mode 100644 index 00000000000000..4d7368f8d091e9 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGG.h @@ -0,0 +1,23 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGG_DEFINED +#define SkSVGG_DEFINED + +#include "modules/svg/include/SkSVGContainer.h" + +class SkSVGG : public SkSVGContainer { +public: + static sk_sp Make() { return sk_sp(new SkSVGG()); } + +private: + SkSVGG() : INHERITED(SkSVGTag::kG) { } + + using INHERITED = SkSVGContainer; +}; + +#endif // SkSVGG_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGGradient.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGGradient.h new file mode 100644 index 00000000000000..16053e83c85fd8 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGGradient.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGGradient_DEFINED +#define SkSVGGradient_DEFINED + +#include "include/core/SkShader.h" +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkMatrix; +class SkSVGRenderContext; +class SkSVGStop; + +class SkSVGGradient : public SkSVGHiddenContainer { +public: + SVG_ATTR(Href, SkSVGIRI, SkSVGIRI()) + SVG_ATTR(GradientTransform, SkSVGTransformType, SkSVGTransformType(SkMatrix::I())) + SVG_ATTR(SpreadMethod, SkSVGSpreadMethod, SkSVGSpreadMethod(SkSVGSpreadMethod::Type::kPad)) + SVG_ATTR(GradientUnits, + SkSVGObjectBoundingBoxUnits, + SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kObjectBoundingBox)) + +protected: + explicit SkSVGGradient(SkSVGTag t) : INHERITED(t) {} + + bool parseAndSetAttribute(const char*, const char*) override; + + bool onAsPaint(const SkSVGRenderContext&, SkPaint*) const final; + + virtual sk_sp onMakeShader(const SkSVGRenderContext&, + const SkColor4f*, const SkScalar*, int count, + SkTileMode, const SkMatrix& localMatrix) const = 0; + +private: + using StopPositionArray = skia_private::STArray<2, SkScalar , true>; + using StopColorArray = skia_private::STArray<2, SkColor4f, true>; + void collectColorStops(const SkSVGRenderContext&, StopPositionArray*, StopColorArray*) const; + SkColor4f resolveStopColor(const SkSVGRenderContext&, const SkSVGStop&) const; + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGGradient_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGHiddenContainer.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGHiddenContainer.h new file mode 100644 index 00000000000000..319118e6927566 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGHiddenContainer.h @@ -0,0 +1,23 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGHiddenContainer_DEFINED +#define SkSVGHiddenContainer_DEFINED + +#include "modules/svg/include/SkSVGContainer.h" + +class SkSVGHiddenContainer : public SkSVGContainer { +protected: + explicit SkSVGHiddenContainer(SkSVGTag t) : INHERITED(t) {} + + void onRender(const SkSVGRenderContext&) const final {} + +private: + using INHERITED = SkSVGContainer; +}; + +#endif // SkSVGHiddenContainer_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGIDMapper.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGIDMapper.h new file mode 100644 index 00000000000000..e78f28de37368b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGIDMapper.h @@ -0,0 +1,19 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGIDMapper_DEFINED +#define SkSVGIDMapper_DEFINED + +#include "include/core/SkRefCnt.h" +#include "src/core/SkTHash.h" + +class SkString; +class SkSVGNode; + +using SkSVGIDMapper = skia_private::THashMap>; + +#endif // SkSVGIDMapper_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGImage.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGImage.h new file mode 100644 index 00000000000000..bef8c1f5e43a9d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGImage.h @@ -0,0 +1,58 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGImage_DEFINED +#define SkSVGImage_DEFINED + +#include "modules/svg/include/SkSVGTransformableNode.h" +#include "modules/svg/include/SkSVGTypes.h" + +namespace skresources { +class ResourceProvider; +} + +class SkSVGImage final : public SkSVGTransformableNode { +public: + static sk_sp Make() { + return sk_sp(new SkSVGImage()); + } + + void appendChild(sk_sp) override { + SkDebugf("cannot append child nodes to this element.\n"); + } + + bool onPrepareToRender(SkSVGRenderContext*) const override; + void onRender(const SkSVGRenderContext&) const override; + SkPath onAsPath(const SkSVGRenderContext&) const override; + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + + struct ImageInfo { + sk_sp fImage; + SkRect fDst; + }; + static ImageInfo LoadImage(const sk_sp&, + const SkSVGIRI&, + const SkRect&, + SkSVGPreserveAspectRatio); + + SVG_ATTR(X , SkSVGLength , SkSVGLength(0)) + SVG_ATTR(Y , SkSVGLength , SkSVGLength(0)) + SVG_ATTR(Width , SkSVGLength , SkSVGLength(0)) + SVG_ATTR(Height , SkSVGLength , SkSVGLength(0)) + SVG_ATTR(Href , SkSVGIRI , SkSVGIRI()) + SVG_ATTR(PreserveAspectRatio, SkSVGPreserveAspectRatio, SkSVGPreserveAspectRatio()) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGImage() : INHERITED(SkSVGTag::kImage) {} + + using INHERITED = SkSVGTransformableNode; +}; + +#endif // SkSVGImage_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGLine.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGLine.h new file mode 100644 index 00000000000000..35c534f5efc12b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGLine.h @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGLine_DEFINED +#define SkSVGLine_DEFINED + +#include "modules/svg/include/SkSVGShape.h" +#include "modules/svg/include/SkSVGTypes.h" + +struct SkPoint; + +class SkSVGLine final : public SkSVGShape { +public: + static sk_sp Make() { return sk_sp(new SkSVGLine()); } + + SVG_ATTR(X1, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Y1, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(X2, SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Y2, SkSVGLength, SkSVGLength(0)) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + +private: + SkSVGLine(); + + // resolve and return the two endpoints + std::tuple resolve(const SkSVGLengthContext&) const; + + using INHERITED = SkSVGShape; +}; + +#endif // SkSVGLine_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGLinearGradient.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGLinearGradient.h new file mode 100644 index 00000000000000..57ef10a6dbe1d1 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGLinearGradient.h @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGLinearGradient_DEFINED +#define SkSVGLinearGradient_DEFINED + +#include "modules/svg/include/SkSVGGradient.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGLinearGradient final : public SkSVGGradient { +public: + static sk_sp Make() { + return sk_sp(new SkSVGLinearGradient()); + } + + SVG_ATTR(X1, SkSVGLength, SkSVGLength(0 , SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Y1, SkSVGLength, SkSVGLength(0 , SkSVGLength::Unit::kPercentage)) + SVG_ATTR(X2, SkSVGLength, SkSVGLength(100, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Y2, SkSVGLength, SkSVGLength(0 , SkSVGLength::Unit::kPercentage)) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + sk_sp onMakeShader(const SkSVGRenderContext&, + const SkColor4f*, const SkScalar*, int count, + SkTileMode, const SkMatrix&) const override; +private: + SkSVGLinearGradient(); + + using INHERITED = SkSVGGradient; +}; + +#endif // SkSVGLinearGradient_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGMask.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGMask.h new file mode 100644 index 00000000000000..f5460c89715722 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGMask.h @@ -0,0 +1,43 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGMask_DEFINED +#define SkSVGMask_DEFINED + +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGMask final : public SkSVGHiddenContainer { +public: + static sk_sp Make() { + return sk_sp(new SkSVGMask()); + } + + SVG_ATTR(X , SkSVGLength, SkSVGLength(-10, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Y , SkSVGLength, SkSVGLength(-10, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Width , SkSVGLength, SkSVGLength(120, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Height, SkSVGLength, SkSVGLength(120, SkSVGLength::Unit::kPercentage)) + + SVG_ATTR(MaskUnits, SkSVGObjectBoundingBoxUnits, + SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kObjectBoundingBox)) + SVG_ATTR(MaskContentUnits, SkSVGObjectBoundingBoxUnits, + SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kUserSpaceOnUse)) + +private: + friend class SkSVGRenderContext; + + SkSVGMask() : INHERITED(SkSVGTag::kMask) {} + + bool parseAndSetAttribute(const char*, const char*) override; + + SkRect bounds(const SkSVGRenderContext&) const; + void renderMask(const SkSVGRenderContext&) const; + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGMask_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGNode.h new file mode 100644 index 00000000000000..9ca1b33b387451 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGNode.h @@ -0,0 +1,223 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGNode_DEFINED +#define SkSVGNode_DEFINED + +#include "include/core/SkRefCnt.h" +#include "modules/svg/include/SkSVGAttribute.h" +#include "modules/svg/include/SkSVGAttributeParser.h" + +class SkCanvas; +class SkMatrix; +class SkPaint; +class SkPath; +class SkSVGLengthContext; +class SkSVGRenderContext; +class SkSVGValue; + +enum class SkSVGTag { + kCircle, + kClipPath, + kDefs, + kEllipse, + kFeBlend, + kFeColorMatrix, + kFeComposite, + kFeDiffuseLighting, + kFeDisplacementMap, + kFeDistantLight, + kFeFlood, + kFeGaussianBlur, + kFeImage, + kFeMorphology, + kFeOffset, + kFePointLight, + kFeSpecularLighting, + kFeSpotLight, + kFeTurbulence, + kFilter, + kG, + kImage, + kLine, + kLinearGradient, + kMask, + kPath, + kPattern, + kPolygon, + kPolyline, + kRadialGradient, + kRect, + kStop, + kSvg, + kText, + kTextLiteral, + kTextPath, + kTSpan, + kUse +}; + +#define SVG_PRES_ATTR(attr_name, attr_type, attr_inherited) \ +private: \ + bool set##attr_name(SkSVGAttributeParser::ParseResult< \ + SkSVGProperty>&& pr) {\ + if (pr.isValid()) { this->set##attr_name(std::move(*pr)); } \ + return pr.isValid(); \ + } \ + \ +public: \ + const SkSVGProperty& get##attr_name() const { \ + return fPresentationAttributes.f##attr_name; \ + } \ + void set##attr_name(const SkSVGProperty& v) { \ + auto* dest = &fPresentationAttributes.f##attr_name; \ + if (!dest->isInheritable() || v.isValue()) { \ + /* TODO: If dest is not inheritable, handle v == "inherit" */ \ + *dest = v; \ + } else { \ + dest->set(SkSVGPropertyState::kInherit); \ + } \ + } \ + void set##attr_name(SkSVGProperty&& v) { \ + auto* dest = &fPresentationAttributes.f##attr_name; \ + if (!dest->isInheritable() || v.isValue()) { \ + /* TODO: If dest is not inheritable, handle v == "inherit" */ \ + *dest = std::move(v); \ + } else { \ + dest->set(SkSVGPropertyState::kInherit); \ + } \ + } + +class SkSVGNode : public SkRefCnt { +public: + ~SkSVGNode() override; + + SkSVGTag tag() const { return fTag; } + + virtual void appendChild(sk_sp) = 0; + + void render(const SkSVGRenderContext&) const; + bool asPaint(const SkSVGRenderContext&, SkPaint*) const; + SkPath asPath(const SkSVGRenderContext&) const; + SkRect objectBoundingBox(const SkSVGRenderContext&) const; + + void setAttribute(SkSVGAttribute, const SkSVGValue&); + bool setAttribute(const char* attributeName, const char* attributeValue); + + // TODO: consolidate with existing setAttribute + virtual bool parseAndSetAttribute(const char* name, const char* value); + + // inherited + SVG_PRES_ATTR(ClipRule , SkSVGFillRule , true) + SVG_PRES_ATTR(Color , SkSVGColorType , true) + SVG_PRES_ATTR(ColorInterpolation , SkSVGColorspace, true) + SVG_PRES_ATTR(ColorInterpolationFilters, SkSVGColorspace, true) + SVG_PRES_ATTR(FillRule , SkSVGFillRule , true) + SVG_PRES_ATTR(Fill , SkSVGPaint , true) + SVG_PRES_ATTR(FillOpacity , SkSVGNumberType, true) + SVG_PRES_ATTR(FontFamily , SkSVGFontFamily, true) + SVG_PRES_ATTR(FontSize , SkSVGFontSize , true) + SVG_PRES_ATTR(FontStyle , SkSVGFontStyle , true) + SVG_PRES_ATTR(FontWeight , SkSVGFontWeight, true) + SVG_PRES_ATTR(Stroke , SkSVGPaint , true) + SVG_PRES_ATTR(StrokeDashArray , SkSVGDashArray , true) + SVG_PRES_ATTR(StrokeDashOffset , SkSVGLength , true) + SVG_PRES_ATTR(StrokeLineCap , SkSVGLineCap , true) + SVG_PRES_ATTR(StrokeLineJoin , SkSVGLineJoin , true) + SVG_PRES_ATTR(StrokeMiterLimit , SkSVGNumberType, true) + SVG_PRES_ATTR(StrokeOpacity , SkSVGNumberType, true) + SVG_PRES_ATTR(StrokeWidth , SkSVGLength , true) + SVG_PRES_ATTR(TextAnchor , SkSVGTextAnchor, true) + SVG_PRES_ATTR(Visibility , SkSVGVisibility, true) + + // not inherited + SVG_PRES_ATTR(ClipPath , SkSVGFuncIRI , false) + SVG_PRES_ATTR(Display , SkSVGDisplay , false) + SVG_PRES_ATTR(Mask , SkSVGFuncIRI , false) + SVG_PRES_ATTR(Filter , SkSVGFuncIRI , false) + SVG_PRES_ATTR(Opacity , SkSVGNumberType, false) + SVG_PRES_ATTR(StopColor , SkSVGColor , false) + SVG_PRES_ATTR(StopOpacity , SkSVGNumberType, false) + SVG_PRES_ATTR(FloodColor , SkSVGColor , false) + SVG_PRES_ATTR(FloodOpacity , SkSVGNumberType, false) + SVG_PRES_ATTR(LightingColor , SkSVGColor , false) + +protected: + SkSVGNode(SkSVGTag); + + static SkMatrix ComputeViewboxMatrix(const SkRect&, const SkRect&, SkSVGPreserveAspectRatio); + + // Called before onRender(), to apply local attributes to the context. Unlike onRender(), + // onPrepareToRender() bubbles up the inheritance chain: overriders should always call + // INHERITED::onPrepareToRender(), unless they intend to short-circuit rendering + // (return false). + // Implementations are expected to return true if rendering is to continue, or false if + // the node/subtree rendering is disabled. + virtual bool onPrepareToRender(SkSVGRenderContext*) const; + + virtual void onRender(const SkSVGRenderContext&) const = 0; + + virtual bool onAsPaint(const SkSVGRenderContext&, SkPaint*) const { return false; } + + virtual SkPath onAsPath(const SkSVGRenderContext&) const = 0; + + virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&) {} + + virtual bool hasChildren() const { return false; } + + virtual SkRect onObjectBoundingBox(const SkSVGRenderContext&) const { + return SkRect::MakeEmpty(); + } + +private: + SkSVGTag fTag; + + // FIXME: this should be sparse + SkSVGPresentationAttributes fPresentationAttributes; + + using INHERITED = SkRefCnt; +}; + +#undef SVG_PRES_ATTR // presentation attributes are only defined for the base class + +#define _SVG_ATTR_SETTERS(attr_name, attr_type, attr_default, set_cp, set_mv) \ + private: \ + bool set##attr_name( \ + const SkSVGAttributeParser::ParseResult& pr) { \ + if (pr.isValid()) { this->set##attr_name(*pr); } \ + return pr.isValid(); \ + } \ + bool set##attr_name( \ + SkSVGAttributeParser::ParseResult&& pr) { \ + if (pr.isValid()) { this->set##attr_name(std::move(*pr)); } \ + return pr.isValid(); \ + } \ + public: \ + void set##attr_name(const attr_type& a) { set_cp(a); } \ + void set##attr_name(attr_type&& a) { set_mv(std::move(a)); } + +#define SVG_ATTR(attr_name, attr_type, attr_default) \ + private: \ + attr_type f##attr_name = attr_default; \ + public: \ + const attr_type& get##attr_name() const { return f##attr_name; } \ + _SVG_ATTR_SETTERS( \ + attr_name, attr_type, attr_default, \ + [this](const attr_type& a) { this->f##attr_name = a; }, \ + [this](attr_type&& a) { this->f##attr_name = std::move(a); }) + +#define SVG_OPTIONAL_ATTR(attr_name, attr_type) \ + private: \ + SkTLazy f##attr_name; \ + public: \ + const SkTLazy& get##attr_name() const { return f##attr_name; } \ + _SVG_ATTR_SETTERS( \ + attr_name, attr_type, attr_default, \ + [this](const attr_type& a) { this->f##attr_name.set(a); }, \ + [this](attr_type&& a) { this->f##attr_name.set(std::move(a)); }) + +#endif // SkSVGNode_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGOpenTypeSVGDecoder.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGOpenTypeSVGDecoder.h new file mode 100644 index 00000000000000..fb4f830434fa3c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGOpenTypeSVGDecoder.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGOpenTypeSVGDecoder_DEFINED +#define SkSVGOpenTypeSVGDecoder_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkOpenTypeSVGDecoder.h" +#include "include/core/SkSpan.h" +#include "include/core/SkTypes.h" + +class SkCanvas; +class SkSVGDOM; + +class SkSVGOpenTypeSVGDecoder : public SkOpenTypeSVGDecoder { +public: + static std::unique_ptr Make(const uint8_t* svg, size_t svgLength); + size_t approximateSize() override; + bool render(SkCanvas&, int upem, SkGlyphID glyphId, + SkColor foregroundColor, SkSpan palette) override; + ~SkSVGOpenTypeSVGDecoder() override; +private: + SkSVGOpenTypeSVGDecoder(sk_sp skSvg, size_t approximateSize); + sk_sp fSkSvg; + size_t fApproximateSize; +}; + +#endif // SkSVGOpenTypeSVGDecoder_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPath.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPath.h new file mode 100644 index 00000000000000..24f97d4de4504a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPath.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGPath_DEFINED +#define SkSVGPath_DEFINED + +#include "include/core/SkPath.h" +#include "modules/svg/include/SkSVGShape.h" + +class SkSVGPath final : public SkSVGShape { +public: + static sk_sp Make() { return sk_sp(new SkSVGPath()); } + + SVG_ATTR(Path, SkPath, SkPath()) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + +private: + SkSVGPath(); + + using INHERITED = SkSVGShape; +}; + +#endif // SkSVGPath_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPattern.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPattern.h new file mode 100644 index 00000000000000..442ee1e912cb90 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPattern.h @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGPattern_DEFINED +#define SkSVGPattern_DEFINED + +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGRenderContext; + +class SkSVGPattern final : public SkSVGHiddenContainer { +public: + static sk_sp Make() { + return sk_sp(new SkSVGPattern()); + } + + SVG_ATTR(Href, SkSVGIRI, SkSVGIRI()) + SVG_OPTIONAL_ATTR(X , SkSVGLength) + SVG_OPTIONAL_ATTR(Y , SkSVGLength) + SVG_OPTIONAL_ATTR(Width , SkSVGLength) + SVG_OPTIONAL_ATTR(Height , SkSVGLength) + SVG_OPTIONAL_ATTR(PatternTransform, SkSVGTransformType) + +protected: + SkSVGPattern(); + + bool parseAndSetAttribute(const char*, const char*) override; + + bool onAsPaint(const SkSVGRenderContext&, SkPaint*) const override; + +private: + struct PatternAttributes { + SkTLazy fX, + fY, + fWidth, + fHeight; + SkTLazy fPatternTransform; + }; + + const SkSVGPattern* resolveHref(const SkSVGRenderContext&, PatternAttributes*) const; + const SkSVGPattern* hrefTarget(const SkSVGRenderContext&) const; + + // TODO: + // - patternUnits + // - patternContentUnits + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGPattern_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPoly.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPoly.h new file mode 100644 index 00000000000000..c6a49f199f289a --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGPoly.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGPoly_DEFINED +#define SkSVGPoly_DEFINED + +#include "include/core/SkPath.h" +#include "modules/svg/include/SkSVGShape.h" + +// Handles and elements. +class SkSVGPoly final : public SkSVGShape { +public: + static sk_sp MakePolygon() { + return sk_sp(new SkSVGPoly(SkSVGTag::kPolygon)); + } + + static sk_sp MakePolyline() { + return sk_sp(new SkSVGPoly(SkSVGTag::kPolyline)); + } + + SVG_ATTR(Points, SkSVGPointsType, SkSVGPointsType()) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + +private: + SkSVGPoly(SkSVGTag); + + mutable SkPath fPath; // mutated in onDraw(), to apply inherited fill types. + + using INHERITED = SkSVGShape; +}; + +#endif // SkSVGPoly_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRadialGradient.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRadialGradient.h new file mode 100644 index 00000000000000..1ab52e42214d9f --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRadialGradient.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGRadialGradient_DEFINED +#define SkSVGRadialGradient_DEFINED + +#include "modules/svg/include/SkSVGGradient.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGRadialGradient final : public SkSVGGradient { +public: + static sk_sp Make() { + return sk_sp(new SkSVGRadialGradient()); + } + + SVG_ATTR(Cx, SkSVGLength, SkSVGLength(50, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Cy, SkSVGLength, SkSVGLength(50, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(R, SkSVGLength, SkSVGLength(50, SkSVGLength::Unit::kPercentage)) + SVG_OPTIONAL_ATTR(Fx, SkSVGLength) + SVG_OPTIONAL_ATTR(Fy, SkSVGLength) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + sk_sp onMakeShader(const SkSVGRenderContext&, + const SkColor4f*, const SkScalar*, int count, + SkTileMode, const SkMatrix&) const override; +private: + SkSVGRadialGradient(); + + using INHERITED = SkSVGGradient; +}; + +#endif // SkSVGRadialGradient_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRect.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRect.h new file mode 100644 index 00000000000000..87f1e44bc1078d --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRect.h @@ -0,0 +1,46 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGRect_DEFINED +#define SkSVGRect_DEFINED + +#include "modules/svg/include/SkSVGShape.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkRRect; + +class SkSVGRect final : public SkSVGShape { +public: + static sk_sp Make() { return sk_sp(new SkSVGRect()); } + + SVG_ATTR(X , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Y , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Width , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Height, SkSVGLength, SkSVGLength(0)) + + SVG_OPTIONAL_ATTR(Rx, SkSVGLength) + SVG_OPTIONAL_ATTR(Ry, SkSVGLength) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + + void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const override; + + SkPath onAsPath(const SkSVGRenderContext&) const override; + + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + +private: + SkSVGRect(); + + SkRRect resolve(const SkSVGLengthContext&) const; + + using INHERITED = SkSVGShape; +}; + +#endif // SkSVGRect_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRenderContext.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRenderContext.h new file mode 100644 index 00000000000000..32ee8a08e415f0 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGRenderContext.h @@ -0,0 +1,188 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGRenderContext_DEFINED +#define SkSVGRenderContext_DEFINED + +#include "include/core/SkFontMgr.h" +#include "include/core/SkM44.h" +#include "include/core/SkPaint.h" +#include "include/core/SkPath.h" +#include "include/core/SkRect.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "modules/skresources/include/SkResources.h" +#include "modules/svg/include/SkSVGAttribute.h" +#include "modules/svg/include/SkSVGIDMapper.h" +#include "src/base/SkTLazy.h" +#include "src/core/SkTHash.h" + +class SkCanvas; +class SkSVGLength; + +class SkSVGLengthContext { +public: + SkSVGLengthContext(const SkSize& viewport, SkScalar dpi = 90) + : fViewport(viewport), fDPI(dpi) {} + + enum class LengthType { + kHorizontal, + kVertical, + kOther, + }; + + const SkSize& viewPort() const { return fViewport; } + void setViewPort(const SkSize& viewport) { fViewport = viewport; } + + SkScalar resolve(const SkSVGLength&, LengthType) const; + SkRect resolveRect(const SkSVGLength& x, const SkSVGLength& y, + const SkSVGLength& w, const SkSVGLength& h) const; + +private: + SkSize fViewport; + SkScalar fDPI; +}; + +struct SkSVGPresentationContext { + SkSVGPresentationContext(); + SkSVGPresentationContext(const SkSVGPresentationContext&) = default; + SkSVGPresentationContext& operator=(const SkSVGPresentationContext&) = default; + + const skia_private::THashMap* fNamedColors = nullptr; + + // Inherited presentation attributes, computed for the current node. + SkSVGPresentationAttributes fInherited; +}; + +class SkSVGRenderContext { +public: + // Captures data required for object bounding box resolution. + struct OBBScope { + const SkSVGNode* fNode; + const SkSVGRenderContext* fCtx; + }; + + SkSVGRenderContext(SkCanvas*, const sk_sp&, + const sk_sp&, const SkSVGIDMapper&, + const SkSVGLengthContext&, const SkSVGPresentationContext&, + const OBBScope&); + SkSVGRenderContext(const SkSVGRenderContext&); + SkSVGRenderContext(const SkSVGRenderContext&, SkCanvas*); + // Establish a new OBB scope. Normally used when entering a node's render scope. + SkSVGRenderContext(const SkSVGRenderContext&, const SkSVGNode*); + ~SkSVGRenderContext(); + + const SkSVGLengthContext& lengthContext() const { return *fLengthContext; } + SkSVGLengthContext* writableLengthContext() { return fLengthContext.writable(); } + + const SkSVGPresentationContext& presentationContext() const { return *fPresentationContext; } + + SkCanvas* canvas() const { return fCanvas; } + void saveOnce(); + + enum ApplyFlags { + kLeaf = 1 << 0, // the target node doesn't have descendants + }; + void applyPresentationAttributes(const SkSVGPresentationAttributes&, uint32_t flags); + + // Scoped wrapper that temporarily clears the original node reference. + class BorrowedNode { + public: + explicit BorrowedNode(sk_sp* node) + : fOwner(node) { + if (fOwner) { + fBorrowed = std::move(*fOwner); + *fOwner = nullptr; + } + } + + ~BorrowedNode() { + if (fOwner) { + *fOwner = std::move(fBorrowed); + } + } + + const SkSVGNode* get() const { return fBorrowed.get(); } + const SkSVGNode* operator->() const { return fBorrowed.get(); } + const SkSVGNode& operator*() const { return *fBorrowed; } + + explicit operator bool() const { return !!fBorrowed; } + + private: + // noncopyable + BorrowedNode(const BorrowedNode&) = delete; + BorrowedNode& operator=(BorrowedNode&) = delete; + + sk_sp* fOwner; + sk_sp fBorrowed; + }; + + // Note: the id->node association is cleared for the lifetime of the returned value + // (effectively breaks reference cycles, assuming appropriate return value scoping). + BorrowedNode findNodeById(const SkSVGIRI&) const; + + SkTLazy fillPaint() const; + SkTLazy strokePaint() const; + + SkSVGColorType resolveSvgColor(const SkSVGColor&) const; + + // The local computed clip path (not inherited). + const SkPath* clipPath() const { return fClipPath.getMaybeNull(); } + + const sk_sp& resourceProvider() const { + return fResourceProvider; + } + + sk_sp fontMgr() const { + return fFontMgr ? fFontMgr : SkFontMgr::RefDefault(); + } + + // Returns the translate/scale transformation required to map into the current OBB scope, + // with the specified units. + struct OBBTransform { + SkV2 offset, scale; + }; + OBBTransform transformForCurrentOBB(SkSVGObjectBoundingBoxUnits) const; + + SkRect resolveOBBRect(const SkSVGLength& x, const SkSVGLength& y, + const SkSVGLength& w, const SkSVGLength& h, + SkSVGObjectBoundingBoxUnits) const; + +private: + // Stack-only + void* operator new(size_t) = delete; + void* operator new(size_t, void*) = delete; + SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete; + + void applyOpacity(SkScalar opacity, uint32_t flags, bool hasFilter); + void applyFilter(const SkSVGFuncIRI&); + void applyClip(const SkSVGFuncIRI&); + void applyMask(const SkSVGFuncIRI&); + + SkTLazy commonPaint(const SkSVGPaint&, float opacity) const; + + const sk_sp& fFontMgr; + const sk_sp& fResourceProvider; + const SkSVGIDMapper& fIDMapper; + SkTCopyOnFirstWrite fLengthContext; + SkTCopyOnFirstWrite fPresentationContext; + SkCanvas* fCanvas; + // The save count on 'fCanvas' at construction time. + // A restoreToCount() will be issued on destruction. + int fCanvasSaveCount; + + // clipPath, if present for the current context (not inherited). + SkTLazy fClipPath; + + // Deferred opacity optimization for leaf nodes. + float fDeferredPaintOpacity = 1; + + // Current object bounding box scope. + const OBBScope fOBBScope; +}; + +#endif // SkSVGRenderContext_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGSVG.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGSVG.h new file mode 100644 index 00000000000000..41e041de3f76cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGSVG.h @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGSVG_DEFINED +#define SkSVGSVG_DEFINED + +#include "modules/svg/include/SkSVGContainer.h" +#include "modules/svg/include/SkSVGTypes.h" +#include "src/base/SkTLazy.h" + +class SkSVGLengthContext; + +class SkSVGSVG : public SkSVGContainer { +public: + enum class Type { + kRoot, + kInner, + }; + static sk_sp Make(Type t = Type::kInner) { return sk_sp(new SkSVGSVG(t)); } + + SVG_ATTR(X , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Y , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Width , SkSVGLength, SkSVGLength(100, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(Height , SkSVGLength, SkSVGLength(100, SkSVGLength::Unit::kPercentage)) + SVG_ATTR(PreserveAspectRatio, SkSVGPreserveAspectRatio, SkSVGPreserveAspectRatio()) + + SVG_OPTIONAL_ATTR(ViewBox, SkSVGViewBoxType) + + SkSize intrinsicSize(const SkSVGLengthContext&) const; + + void renderNode(const SkSVGRenderContext&, const SkSVGIRI& iri) const; + +protected: + bool onPrepareToRender(SkSVGRenderContext*) const override; + + void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override; + +private: + explicit SkSVGSVG(Type t) + : INHERITED(SkSVGTag::kSvg) + , fType(t) + {} + + // Some attributes behave differently for the outermost svg element. + const Type fType; + + using INHERITED = SkSVGContainer; +}; + +#endif // SkSVGSVG_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGShape.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGShape.h new file mode 100644 index 00000000000000..79078354e9227c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGShape.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGShape_DEFINED +#define SkSVGShape_DEFINED + +#include "include/core/SkPath.h" +#include "modules/svg/include/SkSVGTransformableNode.h" + +class SkSVGLengthContext; +class SkPaint; + +class SkSVGShape : public SkSVGTransformableNode { +public: + void appendChild(sk_sp) override; + +protected: + SkSVGShape(SkSVGTag); + + void onRender(const SkSVGRenderContext&) const final; + + virtual void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&, + SkPathFillType) const = 0; + +private: + using INHERITED = SkSVGTransformableNode; +}; + +#endif // SkSVGShape_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGStop.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGStop.h new file mode 100644 index 00000000000000..58bf57b7642049 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGStop.h @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGStop_DEFINED +#define SkSVGStop_DEFINED + +#include "modules/svg/include/SkSVGHiddenContainer.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGLengthContext; + +class SkSVGStop : public SkSVGHiddenContainer { +public: + static sk_sp Make() { + return sk_sp(new SkSVGStop()); + } + + + SVG_ATTR(Offset, SkSVGLength, SkSVGLength(0, SkSVGLength::Unit::kPercentage)) + +protected: + bool parseAndSetAttribute(const char*, const char*) override; + +private: + SkSVGStop(); + + using INHERITED = SkSVGHiddenContainer; +}; + +#endif // SkSVGStop_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGText.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGText.h new file mode 100644 index 00000000000000..f1fa4e7eeb745b --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGText.h @@ -0,0 +1,122 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGText_DEFINED +#define SkSVGText_DEFINED + +#include + +#include "modules/svg/include/SkSVGTransformableNode.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGTextContext; + +// Base class for text-rendering nodes. +class SkSVGTextFragment : public SkSVGTransformableNode { +public: + void renderText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const; + +protected: + explicit SkSVGTextFragment(SkSVGTag t) : INHERITED(t) {} + + virtual void onShapeText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const = 0; + + // Text nodes other than the root element are not rendered directly. + void onRender(const SkSVGRenderContext&) const override {} + +private: + SkPath onAsPath(const SkSVGRenderContext&) const override; + + using INHERITED = SkSVGTransformableNode; +}; + +// Base class for nestable text containers (, , etc). +class SkSVGTextContainer : public SkSVGTextFragment { +public: + SVG_ATTR(X, std::vector, {}) + SVG_ATTR(Y, std::vector, {}) + SVG_ATTR(Dx, std::vector, {}) + SVG_ATTR(Dy, std::vector, {}) + SVG_ATTR(Rotate, std::vector, {}) + + SVG_ATTR(XmlSpace, SkSVGXmlSpace, SkSVGXmlSpace::kDefault) + + void appendChild(sk_sp) final; + +protected: + explicit SkSVGTextContainer(SkSVGTag t) : INHERITED(t) {} + + void onShapeText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const override; + + bool parseAndSetAttribute(const char*, const char*) override; + +private: + std::vector> fChildren; + + using INHERITED = SkSVGTextFragment; +}; + +class SkSVGText final : public SkSVGTextContainer { +public: + static sk_sp Make() { return sk_sp(new SkSVGText()); } + +private: + SkSVGText() : INHERITED(SkSVGTag::kText) {} + + void onRender(const SkSVGRenderContext&) const override; + + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + SkPath onAsPath(const SkSVGRenderContext&) const override; + + using INHERITED = SkSVGTextContainer; +}; + +class SkSVGTSpan final : public SkSVGTextContainer { +public: + static sk_sp Make() { return sk_sp(new SkSVGTSpan()); } + +private: + SkSVGTSpan() : INHERITED(SkSVGTag::kTSpan) {} + + using INHERITED = SkSVGTextContainer; +}; + +class SkSVGTextLiteral final : public SkSVGTextFragment { +public: + static sk_sp Make() { + return sk_sp(new SkSVGTextLiteral()); + } + + SVG_ATTR(Text, SkSVGStringType, SkSVGStringType()) + +private: + SkSVGTextLiteral() : INHERITED(SkSVGTag::kTextLiteral) {} + + void onShapeText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const override; + + void appendChild(sk_sp) override {} + + using INHERITED = SkSVGTextFragment; +}; + +class SkSVGTextPath final : public SkSVGTextContainer { +public: + static sk_sp Make() { return sk_sp(new SkSVGTextPath()); } + + SVG_ATTR(Href , SkSVGIRI , {} ) + SVG_ATTR(StartOffset, SkSVGLength, SkSVGLength(0)) + +private: + SkSVGTextPath() : INHERITED(SkSVGTag::kTextPath) {} + + void onShapeText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const override; + bool parseAndSetAttribute(const char*, const char*) override; + + using INHERITED = SkSVGTextContainer; +}; + +#endif // SkSVGText_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGTransformableNode.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGTransformableNode.h new file mode 100644 index 00000000000000..bc4d18f18e437c --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGTransformableNode.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGTransformableNode_DEFINED +#define SkSVGTransformableNode_DEFINED + +#include "include/core/SkMatrix.h" +#include "modules/svg/include/SkSVGNode.h" + +class SkSVGTransformableNode : public SkSVGNode { +public: + void setTransform(const SkSVGTransformType& t) { fTransform = t; } + +protected: + SkSVGTransformableNode(SkSVGTag); + + bool onPrepareToRender(SkSVGRenderContext*) const override; + + void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override; + + void mapToParent(SkPath*) const; + + void mapToParent(SkRect*) const; + +private: + // FIXME: should be sparse + SkSVGTransformType fTransform; + + using INHERITED = SkSVGNode; +}; + +#endif // SkSVGTransformableNode_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGTypes.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGTypes.h new file mode 100644 index 00000000000000..77c5fbef405623 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGTypes.h @@ -0,0 +1,731 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGTypes_DEFINED +#define SkSVGTypes_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPath.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSpan.h" +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" + +#include +#include + +using SkSVGColorType = SkColor; +using SkSVGIntegerType = int; +using SkSVGNumberType = SkScalar; +using SkSVGStringType = SkString; +using SkSVGViewBoxType = SkRect; +using SkSVGTransformType = SkMatrix; +using SkSVGPointsType = std::vector; + +enum class SkSVGPropertyState { + kUnspecified, + kInherit, + kValue, +}; + +// https://www.w3.org/TR/SVG11/intro.html#TermProperty +template class SkSVGProperty { +public: + using ValueT = T; + + SkSVGProperty() : fState(SkSVGPropertyState::kUnspecified) {} + + explicit SkSVGProperty(SkSVGPropertyState state) : fState(state) {} + + explicit SkSVGProperty(const T& value) : fState(SkSVGPropertyState::kValue) { + fValue = value; + } + + explicit SkSVGProperty(T&& value) : fState(SkSVGPropertyState::kValue) { + fValue = std::move(value); + } + + template + void init(Args&&... args) { + fState = SkSVGPropertyState::kValue; + fValue.emplace(std::forward(args)...); + } + + constexpr bool isInheritable() const { return kInheritable; } + + bool isValue() const { return fState == SkSVGPropertyState::kValue; } + + T* getMaybeNull() const { + return fValue.has_value() ? &fValue.value() : nullptr; + } + + void set(SkSVGPropertyState state) { + fState = state; + if (fState != SkSVGPropertyState::kValue) { + fValue.reset(); + } + } + + void set(const T& value) { + fState = SkSVGPropertyState::kValue; + fValue = value; + } + + void set(T&& value) { + fState = SkSVGPropertyState::kValue; + fValue = std::move(value); + } + + T* operator->() { + SkASSERT(fState == SkSVGPropertyState::kValue); + SkASSERT(fValue.has_value()); + return &fValue.value(); + } + + const T* operator->() const { + SkASSERT(fState == SkSVGPropertyState::kValue); + SkASSERT(fValue.has_value()); + return &fValue.value(); + } + + T& operator*() { + SkASSERT(fState == SkSVGPropertyState::kValue); + SkASSERT(fValue.has_value()); + return *fValue; + } + + const T& operator*() const { + SkASSERT(fState == SkSVGPropertyState::kValue); + SkASSERT(fValue.has_value()); + return *fValue; + } + +private: + SkSVGPropertyState fState; + std::optional fValue; +}; + +class SkSVGLength { +public: + enum class Unit { + kUnknown, + kNumber, + kPercentage, + kEMS, + kEXS, + kPX, + kCM, + kMM, + kIN, + kPT, + kPC, + }; + + constexpr SkSVGLength() : fValue(0), fUnit(Unit::kUnknown) {} + explicit constexpr SkSVGLength(SkScalar v, Unit u = Unit::kNumber) + : fValue(v), fUnit(u) {} + SkSVGLength(const SkSVGLength&) = default; + SkSVGLength& operator=(const SkSVGLength&) = default; + + bool operator==(const SkSVGLength& other) const { + return fUnit == other.fUnit && fValue == other.fValue; + } + bool operator!=(const SkSVGLength& other) const { return !(*this == other); } + + const SkScalar& value() const { return fValue; } + const Unit& unit() const { return fUnit; } + +private: + SkScalar fValue; + Unit fUnit; +}; + +// https://www.w3.org/TR/SVG11/linking.html#IRIReference +class SkSVGIRI { +public: + enum class Type { + kLocal, + kNonlocal, + kDataURI, + }; + + SkSVGIRI() : fType(Type::kLocal) {} + SkSVGIRI(Type t, const SkSVGStringType& iri) : fType(t), fIRI(iri) {} + + Type type() const { return fType; } + const SkSVGStringType& iri() const { return fIRI; } + + bool operator==(const SkSVGIRI& other) const { + return fType == other.fType && fIRI == other.fIRI; + } + bool operator!=(const SkSVGIRI& other) const { return !(*this == other); } + +private: + Type fType; + SkSVGStringType fIRI; +}; + +// https://www.w3.org/TR/SVG11/types.html#InterfaceSVGColor +class SkSVGColor { +public: + enum class Type { + kCurrentColor, + kColor, + kICCColor, + }; + using Vars = std::vector; + + SkSVGColor() : SkSVGColor(SK_ColorBLACK) {} + explicit SkSVGColor(const SkSVGColorType& c) : fType(Type::kColor), fColor(c), fVars(nullptr) {} + explicit SkSVGColor(Type t, Vars&& vars) + : fType(t), fColor(SK_ColorBLACK) + , fVars(vars.empty() ? nullptr : new RefCntVars(std::move(vars))) {} + explicit SkSVGColor(const SkSVGColorType& c, Vars&& vars) + : fType(Type::kColor), fColor(c) + , fVars(vars.empty() ? nullptr : new RefCntVars(std::move(vars))) {} + + SkSVGColor(const SkSVGColor&) = default; + SkSVGColor& operator=(const SkSVGColor&) = default; + SkSVGColor(SkSVGColor&&) = default; + SkSVGColor& operator=(SkSVGColor&&) = default; + + bool operator==(const SkSVGColor& other) const { + return fType == other.fType && fColor == other.fColor && fVars == other.fVars; + } + bool operator!=(const SkSVGColor& other) const { return !(*this == other); } + + Type type() const { return fType; } + const SkSVGColorType& color() const { SkASSERT(fType == Type::kColor); return fColor; } + SkSpan vars() const { + return fVars ? SkSpan(fVars->fData) : SkSpan(); + } + SkSpan vars() { + return fVars ? SkSpan(fVars->fData) : SkSpan(); + } + +private: + Type fType; + SkSVGColorType fColor; + struct RefCntVars : public SkNVRefCnt { + RefCntVars(Vars&& vars) : fData(std::move(vars)) {} + Vars fData; + }; + sk_sp fVars; +}; + +class SkSVGPaint { +public: + enum class Type { + kNone, + kColor, + kIRI, + }; + + SkSVGPaint() : fType(Type::kNone), fColor(SK_ColorBLACK) {} + explicit SkSVGPaint(Type t) : fType(t), fColor(SK_ColorBLACK) {} + explicit SkSVGPaint(SkSVGColor c) : fType(Type::kColor), fColor(std::move(c)) {} + SkSVGPaint(const SkSVGIRI& iri, SkSVGColor fallback_color) + : fType(Type::kIRI), fColor(std::move(fallback_color)), fIRI(iri) {} + + SkSVGPaint(const SkSVGPaint&) = default; + SkSVGPaint& operator=(const SkSVGPaint&) = default; + SkSVGPaint(SkSVGPaint&&) = default; + SkSVGPaint& operator=(SkSVGPaint&&) = default; + + bool operator==(const SkSVGPaint& other) const { + return fType == other.fType && fColor == other.fColor && fIRI == other.fIRI; + } + bool operator!=(const SkSVGPaint& other) const { return !(*this == other); } + + Type type() const { return fType; } + const SkSVGColor& color() const { + SkASSERT(fType == Type::kColor || fType == Type::kIRI); + return fColor; + } + const SkSVGIRI& iri() const { SkASSERT(fType == Type::kIRI); return fIRI; } + +private: + Type fType; + + // Logical union. + SkSVGColor fColor; + SkSVGIRI fIRI; +}; + +// | none (used for clip/mask/filter properties) +class SkSVGFuncIRI { +public: + enum class Type { + kNone, + kIRI, + }; + + SkSVGFuncIRI() : fType(Type::kNone) {} + explicit SkSVGFuncIRI(Type t) : fType(t) {} + explicit SkSVGFuncIRI(SkSVGIRI&& iri) : fType(Type::kIRI), fIRI(std::move(iri)) {} + + bool operator==(const SkSVGFuncIRI& other) const { + return fType == other.fType && fIRI == other.fIRI; + } + bool operator!=(const SkSVGFuncIRI& other) const { return !(*this == other); } + + Type type() const { return fType; } + const SkSVGIRI& iri() const { SkASSERT(fType == Type::kIRI); return fIRI; } + +private: + Type fType; + SkSVGIRI fIRI; +}; + +enum class SkSVGLineCap { + kButt, + kRound, + kSquare, +}; + +class SkSVGLineJoin { +public: + enum class Type { + kMiter, + kRound, + kBevel, + kInherit, + }; + + constexpr SkSVGLineJoin() : fType(Type::kInherit) {} + constexpr explicit SkSVGLineJoin(Type t) : fType(t) {} + + SkSVGLineJoin(const SkSVGLineJoin&) = default; + SkSVGLineJoin& operator=(const SkSVGLineJoin&) = default; + + bool operator==(const SkSVGLineJoin& other) const { return fType == other.fType; } + bool operator!=(const SkSVGLineJoin& other) const { return !(*this == other); } + + Type type() const { return fType; } + +private: + Type fType; +}; + +class SkSVGSpreadMethod { +public: + // These values must match Skia's SkShader::TileMode enum. + enum class Type { + kPad, // kClamp_TileMode + kRepeat, // kRepeat_TileMode + kReflect, // kMirror_TileMode + }; + + constexpr SkSVGSpreadMethod() : fType(Type::kPad) {} + constexpr explicit SkSVGSpreadMethod(Type t) : fType(t) {} + + SkSVGSpreadMethod(const SkSVGSpreadMethod&) = default; + SkSVGSpreadMethod& operator=(const SkSVGSpreadMethod&) = default; + + bool operator==(const SkSVGSpreadMethod& other) const { return fType == other.fType; } + bool operator!=(const SkSVGSpreadMethod& other) const { return !(*this == other); } + + Type type() const { return fType; } + +private: + Type fType; +}; + +class SkSVGFillRule { +public: + enum class Type { + kNonZero, + kEvenOdd, + kInherit, + }; + + constexpr SkSVGFillRule() : fType(Type::kInherit) {} + constexpr explicit SkSVGFillRule(Type t) : fType(t) {} + + SkSVGFillRule(const SkSVGFillRule&) = default; + SkSVGFillRule& operator=(const SkSVGFillRule&) = default; + + bool operator==(const SkSVGFillRule& other) const { return fType == other.fType; } + bool operator!=(const SkSVGFillRule& other) const { return !(*this == other); } + + Type type() const { return fType; } + + SkPathFillType asFillType() const { + SkASSERT(fType != Type::kInherit); // should never be called for unresolved values. + return fType == Type::kEvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding; + } + +private: + Type fType; +}; + +class SkSVGVisibility { +public: + enum class Type { + kVisible, + kHidden, + kCollapse, + kInherit, + }; + + constexpr SkSVGVisibility() : fType(Type::kVisible) {} + constexpr explicit SkSVGVisibility(Type t) : fType(t) {} + + SkSVGVisibility(const SkSVGVisibility&) = default; + SkSVGVisibility& operator=(const SkSVGVisibility&) = default; + + bool operator==(const SkSVGVisibility& other) const { return fType == other.fType; } + bool operator!=(const SkSVGVisibility& other) const { return !(*this == other); } + + Type type() const { return fType; } + +private: + Type fType; +}; + +class SkSVGDashArray { +public: + enum class Type { + kNone, + kDashArray, + kInherit, + }; + + SkSVGDashArray() : fType(Type::kNone) {} + explicit SkSVGDashArray(Type t) : fType(t) {} + explicit SkSVGDashArray(std::vector&& dashArray) + : fType(Type::kDashArray) + , fDashArray(std::move(dashArray)) {} + + SkSVGDashArray(const SkSVGDashArray&) = default; + SkSVGDashArray& operator=(const SkSVGDashArray&) = default; + + bool operator==(const SkSVGDashArray& other) const { + return fType == other.fType && fDashArray == other.fDashArray; + } + bool operator!=(const SkSVGDashArray& other) const { return !(*this == other); } + + Type type() const { return fType; } + + const std::vector& dashArray() const { return fDashArray; } + +private: + Type fType; + std::vector fDashArray; +}; + +class SkSVGStopColor { +public: + enum class Type { + kColor, + kCurrentColor, + kICCColor, + kInherit, + }; + + SkSVGStopColor() : fType(Type::kColor), fColor(SK_ColorBLACK) {} + explicit SkSVGStopColor(Type t) : fType(t), fColor(SK_ColorBLACK) {} + explicit SkSVGStopColor(const SkSVGColorType& c) : fType(Type::kColor), fColor(c) {} + + SkSVGStopColor(const SkSVGStopColor&) = default; + SkSVGStopColor& operator=(const SkSVGStopColor&) = default; + + bool operator==(const SkSVGStopColor& other) const { + return fType == other.fType && fColor == other.fColor; + } + bool operator!=(const SkSVGStopColor& other) const { return !(*this == other); } + + Type type() const { return fType; } + const SkSVGColorType& color() const { SkASSERT(fType == Type::kColor); return fColor; } + +private: + Type fType; + SkSVGColorType fColor; +}; + +class SkSVGObjectBoundingBoxUnits { +public: + enum class Type { + kUserSpaceOnUse, + kObjectBoundingBox, + }; + + SkSVGObjectBoundingBoxUnits() : fType(Type::kUserSpaceOnUse) {} + explicit SkSVGObjectBoundingBoxUnits(Type t) : fType(t) {} + + bool operator==(const SkSVGObjectBoundingBoxUnits& other) const { + return fType == other.fType; + } + bool operator!=(const SkSVGObjectBoundingBoxUnits& other) const { + return !(*this == other); + } + + Type type() const { return fType; } + +private: + Type fType; +}; + +class SkSVGFontFamily { +public: + enum class Type { + kFamily, + kInherit, + }; + + SkSVGFontFamily() : fType(Type::kInherit) {} + explicit SkSVGFontFamily(const char family[]) + : fType(Type::kFamily) + , fFamily(family) {} + + bool operator==(const SkSVGFontFamily& other) const { + return fType == other.fType && fFamily == other.fFamily; + } + bool operator!=(const SkSVGFontFamily& other) const { return !(*this == other); } + + Type type() const { return fType; } + + const SkString& family() const { return fFamily; } + +private: + Type fType; + SkString fFamily; +}; + +class SkSVGFontStyle { +public: + enum class Type { + kNormal, + kItalic, + kOblique, + kInherit, + }; + + SkSVGFontStyle() : fType(Type::kInherit) {} + explicit SkSVGFontStyle(Type t) : fType(t) {} + + bool operator==(const SkSVGFontStyle& other) const { + return fType == other.fType; + } + bool operator!=(const SkSVGFontStyle& other) const { return !(*this == other); } + + Type type() const { return fType; } + +private: + Type fType; +}; + +class SkSVGFontSize { +public: + enum class Type { + kLength, + kInherit, + }; + + SkSVGFontSize() : fType(Type::kInherit), fSize(0) {} + explicit SkSVGFontSize(const SkSVGLength& s) + : fType(Type::kLength) + , fSize(s) {} + + bool operator==(const SkSVGFontSize& other) const { + return fType == other.fType && fSize == other.fSize; + } + bool operator!=(const SkSVGFontSize& other) const { return !(*this == other); } + + Type type() const { return fType; } + + const SkSVGLength& size() const { return fSize; } + +private: + Type fType; + SkSVGLength fSize; +}; + +class SkSVGFontWeight { +public: + enum class Type { + k100, + k200, + k300, + k400, + k500, + k600, + k700, + k800, + k900, + kNormal, + kBold, + kBolder, + kLighter, + kInherit, + }; + + SkSVGFontWeight() : fType(Type::kInherit) {} + explicit SkSVGFontWeight(Type t) : fType(t) {} + + bool operator==(const SkSVGFontWeight& other) const { + return fType == other.fType; + } + bool operator!=(const SkSVGFontWeight& other) const { return !(*this == other); } + + Type type() const { return fType; } + +private: + Type fType; +}; + +struct SkSVGPreserveAspectRatio { + enum Align : uint8_t { + // These values are chosen such that bits [0,1] encode X alignment, and + // bits [2,3] encode Y alignment. + kXMinYMin = 0x00, + kXMidYMin = 0x01, + kXMaxYMin = 0x02, + kXMinYMid = 0x04, + kXMidYMid = 0x05, + kXMaxYMid = 0x06, + kXMinYMax = 0x08, + kXMidYMax = 0x09, + kXMaxYMax = 0x0a, + + kNone = 0x10, + }; + + enum Scale { + kMeet, + kSlice, + }; + + Align fAlign = kXMidYMid; + Scale fScale = kMeet; +}; + +class SkSVGTextAnchor { +public: + enum class Type { + kStart, + kMiddle, + kEnd, + kInherit, + }; + + SkSVGTextAnchor() : fType(Type::kInherit) {} + explicit SkSVGTextAnchor(Type t) : fType(t) {} + + bool operator==(const SkSVGTextAnchor& other) const { + return fType == other.fType; + } + bool operator!=(const SkSVGTextAnchor& other) const { return !(*this == other); } + + Type type() const { return fType; } + +private: + Type fType; +}; + +// https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveInAttribute +class SkSVGFeInputType { +public: + enum class Type { + kSourceGraphic, + kSourceAlpha, + kBackgroundImage, + kBackgroundAlpha, + kFillPaint, + kStrokePaint, + kFilterPrimitiveReference, + kUnspecified, + }; + + SkSVGFeInputType() : fType(Type::kUnspecified) {} + explicit SkSVGFeInputType(Type t) : fType(t) {} + explicit SkSVGFeInputType(const SkSVGStringType& id) + : fType(Type::kFilterPrimitiveReference), fId(id) {} + + bool operator==(const SkSVGFeInputType& other) const { + return fType == other.fType && fId == other.fId; + } + bool operator!=(const SkSVGFeInputType& other) const { return !(*this == other); } + + const SkString& id() const { + SkASSERT(fType == Type::kFilterPrimitiveReference); + return fId; + } + + Type type() const { return fType; } + +private: + Type fType; + SkString fId; +}; + +enum class SkSVGFeColorMatrixType { + kMatrix, + kSaturate, + kHueRotate, + kLuminanceToAlpha, +}; + +using SkSVGFeColorMatrixValues = std::vector; + +enum class SkSVGFeCompositeOperator { + kOver, + kIn, + kOut, + kAtop, + kXor, + kArithmetic, +}; + +class SkSVGFeTurbulenceBaseFrequency { +public: + SkSVGFeTurbulenceBaseFrequency() : fFreqX(0), fFreqY(0) {} + SkSVGFeTurbulenceBaseFrequency(SkSVGNumberType freqX, SkSVGNumberType freqY) + : fFreqX(freqX), fFreqY(freqY) {} + + SkSVGNumberType freqX() const { return fFreqX; } + SkSVGNumberType freqY() const { return fFreqY; } + +private: + SkSVGNumberType fFreqX; + SkSVGNumberType fFreqY; +}; + +struct SkSVGFeTurbulenceType { + enum Type { + kFractalNoise, + kTurbulence, + }; + + Type fType; + + SkSVGFeTurbulenceType() : fType(kTurbulence) {} + explicit SkSVGFeTurbulenceType(Type type) : fType(type) {} +}; + +enum class SkSVGXmlSpace { + kDefault, + kPreserve, +}; + +enum class SkSVGColorspace { + kAuto, + kSRGB, + kLinearRGB, +}; + +// https://www.w3.org/TR/SVG11/painting.html#DisplayProperty +enum class SkSVGDisplay { + kInline, + kNone, +}; + +#endif // SkSVGTypes_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGUse.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGUse.h new file mode 100644 index 00000000000000..93c2d2096403cb --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGUse.h @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGUse_DEFINED +#define SkSVGUse_DEFINED + +#include "modules/svg/include/SkSVGTransformableNode.h" +#include "modules/svg/include/SkSVGTypes.h" + +/** + * Implements support for (reference) elements. + * (https://www.w3.org/TR/SVG11/struct.html#UseElement) + */ +class SkSVGUse final : public SkSVGTransformableNode { +public: + static sk_sp Make() { return sk_sp(new SkSVGUse()); } + + void appendChild(sk_sp) override; + + SVG_ATTR(X , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Y , SkSVGLength, SkSVGLength(0)) + SVG_ATTR(Href, SkSVGIRI , SkSVGIRI()) + +protected: + bool onPrepareToRender(SkSVGRenderContext*) const override; + void onRender(const SkSVGRenderContext&) const override; + SkPath onAsPath(const SkSVGRenderContext&) const override; + SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override; + +private: + SkSVGUse(); + + bool parseAndSetAttribute(const char*, const char*) override; + + using INHERITED = SkSVGTransformableNode; +}; + +#endif // SkSVGUse_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGValue.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGValue.h new file mode 100644 index 00000000000000..d03afa6d9fa989 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/modules/svg/include/SkSVGValue.h @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGValue_DEFINED +#define SkSVGValue_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPath.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkNoncopyable.h" +#include "modules/svg/include/SkSVGTypes.h" + +class SkSVGValue : public SkNoncopyable { +public: + enum class Type { + kColor, + kFilter, + kLength, + kNumber, + kObjectBoundingBoxUnits, + kPreserveAspectRatio, + kStopColor, + kString, + kTransform, + kViewBox, + }; + + Type type() const { return fType; } + + template + const T* as() const { + return fType == T::TYPE ? static_cast(this) : nullptr; + } + +protected: + SkSVGValue(Type t) : fType(t) { } + +private: + Type fType; + + using INHERITED = SkNoncopyable; +}; + +template +class SkSVGWrapperValue final : public SkSVGValue { +public: + static constexpr Type TYPE = ValueType; + + explicit SkSVGWrapperValue(const T& v) + : INHERITED(ValueType) + , fWrappedValue(v) { } + + operator const T&() const { return fWrappedValue; } + const T* operator->() const { return &fWrappedValue; } + +private: + // Stack-only + void* operator new(size_t) = delete; + void* operator new(size_t, void*) = delete; + + const T& fWrappedValue; + + using INHERITED = SkSVGValue; +}; + +using SkSVGColorValue = SkSVGWrapperValue; +using SkSVGLengthValue = SkSVGWrapperValue; +using SkSVGTransformValue = SkSVGWrapperValue; +using SkSVGViewBoxValue = SkSVGWrapperValue; +using SkSVGNumberValue = SkSVGWrapperValue; +using SkSVGStringValue = SkSVGWrapperValue; +using SkSVGStopColorValue = SkSVGWrapperValue; + +using SkSVGPreserveAspectRatioValue = SkSVGWrapperValue; + +using SkSVGObjectBoundingBoxUnitsValue = SkSVGWrapperValue; + +#endif // SkSVGValue_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/src/core/SkTHash.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/src/core/SkTHash.h new file mode 100644 index 00000000000000..e72483b501df1e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/skia/src/core/SkTHash.h @@ -0,0 +1,595 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTHash_DEFINED +#define SkTHash_DEFINED + +#include "include/core/SkTypes.h" +#include "include/private/SkChecksum.h" +#include "include/private/base/SkTemplates.h" + +#include +#include +#include + +namespace skia_private { + +// Before trying to use THashTable, look below to see if THashMap or THashSet works for you. +// They're easier to use, usually perform the same, and have fewer sharp edges. + +// T and K are treated as ordinary copyable C++ types. +// Traits must have: +// - static K GetKey(T) +// - static uint32_t Hash(K) +// If the key is large and stored inside T, you may want to make K a const&. +// Similarly, if T is large you might want it to be a pointer. +template +class THashTable { +public: + THashTable() = default; + ~THashTable() = default; + + THashTable(const THashTable& that) { *this = that; } + THashTable( THashTable&& that) { *this = std::move(that); } + + THashTable& operator=(const THashTable& that) { + if (this != &that) { + fCount = that.fCount; + fCapacity = that.fCapacity; + fSlots.reset(that.fCapacity); + for (int i = 0; i < fCapacity; i++) { + fSlots[i] = that.fSlots[i]; + } + } + return *this; + } + + THashTable& operator=(THashTable&& that) { + if (this != &that) { + fCount = that.fCount; + fCapacity = that.fCapacity; + fSlots = std::move(that.fSlots); + + that.fCount = that.fCapacity = 0; + } + return *this; + } + + // Clear the table. + void reset() { *this = THashTable(); } + + // How many entries are in the table? + int count() const { return fCount; } + + // How many slots does the table contain? (Note that unlike an array, hash tables can grow + // before reaching 100% capacity.) + int capacity() const { return fCapacity; } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fCapacity * sizeof(Slot); } + + // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!!!!! + // set(), find() and foreach() all allow mutable access to table entries. + // If you change an entry so that it no longer has the same key, all hell + // will break loose. Do not do that! + // + // Please prefer to use THashMap or THashSet, which do not have this danger. + + // The pointers returned by set() and find() are valid only until the next call to set(). + // The pointers you receive in foreach() are only valid for its duration. + + // Copy val into the hash table, returning a pointer to the copy now in the table. + // If there already is an entry in the table with the same key, we overwrite it. + T* set(T val) { + if (4 * fCount >= 3 * fCapacity) { + this->resize(fCapacity > 0 ? fCapacity * 2 : 4); + } + return this->uncheckedSet(std::move(val)); + } + + // If there is an entry in the table with this key, return a pointer to it. If not, null. + T* find(const K& key) const { + uint32_t hash = Hash(key); + int index = hash & (fCapacity-1); + for (int n = 0; n < fCapacity; n++) { + Slot& s = fSlots[index]; + if (s.empty()) { + return nullptr; + } + if (hash == s.fHash && key == Traits::GetKey(*s)) { + return &*s; + } + index = this->next(index); + } + SkASSERT(fCapacity == fCount); + return nullptr; + } + + // If there is an entry in the table with this key, return it. If not, null. + // This only works for pointer type T, and cannot be used to find an nullptr entry. + T findOrNull(const K& key) const { + if (T* p = this->find(key)) { + return *p; + } + return nullptr; + } + + // Remove the value with this key from the hash table. + void remove(const K& key) { + SkASSERT(this->find(key)); + + uint32_t hash = Hash(key); + int index = hash & (fCapacity-1); + for (int n = 0; n < fCapacity; n++) { + Slot& s = fSlots[index]; + SkASSERT(s.has_value()); + if (hash == s.fHash && key == Traits::GetKey(*s)) { + this->removeSlot(index); + if (4 * fCount <= fCapacity && fCapacity > 4) { + this->resize(fCapacity / 2); + } + return; + } + index = this->next(index); + } + } + + // Hash tables will automatically resize themselves when set() and remove() are called, but + // resize() can be called to manually grow capacity before a bulk insertion. + void resize(int capacity) { + SkASSERT(capacity >= fCount); + int oldCapacity = fCapacity; + SkDEBUGCODE(int oldCount = fCount); + + fCount = 0; + fCapacity = capacity; + AutoTArray oldSlots = std::move(fSlots); + fSlots = AutoTArray(capacity); + + for (int i = 0; i < oldCapacity; i++) { + Slot& s = oldSlots[i]; + if (s.has_value()) { + this->uncheckedSet(*std::move(s)); + } + } + SkASSERT(fCount == oldCount); + } + + // Call fn on every entry in the table. You may mutate the entries, but be very careful. + template // f(T*) + void foreach(Fn&& fn) { + for (int i = 0; i < fCapacity; i++) { + if (fSlots[i].has_value()) { + fn(&*fSlots[i]); + } + } + } + + // Call fn on every entry in the table. You may not mutate anything. + template // f(T) or f(const T&) + void foreach(Fn&& fn) const { + for (int i = 0; i < fCapacity; i++) { + if (fSlots[i].has_value()) { + fn(*fSlots[i]); + } + } + } + + // A basic iterator-like class which disallows mutation; sufficient for range-based for loops. + // Intended for use by THashMap and THashSet via begin() and end(). + // Adding or removing elements may invalidate all iterators. + template + class Iter { + public: + using TTable = THashTable; + + Iter(const TTable* table, int slot) : fTable(table), fSlot(slot) {} + + static Iter MakeBegin(const TTable* table) { + return Iter{table, table->firstPopulatedSlot()}; + } + + static Iter MakeEnd(const TTable* table) { + return Iter{table, table->capacity()}; + } + + const SlotVal& operator*() const { + return *fTable->slot(fSlot); + } + + const SlotVal* operator->() const { + return fTable->slot(fSlot); + } + + bool operator==(const Iter& that) const { + // Iterators from different tables shouldn't be compared against each other. + SkASSERT(fTable == that.fTable); + return fSlot == that.fSlot; + } + + bool operator!=(const Iter& that) const { + return !(*this == that); + } + + Iter& operator++() { + fSlot = fTable->nextPopulatedSlot(fSlot); + return *this; + } + + Iter operator++(int) { + Iter old = *this; + this->operator++(); + return old; + } + + protected: + const TTable* fTable; + int fSlot; + }; + +private: + // Finds the first non-empty slot for an iterator. + int firstPopulatedSlot() const { + for (int i = 0; i < fCapacity; i++) { + if (fSlots[i].has_value()) { + return i; + } + } + return fCapacity; + } + + // Increments an iterator's slot. + int nextPopulatedSlot(int currentSlot) const { + for (int i = currentSlot + 1; i < fCapacity; i++) { + if (fSlots[i].has_value()) { + return i; + } + } + return fCapacity; + } + + // Reads from an iterator's slot. + const T* slot(int i) const { + SkASSERT(fSlots[i].has_value()); + return &*fSlots[i]; + } + + T* uncheckedSet(T&& val) { + const K& key = Traits::GetKey(val); + SkASSERT(key == key); + uint32_t hash = Hash(key); + int index = hash & (fCapacity-1); + for (int n = 0; n < fCapacity; n++) { + Slot& s = fSlots[index]; + if (s.empty()) { + // New entry. + s.emplace(std::move(val), hash); + fCount++; + return &*s; + } + if (hash == s.fHash && key == Traits::GetKey(*s)) { + // Overwrite previous entry. + // Note: this triggers extra copies when adding the same value repeatedly. + s.emplace(std::move(val), hash); + return &*s; + } + + index = this->next(index); + } + SkASSERT(false); + return nullptr; + } + + void removeSlot(int index) { + fCount--; + + // Rearrange elements to restore the invariants for linear probing. + for (;;) { + Slot& emptySlot = fSlots[index]; + int emptyIndex = index; + int originalIndex; + // Look for an element that can be moved into the empty slot. + // If the empty slot is in between where an element landed, and its native slot, then + // move it to the empty slot. Don't move it if its native slot is in between where + // the element landed and the empty slot. + // [native] <= [empty] < [candidate] == GOOD, can move candidate to empty slot + // [empty] < [native] < [candidate] == BAD, need to leave candidate where it is + do { + index = this->next(index); + Slot& s = fSlots[index]; + if (s.empty()) { + // We're done shuffling elements around. Clear the last empty slot. + emptySlot.reset(); + return; + } + originalIndex = s.fHash & (fCapacity - 1); + } while ((index <= originalIndex && originalIndex < emptyIndex) + || (originalIndex < emptyIndex && emptyIndex < index) + || (emptyIndex < index && index <= originalIndex)); + // Move the element to the empty slot. + Slot& moveFrom = fSlots[index]; + emptySlot = std::move(moveFrom); + } + } + + int next(int index) const { + index--; + if (index < 0) { index += fCapacity; } + return index; + } + + static uint32_t Hash(const K& key) { + uint32_t hash = Traits::Hash(key) & 0xffffffff; + return hash ? hash : 1; // We reserve hash 0 to mark empty. + } + + class Slot { + public: + Slot() = default; + ~Slot() { this->reset(); } + + Slot(const Slot& that) { *this = that; } + Slot& operator=(const Slot& that) { + if (this == &that) { + return *this; + } + if (fHash) { + if (that.fHash) { + fVal.fStorage = that.fVal.fStorage; + fHash = that.fHash; + } else { + this->reset(); + } + } else { + if (that.fHash) { + new (&fVal.fStorage) T(that.fVal.fStorage); + fHash = that.fHash; + } else { + // do nothing, no value on either side + } + } + return *this; + } + + Slot(Slot&& that) { *this = std::move(that); } + Slot& operator=(Slot&& that) { + if (this == &that) { + return *this; + } + if (fHash) { + if (that.fHash) { + fVal.fStorage = std::move(that.fVal.fStorage); + fHash = that.fHash; + } else { + this->reset(); + } + } else { + if (that.fHash) { + new (&fVal.fStorage) T(std::move(that.fVal.fStorage)); + fHash = that.fHash; + } else { + // do nothing, no value on either side + } + } + return *this; + } + + T& operator*() & { return fVal.fStorage; } + const T& operator*() const& { return fVal.fStorage; } + T&& operator*() && { return std::move(fVal.fStorage); } + const T&& operator*() const&& { return std::move(fVal.fStorage); } + + Slot& emplace(T&& v, uint32_t h) { + this->reset(); + new (&fVal.fStorage) T(std::move(v)); + fHash = h; + return *this; + } + + bool has_value() const { return fHash != 0; } + explicit operator bool() const { return this->has_value(); } + bool empty() const { return !this->has_value(); } + + void reset() { + if (fHash) { + fVal.fStorage.~T(); + fHash = 0; + } + } + + uint32_t fHash = 0; + + private: + union Storage { + T fStorage; + Storage() {} + ~Storage() {} + } fVal; + }; + + int fCount = 0, + fCapacity = 0; + AutoTArray fSlots; +}; + +// Maps K->V. A more user-friendly wrapper around THashTable, suitable for most use cases. +// K and V are treated as ordinary copyable C++ types, with no assumed relationship between the two. +template +class THashMap { +public: + // Allow default construction and assignment. + THashMap() = default; + + THashMap(THashMap&& that) = default; + THashMap(const THashMap& that) = default; + + THashMap& operator=(THashMap&& that) = default; + THashMap& operator=(const THashMap& that) = default; + + // Construct with an initializer list of key-value pairs. + struct Pair : public std::pair { + using std::pair::pair; + static const K& GetKey(const Pair& p) { return p.first; } + static auto Hash(const K& key) { return HashK()(key); } + }; + + THashMap(std::initializer_list pairs) { + fTable.resize(pairs.size() * 5 / 3); + for (const Pair& p : pairs) { + fTable.set(p); + } + } + + // Clear the map. + void reset() { fTable.reset(); } + + // How many key/value pairs are in the table? + int count() const { return fTable.count(); } + + // Is empty? + bool empty() const { return fTable.count() == 0; } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } + + // N.B. The pointers returned by set() and find() are valid only until the next call to set(). + + // Set key to val in the table, replacing any previous value with the same key. + // We copy both key and val, and return a pointer to the value copy now in the table. + V* set(K key, V val) { + Pair* out = fTable.set({std::move(key), std::move(val)}); + return &out->second; + } + + // If there is key/value entry in the table with this key, return a pointer to the value. + // If not, return null. + V* find(const K& key) const { + if (Pair* p = fTable.find(key)) { + return &p->second; + } + return nullptr; + } + + V& operator[](const K& key) { + if (V* val = this->find(key)) { + return *val; + } + return *this->set(key, V{}); + } + + // Remove the key/value entry in the table with this key. + void remove(const K& key) { + SkASSERT(this->find(key)); + fTable.remove(key); + } + + // Call fn on every key/value pair in the table. You may mutate the value but not the key. + template // f(K, V*) or f(const K&, V*) + void foreach(Fn&& fn) { + fTable.foreach([&fn](Pair* p){ fn(p->first, &p->second); }); + } + + // Call fn on every key/value pair in the table. You may not mutate anything. + template // f(K, V), f(const K&, V), f(K, const V&) or f(const K&, const V&). + void foreach(Fn&& fn) const { + fTable.foreach([&fn](const Pair& p){ fn(p.first, p.second); }); + } + + // Dereferencing an iterator gives back a key-value pair, suitable for structured binding. + using Iter = typename THashTable::template Iter>; + + Iter begin() const { + return Iter::MakeBegin(&fTable); + } + + Iter end() const { + return Iter::MakeEnd(&fTable); + } + +private: + THashTable fTable; +}; + +// A set of T. T is treated as an ordinary copyable C++ type. +template +class THashSet { +public: + // Allow default construction and assignment. + THashSet() = default; + + THashSet(THashSet&& that) = default; + THashSet(const THashSet& that) = default; + + THashSet& operator=(THashSet&& that) = default; + THashSet& operator=(const THashSet& that) = default; + + // Construct with an initializer list of Ts. + THashSet(std::initializer_list vals) { + fTable.resize(vals.size() * 5 / 3); + for (const T& val : vals) { + fTable.set(val); + } + } + + // Clear the set. + void reset() { fTable.reset(); } + + // How many items are in the set? + int count() const { return fTable.count(); } + + // Is empty? + bool empty() const { return fTable.count() == 0; } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } + + // Copy an item into the set. + void add(T item) { fTable.set(std::move(item)); } + + // Is this item in the set? + bool contains(const T& item) const { return SkToBool(this->find(item)); } + + // If an item equal to this is in the set, return a pointer to it, otherwise null. + // This pointer remains valid until the next call to add(). + const T* find(const T& item) const { return fTable.find(item); } + + // Remove the item in the set equal to this. + void remove(const T& item) { + SkASSERT(this->contains(item)); + fTable.remove(item); + } + + // Call fn on every item in the set. You may not mutate anything. + template // f(T), f(const T&) + void foreach (Fn&& fn) const { + fTable.foreach(fn); + } + +private: + struct Traits { + static const T& GetKey(const T& item) { return item; } + static auto Hash(const T& item) { return HashT()(item); } + }; + +public: + using Iter = typename THashTable::template Iter; + + Iter begin() const { + return Iter::MakeBegin(&fTable); + } + + Iter end() const { + return Iter::MakeEnd(&fTable); + } + +private: + THashTable fTable; +}; + +} // namespace skia_private + +#endif // SkTHash_DEFINED diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkLog.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkLog.h new file mode 100644 index 00000000000000..901c02ffd634e4 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkLog.h @@ -0,0 +1,82 @@ +// +// Created by Christian Falch on 26/08/2021. +// + +#pragma once + +#include +#include + +#ifdef ANDROID +#include +#endif + +#ifdef TARGET_OS_IPHONE +#include +#endif + +namespace RNSkia { + +namespace jsi = facebook::jsi; + +class RNSkLogger { +public: + /** + * Logs message to console + * @param message Message to be written out + */ + static void logToConsole(std::string message) { +#ifdef ANDROID + __android_log_write(ANDROID_LOG_INFO, "RNSkia", message.c_str()); +#endif + +#ifdef TARGET_OS_IPHONE + syslog(LOG_ERR, "%s\n", message.c_str()); +#endif + } + + /** + * Logs to console + * @param fmt Format string + * @param ... Arguments to format string + */ + static void logToConsole(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + static char buffer[512]; + vsnprintf(buffer, sizeof(buffer), fmt, args); +#ifdef ANDROID + __android_log_write(ANDROID_LOG_INFO, "RNSkia", buffer); +#endif +#ifdef TARGET_OS_IPHONE + syslog(LOG_ERR, "RNSKIA: %s\n", buffer); +#endif + va_end(args); + } + + static void logToJavascriptConsole(jsi::Runtime &runtime, + const std::string &message) { + auto console = RNSkLogger::getJavascriptConsole(runtime).asObject(runtime); + auto log = console.getPropertyAsFunction(runtime, "log"); + log.call(runtime, jsi::String::createFromUtf8(runtime, message)); + } + + static void warnToJavascriptConsole(jsi::Runtime &runtime, + const std::string &message) { + auto console = RNSkLogger::getJavascriptConsole(runtime).asObject(runtime); + auto warn = console.getPropertyAsFunction(runtime, "warn"); + warn.call(runtime, jsi::String::createFromUtf8(runtime, message)); + } + +private: + static jsi::Value getJavascriptConsole(jsi::Runtime &runtime) { + auto console = runtime.global().getProperty(runtime, "console"); + if (console.isUndefined() || console.isNull()) { + throw jsi::JSError(runtime, "Could not find console object."); + return jsi::Value::undefined(); + } + return console; + } +}; +} // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkMeasureTime.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkMeasureTime.h new file mode 100644 index 00000000000000..de3e6acde53d3e --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkMeasureTime.h @@ -0,0 +1,32 @@ +// +// Created by Christian Falch on 24/08/2021. +// + +#pragma once + +#include +#include + +#include "RNSkLog.h" + +namespace RNSkia { + +class RNSkMeasureTime { +public: + explicit RNSkMeasureTime(const std::string &name) + : _name(name), _start(std::chrono::high_resolution_clock::now()) {} + + ~RNSkMeasureTime() { + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(stop - _start) + .count(); + RNSkLogger::logToConsole("%s: %lld ms\n", _name.c_str(), duration); + } + +private: + std::string _name; + std::chrono::time_point _start; +}; + +}; // namespace RNSkia diff --git a/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkTimingInfo.h b/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkTimingInfo.h new file mode 100644 index 00000000000000..10d86ec2a7e190 --- /dev/null +++ b/android/vendored/sdk49/@shopify/react-native-skia/cpp/utils/RNSkTimingInfo.h @@ -0,0 +1,107 @@ +#pragma once + +#include "RNSkLog.h" +#include +#include +#include + +#define NUMBER_OF_DURATION_SAMPLES 10 + +namespace RNSkia { + +using frame = std::chrono::duration>; +using ms = std::chrono::duration; +using high_resolution_clock = std::chrono::high_resolution_clock; + +class RNSkTimingInfo { +public: + explicit RNSkTimingInfo(const std::string &name) : _name(std::move(name)) { + reset(); + } + + ~RNSkTimingInfo() {} + + void reset() { + _lastDurationIndex = 0; + _lastDurationsCount = 0; + _lastDuration = 0; + _prevFpsTimer = -1; + _frameCount = 0; + _lastFrameCount = -1; + _didSkip = false; + _average = 0; + } + + void beginTiming() { _start = high_resolution_clock::now(); } + + void stopTiming() { + std::chrono::time_point stop = + high_resolution_clock::now(); + addLastDuration( + std::chrono::duration_cast(stop - _start) + .count()); + tick(stop); + if (_didSkip) { + _didSkip = false; + RNSkLogger::logToConsole("%s: Skipped frame. Previous frame time: %lldms", + _name.c_str(), _lastDuration); + } + } + + void markSkipped() { _didSkip = true; } + + long getAverage() { return static_cast(_average); } + long getFps() { return _lastFrameCount; } + + void addLastDuration(long duration) { + _lastDuration = duration; + + // Average duration + _lastDurations[_lastDurationIndex++] = _lastDuration; + + if (_lastDurationIndex == NUMBER_OF_DURATION_SAMPLES) { + _lastDurationIndex = 0; + } + + if (_lastDurationsCount < NUMBER_OF_DURATION_SAMPLES) { + _lastDurationsCount++; + } + + _average = 0; + for (size_t i = 0; i < _lastDurationsCount; i++) { + _average = _average + _lastDurations[i]; + } + _average = _average / _lastDurationsCount; + } + +private: + void tick(std::chrono::time_point now) { + auto ms = std::chrono::duration_cast( + now.time_since_epoch()) + .count(); + + if (_prevFpsTimer == -1) { + _prevFpsTimer = ms; + } else if (ms - _prevFpsTimer >= 1000) { + _lastFrameCount = _frameCount; + _prevFpsTimer = ms; + _frameCount = 0; + } + _frameCount++; + } + + double _lastTimeStamp; + long _lastDurations[NUMBER_OF_DURATION_SAMPLES]; + int _lastDurationIndex; + int _lastDurationsCount; + long _lastDuration; + std::atomic _average; + std::chrono::time_point _start; + long _prevFpsTimer; + double _frameCount; + double _lastFrameCount; + double _didSkip; + std::string _name; +}; + +} // namespace RNSkia diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/build.gradle b/android/vendored/sdk49/react-native-gesture-handler/android/build.gradle new file mode 100644 index 00000000000000..607bb96c1595c5 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/build.gradle @@ -0,0 +1,298 @@ +import groovy.json.JsonSlurper + +import javax.inject.Inject +import java.nio.file.Files + +buildscript { + def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['RNGH_kotlinVersion'] + + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + mavenCentral() + google() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("com.android.tools.build:gradle:7.2.1") + classpath("com.diffplug.spotless:spotless-plugin-gradle:6.7.2") + } +} + +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +def resolveReactNativeDirectory() { + def reactNativeLocation = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null) + if (reactNativeLocation != null) { + return file(reactNativeLocation) + } + + // monorepo workaround + // react-native can be hoisted or in project's own node_modules + def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native") + if (reactNativeFromProjectNodeModules.exists()) { + return reactNativeFromProjectNodeModules + } + + def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native") + if (reactNativeFromNodeModulesWithReanimated.exists()) { + return reactNativeFromNodeModulesWithReanimated + } + + throw new Exception( + "[react-native-gesture-handler] Unable to resolve react-native location in " + + "node_modules. You should add project extension property (in app/build.gradle) " + + "`REACT_NATIVE_NODE_MODULES_DIR` with path to react-native." + ) +} + +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +if (project == rootProject) { + apply from: "spotless.gradle" +} + +def shouldAssertNoMultipleInstances() { + if (rootProject.hasProperty("disableMultipleInstancesCheck")) { + return rootProject.property("disableMultipleInstancesCheck") != "true" + } else { + return true + } +} + +// Check whether Reanimated 2.3 or higher is installed alongside Gesture Handler +def shouldUseCommonInterfaceFromReanimated() { + return true + + def reanimated = rootProject.subprojects.find { it.name == 'vendored_sdk49_react-native-reanimated' } + if (reanimated != null) { + def inputFile = new File(reanimated.projectDir, '../package.json') + def json = new JsonSlurper().parseText(inputFile.text) + def reanimatedVersion = json.version as String + def (major, minor, patch) = reanimatedVersion.tokenize('.') + return (Integer.parseInt(major) == 2 && Integer.parseInt(minor) >= 3) || Integer.parseInt(major) == 3 + } else { + return false + } +} + +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +def REACT_NATIVE_DIR = resolveReactNativeDirectory() + +def reactProperties = new Properties() +file("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) } + +def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME") +def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger() + + +abstract class NoMultipleInstancesAssertionTask extends DefaultTask { + @Inject abstract ObjectFactory getObjectFactory() + + @Input abstract Property getProjectDirFile() + @Input abstract Property getRootDirFile() + @Input abstract Property getShouldCheck() + + def findGestureHandlerInstancesForPath(String path) { + return objectFactory.fileTree().from(path) + .include("**/react-native-gesture-handler/package.json") + .exclude("**/.yarn/**") + .exclude({ Files.isSymbolicLink(it.getFile().toPath()) }) + .findAll() + } + + @TaskAction + def check() { + if (shouldCheck.get()) { + // Assert there are no multiple installations of Gesture Handler + Set files + + if (projectDirFile.get().parent.contains(rootDirFile.get().parent)) { + // standard app + files = findGestureHandlerInstancesForPath(rootDirFile.get().parent + "/node_modules") + } else { + // monorepo + files = findGestureHandlerInstancesForPath(rootDirFile.get().parent + "/node_modules") + files.addAll( + findGestureHandlerInstancesForPath(projectDirFile.get().parentFile.parent) + ) + } + + if (files.size() > 1) { + String parsedLocation = files.stream().map({ + File file -> "- " + file.toString().replace("/package.json", "") + }).collect().join("\n") + String exceptionMessage = "\n[react-native-gesture-handler] Multiple versions of Gesture Handler " + + "were detected. Only one instance of react-native-gesture-handler can be installed in a " + + "project. You need to resolve the conflict manually. Check out the documentation: " + + "https://docs.swmansion.com/react-native-gesture-handler/docs/troubleshooting" + + "#multiple-instances-of-gesture-handler-were-detected \n\nConflict between: \n" + + parsedLocation + "\n" + throw new GradleException(exceptionMessage) + } + } + } +} + +tasks.register('assertNoMultipleInstances', NoMultipleInstancesAssertionTask) { + shouldCheck = shouldAssertNoMultipleInstances() + rootDirFile = rootDir + projectDirFile = projectDir +} + + tasks.preBuild { + dependsOn assertNoMultipleInstances + } + +repositories { + mavenCentral() +} + +android { + compileSdkVersion safeExtGet("compileSdkVersion", 28) + def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION + if (agpVersion.tokenize('.')[0].toInteger() >= 7) { + namespace "abi49_0_0.com.swmansion.gesturehandler" + } + + // Used to override the NDK path/version on internal CI or by allowing + // users to customize the NDK path/version from their root project (e.g. for M1 support) + if (rootProject.hasProperty("ndkPath")) { + ndkPath rootProject.ext.ndkPath + } + if (rootProject.hasProperty("ndkVersion")) { + ndkVersion rootProject.ext.ndkVersion + } + + if (REACT_NATIVE_MINOR_VERSION >= 71) { + buildFeatures { + prefab true + } + } + + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', 16) + targetSdkVersion safeExtGet('targetSdkVersion', 28) + versionCode 1 + versionName "1.0" + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + buildConfigField "int", "REACT_NATIVE_MINOR_VERSION", REACT_NATIVE_MINOR_VERSION.toString() + + if (isNewArchitectureEnabled()) { + var appProject = rootProject.allprojects.find {it.plugins.hasPlugin('com.android.application')} + externalNativeBuild { + cmake { + cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-Werror", "-std=c++17", "-DANDROID" + arguments "-DAPP_BUILD_DIR=${appProject.buildDir}", + "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}", + "-DANDROID_STL=c++_shared" + abiFilters (*reactNativeArchitectures()) + } + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + if (isNewArchitectureEnabled()) { + externalNativeBuild { + cmake { + path "src/main/jni/CMakeLists.txt" + } + } + } + + packagingOptions { + // For some reason gradle only complains about the duplicated version of libreact_render libraries + // while there are more libraries copied in intermediates folder of the lib build directory, we exclude + // only the ones that make the build fail (ideally we should only include libgesturehandler but we + // are only allowed to specify exclude patterns) + exclude "**/libreact_render*.so" + } + + sourceSets.main { + java { + // Include "common/" only when it's not provided by Reanimated to mitigate + // multiple definitions of the same class preventing build + if (shouldUseCommonInterfaceFromReanimated()) { + srcDirs += 'reanimated/src/main/java' + } else { + srcDirs += 'common/src/main/java' + srcDirs += 'noreanimated/src/main/java' + } + + if (isNewArchitectureEnabled()) { + srcDirs += 'src/fabric/java' + } else { + // this folder also includes files from codegen so the library can compile with + // codegen turned off + srcDirs += 'src/paper/java' + } + } + } +} + +def kotlin_version = safeExtGet('kotlinVersion', project.properties['RNGH_kotlinVersion']) + +dependencies { + //noinspection GradleDynamicVersion + if (REACT_NATIVE_MINOR_VERSION >= 71) { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + // version substituted by RNGP + } else { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + // from node_modules + } + + if (shouldUseCommonInterfaceFromReanimated()) { + // Include Reanimated as dependency to load the common interface + implementation (rootProject.subprojects.find { it.name == 'vendored_sdk49_react-native-reanimated' }) { + exclude group:'com.facebook.fbjni' // resolves "Duplicate class com.facebook.jni.CppException" + } + } + + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "androidx.core:core-ktx:1.6.0" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/common/src/main/java/abi49_0_0/com/swmansion/common/GestureHandlerStateManager.kt b/android/vendored/sdk49/react-native-gesture-handler/android/common/src/main/java/abi49_0_0/com/swmansion/common/GestureHandlerStateManager.kt new file mode 100644 index 00000000000000..f5699fd2218502 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/common/src/main/java/abi49_0_0/com/swmansion/common/GestureHandlerStateManager.kt @@ -0,0 +1,5 @@ +package abi49_0_0.com.swmansion.common + +interface GestureHandlerStateManager { + fun setGestureHandlerState(handlerTag: Int, newState: Int) +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/noreanimated/src/main/java/abi49_0_0/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt b/android/vendored/sdk49/react-native-gesture-handler/android/noreanimated/src/main/java/abi49_0_0/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt new file mode 100644 index 00000000000000..39ca8cf0713bf0 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/noreanimated/src/main/java/abi49_0_0/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt @@ -0,0 +1,10 @@ +package abi49_0_0.com.swmansion.gesturehandler + +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.events.Event + +class ReanimatedEventDispatcher { + fun >sendEvent(event: T, reactApplicationContext: ReactContext) { + // no-op + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/reanimated/src/main/java/abi49_0_0/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt b/android/vendored/sdk49/react-native-gesture-handler/android/reanimated/src/main/java/abi49_0_0/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt new file mode 100644 index 00000000000000..61d10fe9583a2c --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/reanimated/src/main/java/abi49_0_0/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt @@ -0,0 +1,17 @@ +package abi49_0_0.com.swmansion.gesturehandler + +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.swmansion.reanimated.ReanimatedModule + +class ReanimatedEventDispatcher { + private var reanimatedModule: ReanimatedModule? = null + + fun >sendEvent(event: T, reactApplicationContext: ReactContext) { + if (reanimatedModule == null) { + reanimatedModule = reactApplicationContext.getNativeModule(ReanimatedModule::class.java) + } + + reanimatedModule?.nodesManager?.onEventDispatch(event) + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/fabric/java/abi49_0_0/com/swmansion/gesturehandler/RNGestureHandlerComponentsRegistry.java b/android/vendored/sdk49/react-native-gesture-handler/android/src/fabric/java/abi49_0_0/com/swmansion/gesturehandler/RNGestureHandlerComponentsRegistry.java new file mode 100644 index 00000000000000..c1ddbb4b303802 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/fabric/java/abi49_0_0/com/swmansion/gesturehandler/RNGestureHandlerComponentsRegistry.java @@ -0,0 +1,29 @@ +package abi49_0_0.com.swmansion.gesturehandler.react; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.fabric.ComponentFactory; +import com.facebook.soloader.SoLoader; + +@DoNotStrip +public class RNGestureHandlerComponentsRegistry { + static { + SoLoader.loadLibrary("fabricjni_abi49_0_0"); + SoLoader.loadLibrary("gesturehandler_abi49_0_0"); + } + + @DoNotStrip private final HybridData mHybridData; + + @DoNotStrip + private native HybridData initHybrid(ComponentFactory componentFactory); + + @DoNotStrip + private RNGestureHandlerComponentsRegistry(ComponentFactory componentFactory) { + mHybridData = initHybrid(componentFactory); + } + + @DoNotStrip + public static RNGestureHandlerComponentsRegistry register(ComponentFactory componentFactory) { + return new RNGestureHandlerComponentsRegistry(componentFactory); + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/fabric/java/abi49_0_0/com/swmansion/gesturehandler/ReactContextExtensions.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/fabric/java/abi49_0_0/com/swmansion/gesturehandler/ReactContextExtensions.kt new file mode 100644 index 00000000000000..58c8f20f841b9d --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/fabric/java/abi49_0_0/com/swmansion/gesturehandler/ReactContextExtensions.kt @@ -0,0 +1,12 @@ +package abi49_0_0.com.swmansion.gesturehandler + +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.fabric.FabricUIManager +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper +import abi49_0_0.com.facebook.react.uimanager.common.UIManagerType +import abi49_0_0.com.facebook.react.uimanager.events.Event + +fun ReactContext.dispatchEvent(event: Event<*>) { + val fabricUIManager = UIManagerHelper.getUIManager(this, UIManagerType.FABRIC) as FabricUIManager + fabricUIManager.eventDispatcher.dispatchEvent(event) +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..38684aa3f5f999 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt new file mode 100644 index 00000000000000..2c5cd914a99539 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/RNGestureHandlerPackage.kt @@ -0,0 +1,21 @@ +package abi49_0_0.com.swmansion.gesturehandler + +import abi49_0_0.com.facebook.react.ReactPackage +import abi49_0_0.com.facebook.react.bridge.NativeModule +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.uimanager.ViewManager +import abi49_0_0.com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager +import abi49_0_0.com.swmansion.gesturehandler.react.RNGestureHandlerModule +import abi49_0_0.com.swmansion.gesturehandler.react.RNGestureHandlerRootViewManager + +class RNGestureHandlerPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return listOf(RNGestureHandlerModule(reactContext)) + } + + override fun createViewManagers(reactContext: ReactApplicationContext) = + listOf>( + RNGestureHandlerRootViewManager(), + RNGestureHandlerButtonViewManager() + ) +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/FlingGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/FlingGestureHandler.kt new file mode 100644 index 00000000000000..3bfa48d45a45f6 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/FlingGestureHandler.kt @@ -0,0 +1,100 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.os.Handler +import android.os.Looper +import android.view.MotionEvent + +class FlingGestureHandler : GestureHandler() { + var numberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED + var direction = DEFAULT_DIRECTION + + private val maxDurationMs = DEFAULT_MAX_DURATION_MS + private val minAcceptableDelta = DEFAULT_MIN_ACCEPTABLE_DELTA + private var startX = 0f + private var startY = 0f + private var handler: Handler? = null + private var maxNumberOfPointersSimultaneously = 0 + private val failDelayed = Runnable { fail() } + + override fun resetConfig() { + super.resetConfig() + numberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED + direction = DEFAULT_DIRECTION + } + + private fun startFling(event: MotionEvent) { + startX = event.rawX + startY = event.rawY + begin() + maxNumberOfPointersSimultaneously = 1 + if (handler == null) { + handler = Handler(Looper.getMainLooper()) // lazy delegate? + } else { + handler!!.removeCallbacksAndMessages(null) + } + handler!!.postDelayed(failDelayed, maxDurationMs) + } + + private fun tryEndFling(event: MotionEvent) = if ( + maxNumberOfPointersSimultaneously == numberOfPointersRequired && + ( + direction and DIRECTION_RIGHT != 0 && + event.rawX - startX > minAcceptableDelta || + direction and DIRECTION_LEFT != 0 && + startX - event.rawX > minAcceptableDelta || + direction and DIRECTION_UP != 0 && + startY - event.rawY > minAcceptableDelta || + direction and DIRECTION_DOWN != 0 && + event.rawY - startY > minAcceptableDelta + ) + ) { + handler!!.removeCallbacksAndMessages(null) + activate() + true + } else { + false + } + + override fun activate(force: Boolean) { + super.activate(force) + end() + } + + private fun endFling(event: MotionEvent) { + if (!tryEndFling(event)) { + fail() + } + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + val state = state + if (state == STATE_UNDETERMINED) { + startFling(sourceEvent) + } + if (state == STATE_BEGAN) { + tryEndFling(sourceEvent) + if (sourceEvent.pointerCount > maxNumberOfPointersSimultaneously) { + maxNumberOfPointersSimultaneously = sourceEvent.pointerCount + } + val action = sourceEvent.actionMasked + if (action == MotionEvent.ACTION_UP) { + endFling(sourceEvent) + } + } + } + + override fun onCancel() { + handler?.removeCallbacksAndMessages(null) + } + + override fun onReset() { + handler?.removeCallbacksAndMessages(null) + } + + companion object { + private const val DEFAULT_MAX_DURATION_MS: Long = 800 + private const val DEFAULT_MIN_ACCEPTABLE_DELTA: Long = 160 + private const val DEFAULT_DIRECTION = DIRECTION_RIGHT + private const val DEFAULT_NUMBER_OF_TOUCHES_REQUIRED = 1 + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandler.kt new file mode 100644 index 00000000000000..1b46bc1a639bed --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandler.kt @@ -0,0 +1,792 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper +import android.graphics.PointF +import android.graphics.Rect +import android.view.MotionEvent +import android.view.MotionEvent.PointerCoords +import android.view.MotionEvent.PointerProperties +import android.view.View +import android.view.Window +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.facebook.react.bridge.WritableArray +import abi49_0_0.com.facebook.react.uimanager.PixelUtil +import abi49_0_0.com.swmansion.gesturehandler.BuildConfig +import abi49_0_0.com.swmansion.gesturehandler.react.RNGestureHandlerTouchEvent +import java.lang.IllegalStateException +import java.util.* + +open class GestureHandler> { + private val trackedPointerIDs = IntArray(MAX_POINTERS_COUNT) + private var trackedPointersIDsCount = 0 + private val windowOffset = IntArray(2) { 0 } + var tag = 0 + var view: View? = null + private set + var state = STATE_UNDETERMINED + private set + var x = 0f + private set + var y = 0f + private set + var isWithinBounds = false + private set + var isEnabled = true + private set + var actionType = 0 + + var changedTouchesPayload: WritableArray? = null + private set + var allTouchesPayload: WritableArray? = null + private set + var touchEventType = RNGestureHandlerTouchEvent.EVENT_UNDETERMINED + private set + var trackedPointersCount = 0 + private set + private val trackedPointers: Array = Array(MAX_POINTERS_COUNT) { null } + var needsPointerData = false + + private var hitSlop: FloatArray? = null + var eventCoalescingKey: Short = 0 + private set + var lastAbsolutePositionX = 0f + private set + var lastAbsolutePositionY = 0f + private set + + private var manualActivation = false + + private var lastEventOffsetX = 0f + private var lastEventOffsetY = 0f + private var shouldCancelWhenOutside = false + var numberOfPointers = 0 + private set + protected var orchestrator: GestureHandlerOrchestrator? = null + private var onTouchEventListener: OnTouchEventListener? = null + private var interactionController: GestureHandlerInteractionController? = null + + @Suppress("UNCHECKED_CAST") + protected fun self(): ConcreteGestureHandlerT = this as ConcreteGestureHandlerT + + protected inline fun applySelf(block: ConcreteGestureHandlerT.() -> Unit): ConcreteGestureHandlerT = + self().apply { block() } + + // properties set and accessed only by the orchestrator + var activationIndex = 0 + var isActive = false + var isAwaiting = false + var shouldResetProgress = false + + open fun dispatchStateChange(newState: Int, prevState: Int) { + onTouchEventListener?.onStateChange(self(), newState, prevState) + } + + open fun dispatchHandlerUpdate(event: MotionEvent) { + onTouchEventListener?.onHandlerUpdate(self(), event) + } + + open fun dispatchTouchEvent() { + if (changedTouchesPayload != null) { + onTouchEventListener?.onTouchEvent(self()) + } + } + + open fun resetConfig() { + needsPointerData = false + manualActivation = false + shouldCancelWhenOutside = false + isEnabled = true + hitSlop = null + } + + fun hasCommonPointers(other: GestureHandler<*>): Boolean { + for (i in trackedPointerIDs.indices) { + if (trackedPointerIDs[i] != -1 && other.trackedPointerIDs[i] != -1) { + return true + } + } + return false + } + + fun setShouldCancelWhenOutside(shouldCancelWhenOutside: Boolean): ConcreteGestureHandlerT = + applySelf { this.shouldCancelWhenOutside = shouldCancelWhenOutside } + + fun setEnabled(enabled: Boolean): ConcreteGestureHandlerT = applySelf { + // Don't cancel handler when not changing the value of the isEnabled, executing it always caused + // handlers to be cancelled on re-render because that's the moment when the config is updated. + // If the enabled prop "changed" from true to true the handler would get cancelled. + if (view != null && isEnabled != enabled) { + // If view is set then handler is in "active" state. In that case we want to "cancel" handler + // when it changes enabled state so that it gets cleared from the orchestrator + UiThreadUtil.runOnUiThread { cancel() } + } + isEnabled = enabled + } + + fun setManualActivation(manualActivation: Boolean): ConcreteGestureHandlerT = + applySelf { this.manualActivation = manualActivation } + + fun setHitSlop( + leftPad: Float, + topPad: Float, + rightPad: Float, + bottomPad: Float, + width: Float, + height: Float, + ): ConcreteGestureHandlerT = applySelf { + if (hitSlop == null) { + hitSlop = FloatArray(6) + } + hitSlop!![HIT_SLOP_LEFT_IDX] = leftPad + hitSlop!![HIT_SLOP_TOP_IDX] = topPad + hitSlop!![HIT_SLOP_RIGHT_IDX] = rightPad + hitSlop!![HIT_SLOP_BOTTOM_IDX] = bottomPad + hitSlop!![HIT_SLOP_WIDTH_IDX] = width + hitSlop!![HIT_SLOP_HEIGHT_IDX] = height + require(!(hitSlopSet(width) && hitSlopSet(leftPad) && hitSlopSet(rightPad))) { "Cannot have all of left, right and width defined" } + require(!(hitSlopSet(width) && !hitSlopSet(leftPad) && !hitSlopSet(rightPad))) { "When width is set one of left or right pads need to be defined" } + require(!(hitSlopSet(height) && hitSlopSet(bottomPad) && hitSlopSet(topPad))) { "Cannot have all of top, bottom and height defined" } + require(!(hitSlopSet(height) && !hitSlopSet(bottomPad) && !hitSlopSet(topPad))) { "When height is set one of top or bottom pads need to be defined" } + } + + fun setHitSlop(padding: Float): ConcreteGestureHandlerT { + return setHitSlop(padding, padding, padding, padding, HIT_SLOP_NONE, HIT_SLOP_NONE) + } + + fun setInteractionController(controller: GestureHandlerInteractionController?): ConcreteGestureHandlerT = + applySelf { interactionController = controller } + + fun prepare(view: View?, orchestrator: GestureHandlerOrchestrator?) { + check(!(this.view != null || this.orchestrator != null)) { "Already prepared or hasn't been reset" } + Arrays.fill(trackedPointerIDs, -1) + trackedPointersIDsCount = 0 + state = STATE_UNDETERMINED + this.view = view + this.orchestrator = orchestrator + + val decorView = getWindow(view?.context)?.decorView + if (decorView != null) { + val frame = Rect() + decorView.getWindowVisibleDisplayFrame(frame) + windowOffset[0] = frame.left + windowOffset[1] = frame.top + } else { + windowOffset[0] = 0 + windowOffset[1] = 0 + } + + onPrepare() + } + + protected open fun onPrepare() {} + + private fun getWindow(context: Context?): Window? { + if (context == null) return null + if (context is Activity) return context.window + if (context is ContextWrapper) return getWindow(context.baseContext) + + return null + } + + private fun findNextLocalPointerId(): Int { + var localPointerId = 0 + while (localPointerId < trackedPointersIDsCount) { + var i = 0 + while (i < trackedPointerIDs.size) { + if (trackedPointerIDs[i] == localPointerId) { + break + } + i++ + } + if (i == trackedPointerIDs.size) { + return localPointerId + } + localPointerId++ + } + return localPointerId + } + + fun startTrackingPointer(pointerId: Int) { + if (trackedPointerIDs[pointerId] == -1) { + trackedPointerIDs[pointerId] = findNextLocalPointerId() + trackedPointersIDsCount++ + } + } + + fun stopTrackingPointer(pointerId: Int) { + if (trackedPointerIDs[pointerId] != -1) { + trackedPointerIDs[pointerId] = -1 + trackedPointersIDsCount-- + } + } + + private fun needAdapt(event: MotionEvent): Boolean { + if (event.pointerCount != trackedPointersIDsCount) { + return true + } + + for (i in trackedPointerIDs.indices) { + val trackedPointer = trackedPointerIDs[i] + if (trackedPointer != -1 && trackedPointer != i) { + return true + } + } + return false + } + + private fun adaptEvent(event: MotionEvent): MotionEvent { + if (!needAdapt(event)) { + return event + } + var action = event.actionMasked + var actionIndex = -1 + if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) { + actionIndex = event.actionIndex + val actionPointer = event.getPointerId(actionIndex) + action = if (trackedPointerIDs[actionPointer] != -1) { + if (trackedPointersIDsCount == 1) MotionEvent.ACTION_DOWN else MotionEvent.ACTION_POINTER_DOWN + } else { + MotionEvent.ACTION_MOVE + } + } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { + actionIndex = event.actionIndex + val actionPointer = event.getPointerId(actionIndex) + action = if (trackedPointerIDs[actionPointer] != -1) { + if (trackedPointersIDsCount == 1) MotionEvent.ACTION_UP else MotionEvent.ACTION_POINTER_UP + } else { + MotionEvent.ACTION_MOVE + } + } + initPointerProps(trackedPointersIDsCount) + var count = 0 + val deltaX = event.rawX - event.x + val deltaY = event.rawY - event.y + event.offsetLocation(deltaX, deltaY) + var index = 0 + val size = event.pointerCount + while (index < size) { + val origPointerId = event.getPointerId(index) + if (trackedPointerIDs[origPointerId] != -1) { + event.getPointerProperties(index, pointerProps[count]) + pointerProps[count]!!.id = trackedPointerIDs[origPointerId] + event.getPointerCoords(index, pointerCoords[count]) + if (index == actionIndex) { + action = action or (count shl MotionEvent.ACTION_POINTER_INDEX_SHIFT) + } + count++ + } + index++ + } + + // introduced in 1.11.0, remove if crashes are not reported + if (pointerProps.isEmpty() || pointerCoords.isEmpty()) { + throw IllegalStateException("pointerCoords.size=${pointerCoords.size}, pointerProps.size=${pointerProps.size}") + } + + val result: MotionEvent + try { + result = MotionEvent.obtain( + event.downTime, + event.eventTime, + action, + count, + pointerProps, /* props are copied and hence it is safe to use static array here */ + pointerCoords, /* same applies to coords */ + event.metaState, + event.buttonState, + event.xPrecision, + event.yPrecision, + event.deviceId, + event.edgeFlags, + event.source, + event.flags + ) + } catch (e: IllegalArgumentException) { + throw AdaptEventException(this, event, e) + } + event.offsetLocation(-deltaX, -deltaY) + result.offsetLocation(-deltaX, -deltaY) + return result + } + + // exception to help debug https://github.com/software-mansion/react-native-gesture-handler/issues/1188 + class AdaptEventException( + handler: GestureHandler<*>, + event: MotionEvent, + e: IllegalArgumentException + ) : Exception( + """ + handler: ${handler::class.simpleName} + state: ${handler.state} + view: ${handler.view} + orchestrator: ${handler.orchestrator} + isEnabled: ${handler.isEnabled} + isActive: ${handler.isActive} + isAwaiting: ${handler.isAwaiting} + trackedPointersCount: ${handler.trackedPointersIDsCount} + trackedPointers: ${handler.trackedPointerIDs.joinToString(separator = ", ")} + while handling event: $event + """.trimIndent(), + e + ) + + fun handle(transformedEvent: MotionEvent, sourceEvent: MotionEvent) { + if (!isEnabled || + state == STATE_CANCELLED || + state == STATE_FAILED || + state == STATE_END || + trackedPointersIDsCount < 1 + ) { + return + } + + // a workaround for https://github.com/software-mansion/react-native-gesture-handler/issues/1188 + val (adaptedTransformedEvent, adaptedSourceEvent) = if (BuildConfig.DEBUG) { + arrayOf(adaptEvent(transformedEvent), adaptEvent(sourceEvent)) + } else { + try { + arrayOf(adaptEvent(transformedEvent), adaptEvent(sourceEvent)) + } catch (e: AdaptEventException) { + fail() + return + } + } + + x = adaptedTransformedEvent.x + y = adaptedTransformedEvent.y + numberOfPointers = adaptedTransformedEvent.pointerCount + isWithinBounds = isWithinBounds(view, x, y) + if (shouldCancelWhenOutside && !isWithinBounds) { + if (state == STATE_ACTIVE) { + cancel() + } else if (state == STATE_BEGAN) { + fail() + } + return + } + lastAbsolutePositionX = GestureUtils.getLastPointerX(adaptedTransformedEvent, true) + lastAbsolutePositionY = GestureUtils.getLastPointerY(adaptedTransformedEvent, true) + lastEventOffsetX = adaptedTransformedEvent.rawX - adaptedTransformedEvent.x + lastEventOffsetY = adaptedTransformedEvent.rawY - adaptedTransformedEvent.y + onHandle(adaptedTransformedEvent, adaptedSourceEvent) + if (adaptedTransformedEvent != transformedEvent) { + adaptedTransformedEvent.recycle() + } + if (adaptedSourceEvent != sourceEvent) { + adaptedSourceEvent.recycle() + } + } + + private fun dispatchTouchDownEvent(event: MotionEvent) { + changedTouchesPayload = null + touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_DOWN + val pointerId = event.getPointerId(event.actionIndex) + val offsetX = event.rawX - event.x + val offsetY = event.rawY - event.y + + trackedPointers[pointerId] = PointerData( + pointerId, + event.getX(event.actionIndex), + event.getY(event.actionIndex), + event.getX(event.actionIndex) + offsetX - windowOffset[0], + event.getY(event.actionIndex) + offsetY - windowOffset[1], + ) + trackedPointersCount++ + addChangedPointer(trackedPointers[pointerId]!!) + extractAllPointersData() + + dispatchTouchEvent() + } + + private fun dispatchTouchUpEvent(event: MotionEvent) { + extractAllPointersData() + changedTouchesPayload = null + touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_UP + val pointerId = event.getPointerId(event.actionIndex) + val offsetX = event.rawX - event.x + val offsetY = event.rawY - event.y + + trackedPointers[pointerId] = PointerData( + pointerId, + event.getX(event.actionIndex), + event.getY(event.actionIndex), + event.getX(event.actionIndex) + offsetX - windowOffset[0], + event.getY(event.actionIndex) + offsetY - windowOffset[1], + ) + addChangedPointer(trackedPointers[pointerId]!!) + trackedPointers[pointerId] = null + trackedPointersCount-- + + dispatchTouchEvent() + } + + private fun dispatchTouchMoveEvent(event: MotionEvent) { + changedTouchesPayload = null + touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_MOVE + val offsetX = event.rawX - event.x + val offsetY = event.rawY - event.y + var pointersAdded = 0 + + for (i in 0 until event.pointerCount) { + val pointerId = event.getPointerId(i) + val pointer = trackedPointers[pointerId] ?: continue + + if (pointer.x != event.getX(i) || pointer.y != event.getY(i)) { + pointer.x = event.getX(i) + pointer.y = event.getY(i) + pointer.absoluteX = event.getX(i) + offsetX - windowOffset[0] + pointer.absoluteY = event.getY(i) + offsetY - windowOffset[1] + + addChangedPointer(pointer) + pointersAdded++ + } + } + + // only data about pointers that have changed their position is sent, it makes no sense to send + // an empty move event (especially when this method is called during down/up event and there is + // only info about one pointer) + if (pointersAdded > 0) { + extractAllPointersData() + dispatchTouchEvent() + } + } + + fun updatePointerData(event: MotionEvent) { + if (event.actionMasked == MotionEvent.ACTION_DOWN || event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) { + dispatchTouchDownEvent(event) + dispatchTouchMoveEvent(event) + } else if (event.actionMasked == MotionEvent.ACTION_UP || event.actionMasked == MotionEvent.ACTION_POINTER_UP) { + dispatchTouchMoveEvent(event) + dispatchTouchUpEvent(event) + } else if (event.actionMasked == MotionEvent.ACTION_MOVE) { + dispatchTouchMoveEvent(event) + } + } + + private fun extractAllPointersData() { + allTouchesPayload = null + + for (pointerData in trackedPointers) { + if (pointerData != null) { + addPointerToAll(pointerData) + } + } + } + + private fun cancelPointers() { + touchEventType = RNGestureHandlerTouchEvent.EVENT_TOUCH_CANCELLED + changedTouchesPayload = null + extractAllPointersData() + + for (pointer in trackedPointers) { + pointer?.let { + addChangedPointer(it) + } + } + + trackedPointersCount = 0 + trackedPointers.fill(null) + + dispatchTouchEvent() + } + + private fun addChangedPointer(pointerData: PointerData) { + if (changedTouchesPayload == null) { + changedTouchesPayload = Arguments.createArray() + } + + changedTouchesPayload!!.pushMap(createPointerData(pointerData)) + } + + private fun addPointerToAll(pointerData: PointerData) { + if (allTouchesPayload == null) { + allTouchesPayload = Arguments.createArray() + } + + allTouchesPayload!!.pushMap(createPointerData(pointerData)) + } + + private fun createPointerData(pointerData: PointerData) = Arguments.createMap().apply { + putInt("id", pointerData.pointerId) + putDouble("x", PixelUtil.toDIPFromPixel(pointerData.x).toDouble()) + putDouble("y", PixelUtil.toDIPFromPixel(pointerData.y).toDouble()) + putDouble("absoluteX", PixelUtil.toDIPFromPixel(pointerData.absoluteX).toDouble()) + putDouble("absoluteY", PixelUtil.toDIPFromPixel(pointerData.absoluteY).toDouble()) + } + + fun consumeChangedTouchesPayload(): WritableArray? { + val result = changedTouchesPayload + changedTouchesPayload = null + return result + } + + fun consumeAllTouchesPayload(): WritableArray? { + val result = allTouchesPayload + allTouchesPayload = null + return result + } + + private fun moveToState(newState: Int) { + UiThreadUtil.assertOnUiThread() + if (state == newState) { + return + } + + // if there are tracked pointers and the gesture is about to end, send event cancelling all pointers + if (trackedPointersCount > 0 && (newState == STATE_END || newState == STATE_CANCELLED || newState == STATE_FAILED)) { + cancelPointers() + } + + val oldState = state + state = newState + if (state == STATE_ACTIVE) { + // Generate a unique coalescing-key each time the gesture-handler becomes active. All events will have + // the same coalescing-key allowing EventDispatcher to coalesce RNGestureHandlerEvents when events are + // generated faster than they can be treated by JS thread + eventCoalescingKey = nextEventCoalescingKey++ + } + orchestrator!!.onHandlerStateChange(this, newState, oldState) + onStateChange(newState, oldState) + } + + fun wantEvents(): Boolean { + return isEnabled && + state != STATE_FAILED && + state != STATE_CANCELLED && + state != STATE_END && + trackedPointersIDsCount > 0 + } + + open fun shouldRequireToWaitForFailure(handler: GestureHandler<*>): Boolean { + if (handler === this) { + return false + } + + return interactionController?.shouldRequireHandlerToWaitForFailure(this, handler) ?: false + } + + fun shouldWaitForHandlerFailure(handler: GestureHandler<*>): Boolean { + if (handler === this) { + return false + } + + return interactionController?.shouldWaitForHandlerFailure(this, handler) ?: false + } + + open fun shouldRecognizeSimultaneously(handler: GestureHandler<*>): Boolean { + if (handler === this) { + return true + } + + return interactionController?.shouldRecognizeSimultaneously(this, handler) ?: false + } + + open fun shouldBeCancelledBy(handler: GestureHandler<*>): Boolean { + if (handler === this) { + return false + } + + return interactionController?.shouldHandlerBeCancelledBy(this, handler) ?: false + } + + fun isWithinBounds(view: View?, posX: Float, posY: Float): Boolean { + var left = 0f + var top = 0f + var right = view!!.width.toFloat() + var bottom = view.height.toFloat() + hitSlop?.let { hitSlop -> + val padLeft = hitSlop[HIT_SLOP_LEFT_IDX] + val padTop = hitSlop[HIT_SLOP_TOP_IDX] + val padRight = hitSlop[HIT_SLOP_RIGHT_IDX] + val padBottom = hitSlop[HIT_SLOP_BOTTOM_IDX] + if (hitSlopSet(padLeft)) { + left -= padLeft + } + if (hitSlopSet(padTop)) { + top -= padTop + } + if (hitSlopSet(padRight)) { + right += padRight + } + if (hitSlopSet(padBottom)) { + bottom += padBottom + } + val width = hitSlop[HIT_SLOP_WIDTH_IDX] + val height = hitSlop[HIT_SLOP_HEIGHT_IDX] + if (hitSlopSet(width)) { + if (!hitSlopSet(padLeft)) { + left = right - width + } else if (!hitSlopSet(padRight)) { + right = left + width + } + } + if (hitSlopSet(height)) { + if (!hitSlopSet(padTop)) { + top = bottom - height + } else if (!hitSlopSet(padBottom)) { + bottom = top + height + } + } + } + return posX in left..right && posY in top..bottom + } + + fun cancel() { + if (state == STATE_ACTIVE || state == STATE_UNDETERMINED || state == STATE_BEGAN) { + onCancel() + moveToState(STATE_CANCELLED) + } + } + + fun fail() { + if (state == STATE_ACTIVE || state == STATE_UNDETERMINED || state == STATE_BEGAN) { + moveToState(STATE_FAILED) + } + } + + fun activate() = activate(force = false) + + open fun activate(force: Boolean) { + if ((!manualActivation || force) && (state == STATE_UNDETERMINED || state == STATE_BEGAN)) { + moveToState(STATE_ACTIVE) + } + } + + fun begin() { + if (state == STATE_UNDETERMINED) { + moveToState(STATE_BEGAN) + } + } + + fun end() { + if (state == STATE_BEGAN || state == STATE_ACTIVE) { + moveToState(STATE_END) + } + } + + // responsible for resetting the state of handler upon activation (may be called more than once + // if the handler is waiting for failure of other one) + open fun resetProgress() {} + + protected open fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + moveToState(STATE_FAILED) + } + + protected open fun onStateChange(newState: Int, previousState: Int) {} + protected open fun onReset() {} + protected open fun onCancel() {} + + /** + * Transforms a point in the coordinate space of the wrapperView (GestureHandlerRootView) to + * coordinate space of the view the gesture is attached to. + * + * If the gesture handler is not currently attached to a view, it will return (NaN, NaN). + * + * This method modifies and transforms the received point. + */ + protected fun transformPoint(point: PointF): PointF { + return orchestrator?.transformPointToViewCoords(this.view, point) ?: run { + point.x = Float.NaN + point.y = Float.NaN + point + } + } + fun reset() { + view = null + orchestrator = null + Arrays.fill(trackedPointerIDs, -1) + trackedPointersIDsCount = 0 + + trackedPointersCount = 0 + trackedPointers.fill(null) + touchEventType = RNGestureHandlerTouchEvent.EVENT_UNDETERMINED + onReset() + } + + fun setOnTouchEventListener(listener: OnTouchEventListener?): GestureHandler<*> { + onTouchEventListener = listener + return this + } + + override fun toString(): String { + val viewString = if (view == null) null else view!!.javaClass.simpleName + return this.javaClass.simpleName + "@[" + tag + "]:" + viewString + } + + val lastRelativePositionX: Float + get() = lastAbsolutePositionX + val lastRelativePositionY: Float + get() = lastAbsolutePositionY + + val lastPositionInWindowX: Float + get() = lastAbsolutePositionX + lastEventOffsetX - windowOffset[0] + val lastPositionInWindowY: Float + get() = lastAbsolutePositionY + lastEventOffsetY - windowOffset[1] + + companion object { + const val STATE_UNDETERMINED = 0 + const val STATE_FAILED = 1 + const val STATE_BEGAN = 2 + const val STATE_CANCELLED = 3 + const val STATE_ACTIVE = 4 + const val STATE_END = 5 + const val HIT_SLOP_NONE = Float.NaN + private const val HIT_SLOP_LEFT_IDX = 0 + private const val HIT_SLOP_TOP_IDX = 1 + private const val HIT_SLOP_RIGHT_IDX = 2 + private const val HIT_SLOP_BOTTOM_IDX = 3 + private const val HIT_SLOP_WIDTH_IDX = 4 + private const val HIT_SLOP_HEIGHT_IDX = 5 + const val DIRECTION_RIGHT = 1 + const val DIRECTION_LEFT = 2 + const val DIRECTION_UP = 4 + const val DIRECTION_DOWN = 8 + const val ACTION_TYPE_REANIMATED_WORKLET = 1 + const val ACTION_TYPE_NATIVE_ANIMATED_EVENT = 2 + const val ACTION_TYPE_JS_FUNCTION_OLD_API = 3 + const val ACTION_TYPE_JS_FUNCTION_NEW_API = 4 + private const val MAX_POINTERS_COUNT = 12 + private lateinit var pointerProps: Array + private lateinit var pointerCoords: Array + private fun initPointerProps(size: Int) { + var size = size + if (!Companion::pointerProps.isInitialized) { + pointerProps = arrayOfNulls(MAX_POINTERS_COUNT) + pointerCoords = arrayOfNulls(MAX_POINTERS_COUNT) + } + while (size > 0 && pointerProps[size - 1] == null) { + pointerProps[size - 1] = PointerProperties() + pointerCoords[size - 1] = PointerCoords() + size-- + } + } + + private var nextEventCoalescingKey: Short = 0 + private fun hitSlopSet(value: Float): Boolean { + return !java.lang.Float.isNaN(value) + } + + fun stateToString(state: Int): String? { + when (state) { + STATE_UNDETERMINED -> return "UNDETERMINED" + STATE_ACTIVE -> return "ACTIVE" + STATE_FAILED -> return "FAILED" + STATE_BEGAN -> return "BEGIN" + STATE_CANCELLED -> return "CANCELLED" + STATE_END -> return "END" + } + return null + } + } + + private data class PointerData( + val pointerId: Int, + var x: Float, + var y: Float, + var absoluteX: Float, + var absoluteY: Float + ) +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerInteractionController.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerInteractionController.kt new file mode 100644 index 00000000000000..7d0bdbe57774fc --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerInteractionController.kt @@ -0,0 +1,8 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +interface GestureHandlerInteractionController { + fun shouldWaitForHandlerFailure(handler: GestureHandler<*>, otherHandler: GestureHandler<*>): Boolean + fun shouldRequireHandlerToWaitForFailure(handler: GestureHandler<*>, otherHandler: GestureHandler<*>): Boolean + fun shouldRecognizeSimultaneously(handler: GestureHandler<*>, otherHandler: GestureHandler<*>): Boolean + fun shouldHandlerBeCancelledBy(handler: GestureHandler<*>, otherHandler: GestureHandler<*>): Boolean +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt new file mode 100644 index 00000000000000..b98e315e062384 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt @@ -0,0 +1,682 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.graphics.Matrix +import android.graphics.PointF +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import java.util.* + +class GestureHandlerOrchestrator( + private val wrapperView: ViewGroup, + private val handlerRegistry: GestureHandlerRegistry, + private val viewConfigHelper: ViewConfigurationHelper, +) { + /** + * Minimum alpha (value from 0 to 1) that should be set to a view so that it can be treated as a + * gesture target. E.g. if set to 0.1 then views that less than 10% opaque will be ignored when + * traversing view hierarchy and looking for gesture handlers. + */ + var minimumAlphaForTraversal = DEFAULT_MIN_ALPHA_FOR_TRAVERSAL + + private val gestureHandlers = arrayOfNulls?>(SIMULTANEOUS_GESTURE_HANDLER_LIMIT) + private val awaitingHandlers = arrayOfNulls?>(SIMULTANEOUS_GESTURE_HANDLER_LIMIT) + private val preparedHandlers = arrayOfNulls?>(SIMULTANEOUS_GESTURE_HANDLER_LIMIT) + private val handlersToCancel = arrayOfNulls?>(SIMULTANEOUS_GESTURE_HANDLER_LIMIT) + private var gestureHandlersCount = 0 + private var awaitingHandlersCount = 0 + private var isHandlingTouch = false + private var handlingChangeSemaphore = 0 + private var finishedHandlersCleanupScheduled = false + private var activationIndex = 0 + + /** + * Should be called from the view wrapper + */ + fun onTouchEvent(event: MotionEvent): Boolean { + isHandlingTouch = true + val action = event.actionMasked + if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) { + extractGestureHandlers(event) + } else if (action == MotionEvent.ACTION_CANCEL) { + cancelAll() + } + deliverEventToGestureHandlers(event) + isHandlingTouch = false + if (finishedHandlersCleanupScheduled && handlingChangeSemaphore == 0) { + cleanupFinishedHandlers() + } + return true + } + + fun getHandlersForView(view: View) = handlerRegistry.getHandlersForView(view) + + private fun scheduleFinishedHandlersCleanup() { + if (isHandlingTouch || handlingChangeSemaphore != 0) { + finishedHandlersCleanupScheduled = true + } else { + cleanupFinishedHandlers() + } + } + + private inline fun compactHandlersIf(handlers: Array?>, count: Int, predicate: (handler: GestureHandler<*>?) -> Boolean): Int { + var out = 0 + for (i in 0 until count) { + if (predicate(handlers[i])) { + handlers[out++] = handlers[i] + } + } + return out + } + + private fun cleanupFinishedHandlers() { + var shouldCleanEmptyCells = false + for (i in gestureHandlersCount - 1 downTo 0) { + val handler = gestureHandlers[i]!! + if (isFinished(handler.state) && !handler.isAwaiting) { + gestureHandlers[i] = null + shouldCleanEmptyCells = true + handler.reset() + handler.apply { + isActive = false + isAwaiting = false + activationIndex = Int.MAX_VALUE + } + } + } + if (shouldCleanEmptyCells) { + gestureHandlersCount = compactHandlersIf(gestureHandlers, gestureHandlersCount) { handler -> + handler != null + } + } + finishedHandlersCleanupScheduled = false + } + + private fun hasOtherHandlerToWaitFor(handler: GestureHandler<*>): Boolean { + for (i in 0 until gestureHandlersCount) { + val otherHandler = gestureHandlers[i]!! + if (!isFinished(otherHandler.state) && shouldHandlerWaitForOther(handler, otherHandler)) { + return true + } + } + return false + } + + private fun tryActivate(handler: GestureHandler<*>) { + // see if there is anyone else who we need to wait for + if (hasOtherHandlerToWaitFor(handler)) { + addAwaitingHandler(handler) + } else { + // we can activate handler right away + makeActive(handler) + handler.isAwaiting = false + } + } + + private fun cleanupAwaitingHandlers() { + awaitingHandlersCount = compactHandlersIf(awaitingHandlers, awaitingHandlersCount) { handler -> + handler!!.isAwaiting + } + } + + /*package*/ + fun onHandlerStateChange(handler: GestureHandler<*>, newState: Int, prevState: Int) { + handlingChangeSemaphore += 1 + if (isFinished(newState)) { + // if there were handlers awaiting completion of this handler, we can trigger active state + for (i in 0 until awaitingHandlersCount) { + val otherHandler = awaitingHandlers[i] + if (shouldHandlerWaitForOther(otherHandler!!, handler)) { + if (newState == GestureHandler.STATE_END) { + // gesture has ended, we need to kill the awaiting handler + otherHandler.cancel() + if (otherHandler.state == GestureHandler.STATE_END) { + // Handle edge case, where discrete gestures end immediately after activation thus + // their state is set to END and when the gesture they are waiting for activates they + // should be cancelled, however `cancel` was never sent as gestures were already in the END state. + // Send synthetic BEGAN -> CANCELLED to properly handle JS logic + otherHandler.dispatchStateChange( + GestureHandler.STATE_CANCELLED, + GestureHandler.STATE_BEGAN + ) + } + otherHandler.isAwaiting = false + } else { + // gesture has failed recognition, we may try activating + tryActivate(otherHandler) + } + } + } + cleanupAwaitingHandlers() + } + if (newState == GestureHandler.STATE_ACTIVE) { + tryActivate(handler) + } else if (prevState == GestureHandler.STATE_ACTIVE || prevState == GestureHandler.STATE_END) { + if (handler.isActive) { + handler.dispatchStateChange(newState, prevState) + } else if (prevState == GestureHandler.STATE_ACTIVE && (newState == GestureHandler.STATE_CANCELLED || newState == GestureHandler.STATE_FAILED)) { + // Handle edge case where handler awaiting for another one tries to activate but finishes + // before the other would not send state change event upon ending. Note that we only want + // to do this if the newState is either CANCELLED or FAILED, if it is END we still want to + // wait for the other handler to finish as in that case synthetic events will be sent by the + // makeActive method. + handler.dispatchStateChange(newState, GestureHandler.STATE_BEGAN) + } + } else if (prevState != GestureHandler.STATE_UNDETERMINED || newState != GestureHandler.STATE_CANCELLED) { + // If handler is changing state from UNDETERMINED to CANCELLED, the state change event shouldn't + // be sent. Handler hasn't yet began so it may not be initialized which results in crashes. + // If it doesn't crash, there may be some weird behavior on JS side, as `onFinalize` will be + // called without calling `onBegin` first. + handler.dispatchStateChange(newState, prevState) + } + handlingChangeSemaphore -= 1 + scheduleFinishedHandlersCleanup() + } + + private fun makeActive(handler: GestureHandler<*>) { + val currentState = handler.state + with(handler) { + isAwaiting = false + isActive = true + shouldResetProgress = true + activationIndex = this@GestureHandlerOrchestrator.activationIndex++ + } + var toCancelCount = 0 + // Cancel all handlers that are required to be cancel upon current handler's activation + for (i in 0 until gestureHandlersCount) { + val otherHandler = gestureHandlers[i]!! + if (shouldHandlerBeCancelledBy(otherHandler, handler)) { + handlersToCancel[toCancelCount++] = otherHandler + } + } + for (i in toCancelCount - 1 downTo 0) { + handlersToCancel[i]!!.cancel() + } + + // Clear all awaiting handlers waiting for the current handler to fail + for (i in awaitingHandlersCount - 1 downTo 0) { + val otherHandler = awaitingHandlers[i]!! + if (shouldHandlerBeCancelledBy(otherHandler, handler)) { + otherHandler.cancel() + otherHandler.isAwaiting = false + } + } + cleanupAwaitingHandlers() + + // Dispatch state change event if handler is no longer in the active state we should also + // trigger END state change and UNDETERMINED state change if necessary + handler.dispatchStateChange(GestureHandler.STATE_ACTIVE, GestureHandler.STATE_BEGAN) + if (currentState != GestureHandler.STATE_ACTIVE) { + handler.dispatchStateChange(GestureHandler.STATE_END, GestureHandler.STATE_ACTIVE) + if (currentState != GestureHandler.STATE_END) { + handler.dispatchStateChange(GestureHandler.STATE_UNDETERMINED, GestureHandler.STATE_END) + } + } + } + + private fun deliverEventToGestureHandlers(event: MotionEvent) { + // Copy handlers to "prepared handlers" array, because the list of active handlers can change + // as a result of state updates + val handlersCount = gestureHandlersCount + + gestureHandlers.copyInto(preparedHandlers, 0, 0, handlersCount) + // We want to deliver events to active handlers first in order of their activation (handlers + // that activated first will first get event delivered). Otherwise we deliver events in the + // order in which handlers has been added ("most direct" children goes first). Therefore we rely + // on Arrays.sort providing a stable sort (as children are registered in order in which they + // should be tested) + preparedHandlers.sortWith(handlersComparator, 0, handlersCount) + for (i in 0 until handlersCount) { + deliverEventToGestureHandler(preparedHandlers[i]!!, event) + } + } + + private fun cancelAll() { + for (i in awaitingHandlersCount - 1 downTo 0) { + awaitingHandlers[i]!!.cancel() + } + // Copy handlers to "prepared handlers" array, because the list of active handlers can change + // as a result of state updates + val handlersCount = gestureHandlersCount + for (i in 0 until handlersCount) { + preparedHandlers[i] = gestureHandlers[i] + } + for (i in handlersCount - 1 downTo 0) { + preparedHandlers[i]!!.cancel() + } + } + + private fun deliverEventToGestureHandler(handler: GestureHandler<*>, sourceEvent: MotionEvent) { + if (!isViewAttachedUnderWrapper(handler.view)) { + handler.cancel() + return + } + if (!handler.wantEvents()) { + return + } + + val action = sourceEvent.actionMasked + val event = transformEventToViewCoords(handler.view, MotionEvent.obtain(sourceEvent)) + + // Touch events are sent before the handler itself has a chance to process them, + // mainly because `onTouchesUp` shoul be send befor gesture finishes. This means that + // the first `onTouchesDown` event is sent before a gesture begins, activation in + // callback for this event causes problems because the handler doesn't have a chance + // to initialize itself with starting values of pointer (in pan this causes translation + // to be equal to the coordinates of the pointer). The simplest solution is to send + // the first `onTouchesDown` event after the handler processes it and changes state + // to `BEGAN`. + if (handler.needsPointerData && handler.state != 0) { + handler.updatePointerData(event) + } + + if (!handler.isAwaiting || action != MotionEvent.ACTION_MOVE) { + val isFirstEvent = handler.state == 0 + handler.handle(event, sourceEvent) + if (handler.isActive) { + // After handler is done waiting for other one to fail its progress should be + // reset, otherwise there may be a visible jump in values sent by the handler. + // When handler is waiting it's already activated but the `isAwaiting` flag + // prevents it from receiving touch stream. When the flag is changed, the + // difference between this event and the last one may be large enough to be + // visible in interactions based on this gesture. This makes it consistent with + // the behavior on iOS. + if (handler.shouldResetProgress) { + handler.shouldResetProgress = false + handler.resetProgress() + } + handler.dispatchHandlerUpdate(event) + } + + if (handler.needsPointerData && isFirstEvent) { + handler.updatePointerData(event) + } + + // if event was of type UP or POINTER_UP we request handler to stop tracking now that + // the event has been dispatched + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { + val pointerId = event.getPointerId(event.actionIndex) + handler.stopTrackingPointer(pointerId) + } + } + + event.recycle() + } + + /** + * isViewAttachedUnderWrapper checks whether all of parents for view related to handler + * view are attached. Since there might be an issue rarely observed when view + * has been detached and handler's state hasn't been change to canceled, failed or + * ended yet. Probably it's a result of some race condition and stopping delivering + * for this handler and changing its state to failed of end appear to be good enough solution. + */ + private fun isViewAttachedUnderWrapper(view: View?): Boolean { + if (view == null) { + return false + } + if (view === wrapperView) { + return true + } + var parent = view.parent + while (parent != null && parent !== wrapperView) { + parent = parent.parent + } + return parent === wrapperView + } + + /** + * Transforms an event in the coordinates of wrapperView into the coordinate space of the received view. + * + * This modifies and returns the same event as it receives + * + * @param view - view to which coordinate space the event should be transformed + * @param event - event to transform + */ + fun transformEventToViewCoords(view: View?, event: MotionEvent): MotionEvent { + if (view == null) { + return event + } + + val parent = view.parent as? ViewGroup + // Events are passed down to the orchestrator by the wrapperView, so they are already in the + // relevant coordinate space. We want to stop traversing the tree when we reach it. + if (parent != wrapperView) { + transformEventToViewCoords(parent, event) + } + + if (parent != null) { + val localX = event.x + parent.scrollX - view.left + val localY = event.y + parent.scrollY - view.top + event.setLocation(localX, localY) + } + + if (!view.matrix.isIdentity) { + view.matrix.invert(inverseMatrix) + event.transform(inverseMatrix) + } + + return event + } + + /** + * Transforms a point in the coordinates of wrapperView into the coordinate space of the received view. + * + * This modifies and returns the same point as it receives + * + * @param view - view to which coordinate space the point should be transformed + * @param point - point to transform + */ + fun transformPointToViewCoords(view: View?, point: PointF): PointF { + if (view == null) { + return point + } + + val parent = view.parent as? ViewGroup + // Events are passed down to the orchestrator by the wrapperView, so they are already in the + // relevant coordinate space. We want to stop traversing the tree when we reach it. + if (parent != wrapperView) { + transformPointToViewCoords(parent, point) + } + + if (parent != null) { + point.x += parent.scrollX - view.left + point.y += parent.scrollY - view.top + } + + if (!view.matrix.isIdentity) { + view.matrix.invert(inverseMatrix) + tempCoords[0] = point.x + tempCoords[1] = point.y + inverseMatrix.mapPoints(tempCoords) + point.x = tempCoords[0] + point.y = tempCoords[1] + } + + return point + } + + private fun addAwaitingHandler(handler: GestureHandler<*>) { + for (i in 0 until awaitingHandlersCount) { + if (awaitingHandlers[i] === handler) { + return + } + } + check(awaitingHandlersCount < awaitingHandlers.size) { "Too many recognizers" } + awaitingHandlers[awaitingHandlersCount++] = handler + with(handler) { + isAwaiting = true + activationIndex = this@GestureHandlerOrchestrator.activationIndex++ + } + } + + private fun recordHandlerIfNotPresent(handler: GestureHandler<*>, view: View) { + for (i in 0 until gestureHandlersCount) { + if (gestureHandlers[i] === handler) { + return + } + } + check(gestureHandlersCount < gestureHandlers.size) { "Too many recognizers" } + gestureHandlers[gestureHandlersCount++] = handler + handler.isActive = false + handler.isAwaiting = false + handler.activationIndex = Int.MAX_VALUE + handler.prepare(view, this) + } + + private fun isViewOverflowingParent(view: View): Boolean { + val parent = view.parent as? ViewGroup ?: return false + val matrix = view.matrix + val localXY = matrixTransformCoords + localXY[0] = 0f + localXY[1] = 0f + matrix.mapPoints(localXY) + val left = localXY[0] + view.left + val top = localXY[1] + view.top + + return left < 0f || left + view.width > parent.width || top < 0f || top + view.height > parent.height + } + + private fun extractAncestorHandlers(view: View, coords: FloatArray, pointerId: Int): Boolean { + var found = false + var parent = view.parent + + while (parent != null) { + if (parent is ViewGroup) { + val parentViewGroup: ViewGroup = parent + + handlerRegistry.getHandlersForView(parent)?.let { + synchronized(it) { + for (handler in it) { + if (handler.isEnabled && handler.isWithinBounds(view, coords[0], coords[1])) { + found = true + recordHandlerIfNotPresent(handler, parentViewGroup) + handler.startTrackingPointer(pointerId) + } + } + } + } + } + + parent = parent.parent + } + + return found + } + + private fun recordViewHandlersForPointer(view: View, coords: FloatArray, pointerId: Int): Boolean { + var found = false + handlerRegistry.getHandlersForView(view)?.let { + synchronized(it) { + for (handler in it) { + if (handler.isEnabled && handler.isWithinBounds(view, coords[0], coords[1])) { + recordHandlerIfNotPresent(handler, view) + handler.startTrackingPointer(pointerId) + found = true + } + } + } + } + + // if the pointer is inside the view but it overflows its parent, handlers attached to the parent + // might not have been extracted (pointer might be in a child, but may be outside parent) + if (coords[0] in 0f..view.width.toFloat() && coords[1] in 0f..view.height.toFloat() && + isViewOverflowingParent(view) && extractAncestorHandlers(view, coords, pointerId) + ) { + found = true + } + + return found + } + + private fun extractGestureHandlers(event: MotionEvent) { + val actionIndex = event.actionIndex + val pointerId = event.getPointerId(actionIndex) + tempCoords[0] = event.getX(actionIndex) + tempCoords[1] = event.getY(actionIndex) + traverseWithPointerEvents(wrapperView, tempCoords, pointerId) + extractGestureHandlers(wrapperView, tempCoords, pointerId) + } + + private fun extractGestureHandlers(viewGroup: ViewGroup, coords: FloatArray, pointerId: Int): Boolean { + val childrenCount = viewGroup.childCount + for (i in childrenCount - 1 downTo 0) { + val child = viewConfigHelper.getChildInDrawingOrderAtIndex(viewGroup, i) + if (canReceiveEvents(child)) { + val childPoint = tempPoint + transformPointToChildViewCoords(coords[0], coords[1], viewGroup, child, childPoint) + val restoreX = coords[0] + val restoreY = coords[1] + coords[0] = childPoint.x + coords[1] = childPoint.y + var found = false + if (!isClipping(child) || isTransformedTouchPointInView(coords[0], coords[1], child)) { + // we only consider the view if touch is inside the view bounds or if the view's children + // can render outside of the view bounds (overflow visible) + found = traverseWithPointerEvents(child, coords, pointerId) + } + coords[0] = restoreX + coords[1] = restoreY + if (found) { + return true + } + } + } + return false + } + + private fun traverseWithPointerEvents(view: View, coords: FloatArray, pointerId: Int): Boolean = + when (viewConfigHelper.getPointerEventsConfigForView(view)) { + PointerEventsConfig.NONE -> { + // This view and its children can't be the target + false + } + PointerEventsConfig.BOX_ONLY -> { + // This view is the target, its children don't matter + ( + recordViewHandlersForPointer(view, coords, pointerId) || + shouldHandlerlessViewBecomeTouchTarget(view, coords) + ) + } + PointerEventsConfig.BOX_NONE -> { + // This view can't be the target, but its children might + when (view) { + is ViewGroup -> { + extractGestureHandlers(view, coords, pointerId).also { found -> + // A child view is handling touch, also extract handlers attached to this view + if (found) { + recordViewHandlersForPointer(view, coords, pointerId) + } + } + } + // When has editable set to `false` getPointerEventsConfigForView returns + // `BOX_NONE` as it's `isEnabled` property is false. In this case we still want to extract + // handlers attached to the text input, as it makes sense that gestures would work on a + // non-editable TextInput. + is EditText -> { + recordViewHandlersForPointer(view, coords, pointerId) + } + else -> false + } + } + PointerEventsConfig.AUTO -> { + // Either this view or one of its children is the target + val found = if (view is ViewGroup) { + extractGestureHandlers(view, coords, pointerId) + } else false + + ( + recordViewHandlersForPointer(view, coords, pointerId) || + found || shouldHandlerlessViewBecomeTouchTarget(view, coords) + ) + } + } + + private fun canReceiveEvents(view: View) = + view.visibility == View.VISIBLE && view.alpha >= minimumAlphaForTraversal + + // if view is not a view group it is clipping, otherwise we check for `getClipChildren` flag to + // be turned on and also confirm with the ViewConfigHelper implementation + private fun isClipping(view: View) = + view !is ViewGroup || viewConfigHelper.isViewClippingChildren(view) + + companion object { + // The limit doesn't necessarily need to exists, it was just simpler to implement it that way + // it is also more allocation-wise efficient to have a fixed limit + private const val SIMULTANEOUS_GESTURE_HANDLER_LIMIT = 20 + + // Be default fully transparent views can receive touch + private const val DEFAULT_MIN_ALPHA_FOR_TRAVERSAL = 0f + private val tempPoint = PointF() + private val matrixTransformCoords = FloatArray(2) + private val inverseMatrix = Matrix() + private val tempCoords = FloatArray(2) + private val handlersComparator = Comparator?> { a, b -> + return@Comparator if (a.isActive && b.isActive || a.isAwaiting && b.isAwaiting) { + // both A and B are either active or awaiting activation, in which case we prefer one that + // has activated (or turned into "awaiting" state) earlier + Integer.signum(b.activationIndex - a.activationIndex) + } else if (a.isActive) { + -1 // only A is active + } else if (b.isActive) { + 1 // only B is active + } else if (a.isAwaiting) { + -1 // only A is awaiting, B is inactive + } else if (b.isAwaiting) { + 1 // only B is awaiting, A is inactive + } else { + 0 // both A and B are inactive, stable order matters + } + } + + private fun shouldHandlerlessViewBecomeTouchTarget(view: View, coords: FloatArray): Boolean { + // The following code is to match the iOS behavior where transparent parts of the views can + // pass touch events through them allowing sibling nodes to handle them. + + // TODO: this is not an ideal solution as we only consider ViewGroups that has no background set + // TODO: ideally we should determine the pixel color under the given coordinates and return + // false if the color is transparent + val isLeafOrTransparent = view !is ViewGroup || view.getBackground() != null + return isLeafOrTransparent && isTransformedTouchPointInView(coords[0], coords[1], view) + } + + private fun transformPointToChildViewCoords( + x: Float, + y: Float, + parent: ViewGroup, + child: View, + outLocalPoint: PointF, + ) { + var localX = x + parent.scrollX - child.left + var localY = y + parent.scrollY - child.top + val matrix = child.matrix + if (!matrix.isIdentity) { + val localXY = matrixTransformCoords + localXY[0] = localX + localXY[1] = localY + matrix.invert(inverseMatrix) + inverseMatrix.mapPoints(localXY) + localX = localXY[0] + localY = localXY[1] + } + outLocalPoint[localX] = localY + } + + private fun isTransformedTouchPointInView(x: Float, y: Float, child: View) = + x in 0f..child.width.toFloat() && y in 0f..child.height.toFloat() + + private fun shouldHandlerWaitForOther(handler: GestureHandler<*>, other: GestureHandler<*>): Boolean { + return handler !== other && ( + handler.shouldWaitForHandlerFailure(other) || + other.shouldRequireToWaitForFailure(handler) + ) + } + + private fun canRunSimultaneously(a: GestureHandler<*>, b: GestureHandler<*>) = + a === b || a.shouldRecognizeSimultaneously(b) || b.shouldRecognizeSimultaneously(a) + + private fun shouldHandlerBeCancelledBy(handler: GestureHandler<*>, other: GestureHandler<*>): Boolean { + if (!handler.hasCommonPointers(other)) { + // if two handlers share no common pointer one can never trigger cancel for the other + return false + } + if (canRunSimultaneously(handler, other)) { + // if handlers are allowed to run simultaneously, when first activates second can still remain + // in began state + return false + } + return if (handler !== other && + (handler.isAwaiting || handler.state == GestureHandler.STATE_ACTIVE) + ) { + // in every other case as long as the handler is about to be activated or already in active + // state, we delegate the decision to the implementation of GestureHandler#shouldBeCancelledBy + handler.shouldBeCancelledBy(other) + } else true + } + + private fun isFinished(state: Int) = + state == GestureHandler.STATE_CANCELLED || + state == GestureHandler.STATE_FAILED || + state == GestureHandler.STATE_END + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerRegistry.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerRegistry.kt new file mode 100644 index 00000000000000..c44b6f87d1ae44 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureHandlerRegistry.kt @@ -0,0 +1,8 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.view.View +import java.util.* + +interface GestureHandlerRegistry { + fun getHandlersForView(view: View): ArrayList>? +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureUtils.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureUtils.kt new file mode 100644 index 00000000000000..8bcbe5a71551f5 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/GestureUtils.kt @@ -0,0 +1,47 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.view.MotionEvent + +object GestureUtils { + fun getLastPointerX(event: MotionEvent, averageTouches: Boolean): Float { + val excludeIndex = if (event.actionMasked == MotionEvent.ACTION_POINTER_UP) event.actionIndex else -1 + return if (averageTouches) { + var sum = 0f + var count = 0 + for (i in 0 until event.pointerCount) { + if (i != excludeIndex) { + sum += event.getX(i) + count++ + } + } + sum / count + } else { + var lastPointerIdx = event.pointerCount - 1 + if (lastPointerIdx == excludeIndex) { + lastPointerIdx-- + } + event.getX(lastPointerIdx) + } + } + + fun getLastPointerY(event: MotionEvent, averageTouches: Boolean): Float { + val excludeIndex = if (event.actionMasked == MotionEvent.ACTION_POINTER_UP) event.actionIndex else -1 + return if (averageTouches) { + var sum = 0f + var count = 0 + for (i in 0 until event.pointerCount) { + if (i != excludeIndex) { + sum += event.getY(i) + count++ + } + } + sum / count + } else { + var lastPointerIdx = event.pointerCount - 1 + if (lastPointerIdx == excludeIndex) { + lastPointerIdx -= 1 + } + event.getY(lastPointerIdx) + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt new file mode 100644 index 00000000000000..7f85d32c9341b1 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt @@ -0,0 +1,100 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.os.SystemClock +import android.view.MotionEvent + +class LongPressGestureHandler(context: Context) : GestureHandler() { + var minDurationMs = DEFAULT_MIN_DURATION_MS + val duration: Int + get() = (previousTime - startTime).toInt() + private val defaultMaxDistSq: Float + private var maxDistSq: Float + private var startX = 0f + private var startY = 0f + private var startTime: Long = 0 + private var previousTime: Long = 0 + private var handler: Handler? = null + + init { + setShouldCancelWhenOutside(true) + + val defaultMaxDist = DEFAULT_MAX_DIST_DP * context.resources.displayMetrics.density + defaultMaxDistSq = defaultMaxDist * defaultMaxDist + maxDistSq = defaultMaxDistSq + } + + override fun resetConfig() { + super.resetConfig() + minDurationMs = DEFAULT_MIN_DURATION_MS + maxDistSq = defaultMaxDistSq + } + + fun setMaxDist(maxDist: Float): LongPressGestureHandler { + maxDistSq = maxDist * maxDist + return this + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (state == STATE_UNDETERMINED) { + previousTime = SystemClock.uptimeMillis() + startTime = previousTime + begin() + startX = sourceEvent.rawX + startY = sourceEvent.rawY + handler = Handler(Looper.getMainLooper()) + if (minDurationMs > 0) { + handler!!.postDelayed({ activate() }, minDurationMs) + } else if (minDurationMs == 0L) { + activate() + } + } + if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) { + handler?.let { + it.removeCallbacksAndMessages(null) + handler = null + } + if (state == STATE_ACTIVE) { + end() + } else { + fail() + } + } else { + // calculate distance from start + val deltaX = sourceEvent.rawX - startX + val deltaY = sourceEvent.rawY - startY + val distSq = deltaX * deltaX + deltaY * deltaY + if (distSq > maxDistSq) { + if (state == STATE_ACTIVE) { + cancel() + } else { + fail() + } + } + } + } + + override fun onStateChange(newState: Int, previousState: Int) { + handler?.let { + it.removeCallbacksAndMessages(null) + handler = null + } + } + + override fun dispatchStateChange(newState: Int, prevState: Int) { + previousTime = SystemClock.uptimeMillis() + super.dispatchStateChange(newState, prevState) + } + + override fun dispatchHandlerUpdate(event: MotionEvent) { + previousTime = SystemClock.uptimeMillis() + super.dispatchHandlerUpdate(event) + } + + companion object { + private const val DEFAULT_MIN_DURATION_MS: Long = 500 + private const val DEFAULT_MAX_DIST_DP = 10f + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ManualGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ManualGestureHandler.kt new file mode 100644 index 00000000000000..1e50ba2d085305 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ManualGestureHandler.kt @@ -0,0 +1,11 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.view.MotionEvent + +class ManualGestureHandler : GestureHandler() { + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (state == STATE_UNDETERMINED) { + begin() + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt new file mode 100644 index 00000000000000..4ac92a0d2aff3a --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt @@ -0,0 +1,250 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.os.SystemClock +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import android.view.ViewGroup +import android.widget.ScrollView +import abi49_0_0.com.facebook.react.views.swiperefresh.ReactSwipeRefreshLayout +import abi49_0_0.com.facebook.react.views.textinput.ReactEditText + +class NativeViewGestureHandler : GestureHandler() { + private var shouldActivateOnStart = false + var disallowInterruption = false + private set + + private var hook: NativeViewGestureHandlerHook = defaultHook + + init { + setShouldCancelWhenOutside(true) + } + + override fun resetConfig() { + super.resetConfig() + shouldActivateOnStart = false + disallowInterruption = false + } + + fun setShouldActivateOnStart(shouldActivateOnStart: Boolean) = apply { + this.shouldActivateOnStart = shouldActivateOnStart + } + + /** + * Set this to `true` when wrapping native components that are supposed to be an exclusive + * target for a touch stream. Like for example switch or slider component which when activated + * aren't supposed to be cancelled by scrollview or other container that may also handle touches. + */ + fun setDisallowInterruption(disallowInterruption: Boolean) = apply { + this.disallowInterruption = disallowInterruption + } + + override fun shouldRecognizeSimultaneously(handler: GestureHandler<*>): Boolean { + // if the gesture is marked by user as simultaneous with other or the hook return true + if (super.shouldRecognizeSimultaneously(handler) || hook.shouldRecognizeSimultaneously(handler)) { + return true + } + + if (handler is NativeViewGestureHandler) { + // Special case when the peer handler is also an instance of NativeViewGestureHandler: + // For the `disallowInterruption` to work correctly we need to check the property when + // accessed as a peer, because simultaneous recognizers can be set on either side of the + // connection. + if (handler.state == STATE_ACTIVE && handler.disallowInterruption) { + // other handler is active and it disallows interruption, we don't want to get into its way + return false + } + } + val canBeInterrupted = !disallowInterruption + val otherState = handler.state + return if (state == STATE_ACTIVE && otherState == STATE_ACTIVE && canBeInterrupted) { + // if both handlers are active and the current handler can be interrupted it we return `false` + // as it means the other handler has turned active and returning `true` would prevent it from + // interrupting the current handler + false + } else state == STATE_ACTIVE && canBeInterrupted && (!hook.shouldCancelRootViewGestureHandlerIfNecessary() || handler.tag > 0) + // otherwise we can only return `true` if already in an active state + } + + override fun shouldBeCancelledBy(handler: GestureHandler<*>): Boolean { + return !disallowInterruption + } + + override fun onPrepare() { + when (val view = view) { + is NativeViewGestureHandlerHook -> this.hook = view + is ReactEditText -> this.hook = EditTextHook(this, view) + is ReactSwipeRefreshLayout -> this.hook = SwipeRefreshLayoutHook(this, view) + } + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + val view = view!! + if (event.actionMasked == MotionEvent.ACTION_UP) { + view.onTouchEvent(event) + if ((state == STATE_UNDETERMINED || state == STATE_BEGAN) && view.isPressed) { + activate() + } + end() + hook.afterGestureEnd(event) + } else if (state == STATE_UNDETERMINED || state == STATE_BEGAN) { + when { + shouldActivateOnStart -> { + tryIntercept(view, event) + view.onTouchEvent(event) + activate() + } + tryIntercept(view, event) -> { + view.onTouchEvent(event) + activate() + } + hook.wantsToHandleEventBeforeActivation() -> { + hook.handleEventBeforeActivation(event) + } + state != STATE_BEGAN -> { + if (hook.canBegin()) { + begin() + } else { + cancel() + } + } + } + } else if (state == STATE_ACTIVE) { + view.onTouchEvent(event) + } + } + + override fun onCancel() { + val time = SystemClock.uptimeMillis() + val event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0f, 0f, 0).apply { + action = MotionEvent.ACTION_CANCEL + } + view!!.onTouchEvent(event) + } + + override fun onReset() { + this.hook = defaultHook + } + + companion object { + private fun tryIntercept(view: View, event: MotionEvent) = + view is ViewGroup && view.onInterceptTouchEvent(event) + + private val defaultHook = object : NativeViewGestureHandlerHook {} + } + + interface NativeViewGestureHandlerHook { + /** + * Called when gesture is in the UNDETERMINED state, shouldActivateOnStart is set to false, + * and both tryIntercept and wantsToHandleEventBeforeActivation returned false. + * + * @return Boolean value signalling whether the handler can transition to the BEGAN state. If false + * the gesture will be cancelled. + */ + fun canBegin() = true + + /** + * Called after the gesture transitions to the END state. + */ + fun afterGestureEnd(event: MotionEvent) = Unit + + /** + * @return Boolean value signalling whether the gesture can be recognized simultaneously with + * other (handler). Returning false doesn't necessarily prevent it from happening. + */ + fun shouldRecognizeSimultaneously(handler: GestureHandler<*>) = false + + /** + * shouldActivateOnStart and tryIntercept have priority over this method + * + * @return Boolean value signalling if the hook wants to handle events passed to the handler + * before it activates (after that the events are passed to the underlying view). + */ + fun wantsToHandleEventBeforeActivation() = false + + /** + * Will be called with events if wantsToHandleEventBeforeActivation returns true. + */ + fun handleEventBeforeActivation(event: MotionEvent) = Unit + + /** + * @return Boolean value indicating whether the RootViewGestureHandler should be cancelled + * by this one. + */ + fun shouldCancelRootViewGestureHandlerIfNecessary() = false + } + + private class EditTextHook( + private val handler: NativeViewGestureHandler, + private val editText: ReactEditText + ) : NativeViewGestureHandlerHook { + private var startX = 0f + private var startY = 0f + private var touchSlopSquared: Int + + init { + val vc = ViewConfiguration.get(editText.context) + touchSlopSquared = vc.scaledTouchSlop * vc.scaledTouchSlop + } + + override fun afterGestureEnd(event: MotionEvent) { + if ((event.x - startX) * (event.x - startX) + (event.y - startY) * (event.y - startY) < touchSlopSquared) { + editText.requestFocusFromJS() + } + } + + // recognize alongside every handler besides RootViewGestureHandler, which is a private inner class + // of RNGestureHandlerRootHelper so no explicit type checks, but its tag is always negative + // also if other handler is NativeViewGestureHandler then don't override the default implementation + override fun shouldRecognizeSimultaneously(handler: GestureHandler<*>) = + handler.tag > 0 && handler !is NativeViewGestureHandler + + override fun wantsToHandleEventBeforeActivation() = true + + override fun handleEventBeforeActivation(event: MotionEvent) { + handler.activate() + editText.onTouchEvent(event) + + startX = event.x + startY = event.y + } + + override fun shouldCancelRootViewGestureHandlerIfNecessary() = true + } + + private class SwipeRefreshLayoutHook( + private val handler: NativeViewGestureHandler, + private val swipeRefreshLayout: ReactSwipeRefreshLayout + ) : NativeViewGestureHandlerHook { + override fun wantsToHandleEventBeforeActivation() = true + + override fun handleEventBeforeActivation(event: MotionEvent) { + // RefreshControl from GH is set up in a way that ScrollView wrapped with it should wait for + // it to fail. This way the RefreshControl is not canceled by the scroll handler. + // The problem with this approach is that the RefreshControl handler stays active all the time + // preventing scroll from activating. + // This is a workaround to prevent it from happening. + + // First get the ScrollView under the RefreshControl, if there is none, return. + val scroll = swipeRefreshLayout.getChildAt(0) as? ScrollView ?: return + + // Then find the first NativeViewGestureHandler attached to it + val scrollHandler = handler.orchestrator + ?.getHandlersForView(scroll) + ?.first { + it is NativeViewGestureHandler + } + + // If handler was found, it's active and the ScrollView is not at the top, fail the RefreshControl + if (scrollHandler != null && scrollHandler.state == STATE_ACTIVE && scroll.scrollY > 0) { + handler.fail() + } + + // The drawback is that the smooth transition from scrolling to refreshing in a single swipe + // is impossible this way and two swipes are required: + // - one to go back to top + // - one to actually refresh + // oh well ¯\_(ツ)_/¯ + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/OnTouchEventListener.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/OnTouchEventListener.kt new file mode 100644 index 00000000000000..9c04d3c033e3f6 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/OnTouchEventListener.kt @@ -0,0 +1,9 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.view.MotionEvent + +interface OnTouchEventListener { + fun > onHandlerUpdate(handler: T, event: MotionEvent) + fun > onStateChange(handler: T, newState: Int, oldState: Int) + fun > onTouchEvent(handler: T) +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PanGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PanGestureHandler.kt new file mode 100644 index 00000000000000..35f5175614d0d8 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PanGestureHandler.kt @@ -0,0 +1,322 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.view.MotionEvent +import android.view.VelocityTracker +import android.view.ViewConfiguration +import abi49_0_0.com.swmansion.gesturehandler.core.GestureUtils.getLastPointerX +import abi49_0_0.com.swmansion.gesturehandler.core.GestureUtils.getLastPointerY + +class PanGestureHandler(context: Context?) : GestureHandler() { + var velocityX = 0f + private set + var velocityY = 0f + private set + val translationX: Float + get() = lastX - startX + offsetX + val translationY: Float + get() = lastY - startY + offsetY + + private val defaultMinDistSq: Float + private var minDistSq = MAX_VALUE_IGNORE + private var activeOffsetXStart = MIN_VALUE_IGNORE + private var activeOffsetXEnd = MAX_VALUE_IGNORE + private var failOffsetXStart = MAX_VALUE_IGNORE + private var failOffsetXEnd = MIN_VALUE_IGNORE + private var activeOffsetYStart = MIN_VALUE_IGNORE + private var activeOffsetYEnd = MAX_VALUE_IGNORE + private var failOffsetYStart = MAX_VALUE_IGNORE + private var failOffsetYEnd = MIN_VALUE_IGNORE + private var minVelocityX = MIN_VALUE_IGNORE + private var minVelocityY = MIN_VALUE_IGNORE + private var minVelocitySq = MIN_VALUE_IGNORE + private var minPointers = DEFAULT_MIN_POINTERS + private var maxPointers = DEFAULT_MAX_POINTERS + private var startX = 0f + private var startY = 0f + private var offsetX = 0f + private var offsetY = 0f + private var lastX = 0f + private var lastY = 0f + private var velocityTracker: VelocityTracker? = null + private var averageTouches = false + private var activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS + private val activateDelayed = Runnable { activate() } + private var handler: Handler? = null + + /** + * On Android when there are multiple pointers on the screen pan gestures most often just consider + * the last placed pointer. The behaviour on iOS is quite different where the x and y component + * of the pan pointer is calculated as an average out of all the pointers placed on the screen. + * + * This behaviour can be customized on android by setting averageTouches property of the handler + * object. This could be useful in particular for the usecases when we attach other handlers that + * recognizes multi-finger gestures such as rotation. In that case when we only rely on the last + * placed finger it is easier for the gesture handler to trigger when we do a rotation gesture + * because each finger when treated separately will travel some distance, whereas the average + * position of all the fingers will remain still while doing a rotation gesture. + */ + init { + val vc = ViewConfiguration.get(context!!) + val touchSlop = vc.scaledTouchSlop + defaultMinDistSq = (touchSlop * touchSlop).toFloat() + minDistSq = defaultMinDistSq + } + + override fun resetConfig() { + super.resetConfig() + activeOffsetXStart = MIN_VALUE_IGNORE + activeOffsetXEnd = MAX_VALUE_IGNORE + failOffsetXStart = MAX_VALUE_IGNORE + failOffsetXEnd = MIN_VALUE_IGNORE + activeOffsetYStart = MIN_VALUE_IGNORE + activeOffsetYEnd = MAX_VALUE_IGNORE + failOffsetYStart = MAX_VALUE_IGNORE + failOffsetYEnd = MIN_VALUE_IGNORE + minVelocityX = MIN_VALUE_IGNORE + minVelocityY = MIN_VALUE_IGNORE + minVelocitySq = MIN_VALUE_IGNORE + minDistSq = defaultMinDistSq + minPointers = DEFAULT_MIN_POINTERS + maxPointers = DEFAULT_MAX_POINTERS + activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS + averageTouches = false + } + + fun setActiveOffsetXStart(activeOffsetXStart: Float) = apply { + this.activeOffsetXStart = activeOffsetXStart + } + + fun setActiveOffsetXEnd(activeOffsetXEnd: Float) = apply { + this.activeOffsetXEnd = activeOffsetXEnd + } + + fun setFailOffsetXStart(failOffsetXStart: Float) = apply { + this.failOffsetXStart = failOffsetXStart + } + + fun setFailOffsetXEnd(failOffsetXEnd: Float) = apply { + this.failOffsetXEnd = failOffsetXEnd + } + + fun setActiveOffsetYStart(activeOffsetYStart: Float) = apply { + this.activeOffsetYStart = activeOffsetYStart + } + + fun setActiveOffsetYEnd(activeOffsetYEnd: Float) = apply { + this.activeOffsetYEnd = activeOffsetYEnd + } + + fun setFailOffsetYStart(failOffsetYStart: Float) = apply { + this.failOffsetYStart = failOffsetYStart + } + + fun setFailOffsetYEnd(failOffsetYEnd: Float) = apply { + this.failOffsetYEnd = failOffsetYEnd + } + + fun setMinDist(minDist: Float) = apply { + minDistSq = minDist * minDist + } + + fun setMinPointers(minPointers: Int) = apply { + this.minPointers = minPointers + } + + fun setMaxPointers(maxPointers: Int) = apply { + this.maxPointers = maxPointers + } + + fun setAverageTouches(averageTouches: Boolean) = apply { + this.averageTouches = averageTouches + } + + fun setActivateAfterLongPress(time: Long) = apply { + this.activateAfterLongPress = time + } + + /** + * @param minVelocity in pixels per second + */ + fun setMinVelocity(minVelocity: Float) = apply { + minVelocitySq = minVelocity * minVelocity + } + + fun setMinVelocityX(minVelocityX: Float) = apply { + this.minVelocityX = minVelocityX + } + + fun setMinVelocityY(minVelocityY: Float) = apply { + this.minVelocityY = minVelocityY + } + + private fun shouldActivate(): Boolean { + val dx = lastX - startX + offsetX + if (activeOffsetXStart != MIN_VALUE_IGNORE && dx < activeOffsetXStart) { + return true + } + if (activeOffsetXEnd != MAX_VALUE_IGNORE && dx > activeOffsetXEnd) { + return true + } + val dy = lastY - startY + offsetY + if (activeOffsetYStart != MIN_VALUE_IGNORE && dy < activeOffsetYStart) { + return true + } + if (activeOffsetYEnd != MAX_VALUE_IGNORE && dy > activeOffsetYEnd) { + return true + } + val distSq = dx * dx + dy * dy + if (minDistSq != MIN_VALUE_IGNORE && distSq >= minDistSq) { + return true + } + val vx = velocityX + if (minVelocityX != MIN_VALUE_IGNORE && + (minVelocityX < 0 && vx <= minVelocityX || minVelocityX in 0.0f..vx) + ) { + return true + } + val vy = velocityY + if (minVelocityY != MIN_VALUE_IGNORE && + (minVelocityY < 0 && vx <= minVelocityY || minVelocityY in 0.0f..vx) + ) { + return true + } + val velocitySq = vx * vx + vy * vy + return minVelocitySq != MIN_VALUE_IGNORE && velocitySq >= minVelocitySq + } + + private fun shouldFail(): Boolean { + val dx = lastX - startX + offsetX + val dy = lastY - startY + offsetY + + if (activateAfterLongPress > 0 && dx * dx + dy * dy > defaultMinDistSq) { + handler?.removeCallbacksAndMessages(null) + return true + } + if (failOffsetXStart != MAX_VALUE_IGNORE && dx < failOffsetXStart) { + return true + } + if (failOffsetXEnd != MIN_VALUE_IGNORE && dx > failOffsetXEnd) { + return true + } + if (failOffsetYStart != MAX_VALUE_IGNORE && dy < failOffsetYStart) { + return true + } + return failOffsetYEnd != MIN_VALUE_IGNORE && dy > failOffsetYEnd + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + val state = state + val action = sourceEvent.actionMasked + if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) { + // update offset if new pointer gets added or removed + offsetX += lastX - startX + offsetY += lastY - startY + + // reset starting point + lastX = getLastPointerX(sourceEvent, averageTouches) + lastY = getLastPointerY(sourceEvent, averageTouches) + startX = lastX + startY = lastY + } else { + lastX = getLastPointerX(sourceEvent, averageTouches) + lastY = getLastPointerY(sourceEvent, averageTouches) + } + if (state == STATE_UNDETERMINED && sourceEvent.pointerCount >= minPointers) { + resetProgress() + offsetX = 0f + offsetY = 0f + velocityX = 0f + velocityY = 0f + velocityTracker = VelocityTracker.obtain() + addVelocityMovement(velocityTracker, sourceEvent) + begin() + + if (activateAfterLongPress > 0) { + if (handler == null) { + handler = Handler(Looper.getMainLooper()) + } + handler!!.postDelayed(activateDelayed, activateAfterLongPress) + } + } else if (velocityTracker != null) { + addVelocityMovement(velocityTracker, sourceEvent) + velocityTracker!!.computeCurrentVelocity(1000) + velocityX = velocityTracker!!.xVelocity + velocityY = velocityTracker!!.yVelocity + } + if (action == MotionEvent.ACTION_UP) { + if (state == STATE_ACTIVE) { + end() + } else { + fail() + } + } else if (action == MotionEvent.ACTION_POINTER_DOWN && sourceEvent.pointerCount > maxPointers) { + // When new finger is placed down (POINTER_DOWN) we check if MAX_POINTERS is not exceeded + if (state == STATE_ACTIVE) { + cancel() + } else { + fail() + } + } else if (action == MotionEvent.ACTION_POINTER_UP && state == STATE_ACTIVE && sourceEvent.pointerCount < minPointers) { + // When finger is lifted up (POINTER_UP) and the number of pointers falls below MIN_POINTERS + // threshold, we only want to take an action when the handler has already activated. Otherwise + // we can still expect more fingers to be placed on screen and fulfill MIN_POINTERS criteria. + fail() + } else if (state == STATE_BEGAN) { + if (shouldFail()) { + fail() + } else if (shouldActivate()) { + activate() + } + } + } + + override fun activate(force: Boolean) { + // reset starting point if the handler has not yet activated + if (state != STATE_ACTIVE) { + resetProgress() + } + super.activate(force) + } + + override fun onCancel() { + handler?.removeCallbacksAndMessages(null) + } + + override fun onReset() { + handler?.removeCallbacksAndMessages(null) + velocityTracker?.let { + it.recycle() + velocityTracker = null + } + } + + override fun resetProgress() { + startX = lastX + startY = lastY + } + + companion object { + private const val MIN_VALUE_IGNORE = Float.MAX_VALUE + private const val MAX_VALUE_IGNORE = Float.MIN_VALUE + private const val DEFAULT_MIN_POINTERS = 1 + private const val DEFAULT_MAX_POINTERS = 10 + private const val DEFAULT_ACTIVATE_AFTER_LONG_PRESS = 0L + + /** + * This method adds movement to {@class VelocityTracker} first resetting offset of the event so + * that the velocity is calculated based on the absolute position of touch pointers. This is + * because if the underlying view moves along with the finger using relative x/y coords yields + * incorrect results. + */ + private fun addVelocityMovement(tracker: VelocityTracker?, event: MotionEvent) { + val offsetX = event.rawX - event.x + val offsetY = event.rawY - event.y + event.offsetLocation(offsetX, offsetY) + tracker!!.addMovement(event) + event.offsetLocation(-offsetX, -offsetY) + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PinchGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PinchGestureHandler.kt new file mode 100644 index 00000000000000..70b95d700d9a4f --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PinchGestureHandler.kt @@ -0,0 +1,103 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.graphics.PointF +import android.view.MotionEvent +import android.view.ViewConfiguration +import kotlin.math.abs + +class PinchGestureHandler : GestureHandler() { + var scale = 0.0 + private set + var velocity = 0.0 + private set + var focalPointX: Float = Float.NaN + private set + var focalPointY: Float = Float.NaN + private set + + private var scaleGestureDetector: ScaleGestureDetector? = null + private var startingSpan = 0f + private var spanSlop = 0f + private val gestureListener: ScaleGestureDetector.OnScaleGestureListener = object : + ScaleGestureDetector.OnScaleGestureListener { + override fun onScale(detector: ScaleGestureDetector): Boolean { + val prevScaleFactor: Double = scale + scale *= detector.scaleFactor.toDouble() + val delta = detector.timeDelta + if (delta > 0) { + velocity = (scale - prevScaleFactor) / delta + } + if (abs(startingSpan - detector.currentSpan) >= spanSlop && + state == STATE_BEGAN + ) { + activate() + } + return true + } + + init { + setShouldCancelWhenOutside(false) + } + + override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { + startingSpan = detector.currentSpan + return true + } + + override fun onScaleEnd(detector: ScaleGestureDetector) { + // ScaleGestureDetector thinks that when fingers are 27mm away that's a sufficiently good + // reason to trigger this method giving us no other choice but to ignore it completely. + } + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (state == STATE_UNDETERMINED) { + val context = view!!.context + resetProgress() + scaleGestureDetector = ScaleGestureDetector(context, gestureListener) + val configuration = ViewConfiguration.get(context) + spanSlop = configuration.scaledTouchSlop.toFloat() + + // set the focal point to the position of the first pointer as NaN causes the event not to arrive + this.focalPointX = event.x + this.focalPointY = event.y + + begin() + } + scaleGestureDetector?.onTouchEvent(sourceEvent) + scaleGestureDetector?.let { + val point = transformPoint(PointF(it.focusX, it.focusY)) + this.focalPointX = point.x + this.focalPointY = point.y + } + var activePointers = sourceEvent.pointerCount + if (sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_UP) { + activePointers -= 1 + } + if (state == STATE_ACTIVE && activePointers < 2) { + end() + } else if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) { + fail() + } + } + + override fun activate(force: Boolean) { + // reset scale if the handler has not yet activated + if (state != STATE_ACTIVE) { + resetProgress() + } + super.activate(force) + } + + override fun onReset() { + scaleGestureDetector = null + focalPointX = Float.NaN + focalPointY = Float.NaN + resetProgress() + } + + override fun resetProgress() { + velocity = 0.0 + scale = 1.0 + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PointerEventsConfig.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PointerEventsConfig.kt new file mode 100644 index 00000000000000..204b0b0144e0ef --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/PointerEventsConfig.kt @@ -0,0 +1,23 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +enum class PointerEventsConfig { + /** + * Neither the container nor its children receive events. + */ + NONE, + + /** + * Container doesn't get events but all of its children do. + */ + BOX_NONE, + + /** + * Container gets events but none of its children do. + */ + BOX_ONLY, + + /** + * Container and all of its children receive touch events (like pointerEvents is unspecified). + */ + AUTO +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/RotationGestureDetector.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/RotationGestureDetector.kt new file mode 100644 index 00000000000000..9dd257096427a5 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/RotationGestureDetector.kt @@ -0,0 +1,125 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.view.MotionEvent +import kotlin.math.atan2 + +class RotationGestureDetector(private val gestureListener: OnRotationGestureListener?) { + interface OnRotationGestureListener { + fun onRotation(detector: RotationGestureDetector): Boolean + fun onRotationBegin(detector: RotationGestureDetector): Boolean + fun onRotationEnd(detector: RotationGestureDetector) + } + + private var currentTime = 0L + private var previousTime = 0L + private var previousAngle = 0.0 + + /** + * Returns rotation in radians since the previous rotation event. + * + * @return current rotation step in radians. + */ + var rotation = 0.0 + private set + + /** + * Returns X coordinate of the rotation anchor point relative to the view that the provided motion + * event coordinates (usually relative to the view event was sent to). + * + * @return X coordinate of the rotation anchor point + */ + var anchorX = 0f + private set + + /** + * Returns Y coordinate of the rotation anchor point relative to the view that the provided motion + * event coordinates (usually relative to the view event was sent to). + * + * @return Y coordinate of the rotation anchor point + */ + var anchorY = 0f + private set + + /** + * Return the time difference in milliseconds between the previous + * accepted rotation event and the current rotation event. + * + * @return Time difference since the last rotation event in milliseconds. + */ + val timeDelta: Long + get() = currentTime - previousTime + + private var isInProgress = false + private val pointerIds = IntArray(2) + + private fun updateCurrent(event: MotionEvent) { + previousTime = currentTime + currentTime = event.eventTime + val firstPointerIndex = event.findPointerIndex(pointerIds[0]) + val secondPointerIndex = event.findPointerIndex(pointerIds[1]) + val firstPtX = event.getX(firstPointerIndex) + val firstPtY = event.getY(firstPointerIndex) + val secondPtX = event.getX(secondPointerIndex) + val secondPtY = event.getY(secondPointerIndex) + val vectorX = secondPtX - firstPtX + val vectorY = secondPtY - firstPtY + anchorX = (firstPtX + secondPtX) * 0.5f + anchorY = (firstPtY + secondPtY) * 0.5f + + // Angle diff should be positive when rotating in clockwise direction + val angle = -atan2(vectorY.toDouble(), vectorX.toDouble()) + rotation = if (previousAngle.isNaN()) { + 0.0 + } else previousAngle - angle + + previousAngle = angle + if (rotation > Math.PI) { + rotation -= Math.PI + } else if (rotation < -Math.PI) { + rotation += Math.PI + } + if (rotation > Math.PI / 2.0) { + rotation -= Math.PI + } else if (rotation < -Math.PI / 2.0) { + rotation += Math.PI + } + } + + private fun finish() { + if (isInProgress) { + isInProgress = false + gestureListener?.onRotationEnd(this) + } + } + + fun onTouchEvent(event: MotionEvent): Boolean { + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + isInProgress = false + pointerIds[0] = event.getPointerId(event.actionIndex) + pointerIds[1] = MotionEvent.INVALID_POINTER_ID + } + MotionEvent.ACTION_POINTER_DOWN -> if (!isInProgress) { + pointerIds[1] = event.getPointerId(event.actionIndex) + isInProgress = true + previousTime = event.eventTime + previousAngle = Double.NaN + updateCurrent(event) + gestureListener?.onRotationBegin(this) + } + MotionEvent.ACTION_MOVE -> if (isInProgress) { + updateCurrent(event) + gestureListener?.onRotation(this) + } + MotionEvent.ACTION_POINTER_UP -> if (isInProgress) { + val pointerId = event.getPointerId(event.actionIndex) + if (pointerId == pointerIds[0] || pointerId == pointerIds[1]) { + // One of the key pointer has been lifted up, we have to end the gesture + finish() + } + } + MotionEvent.ACTION_UP -> finish() + } + return true + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/RotationGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/RotationGestureHandler.kt new file mode 100644 index 00000000000000..afb0b34cfc0981 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/RotationGestureHandler.kt @@ -0,0 +1,93 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.graphics.PointF +import android.view.MotionEvent +import abi49_0_0.com.swmansion.gesturehandler.core.RotationGestureDetector.OnRotationGestureListener +import kotlin.math.abs + +class RotationGestureHandler : GestureHandler() { + private var rotationGestureDetector: RotationGestureDetector? = null + var rotation = 0.0 + private set + var velocity = 0.0 + private set + var anchorX: Float = Float.NaN + private set + var anchorY: Float = Float.NaN + private set + + init { + setShouldCancelWhenOutside(false) + } + + private val gestureListener: OnRotationGestureListener = object : OnRotationGestureListener { + override fun onRotation(detector: RotationGestureDetector): Boolean { + val prevRotation: Double = rotation + rotation += detector.rotation + val delta = detector.timeDelta + if (delta > 0) { + velocity = (rotation - prevRotation) / delta + } + if (abs(rotation) >= ROTATION_RECOGNITION_THRESHOLD && state == STATE_BEGAN) { + activate() + } + return true + } + + override fun onRotationBegin(detector: RotationGestureDetector) = true + + override fun onRotationEnd(detector: RotationGestureDetector) { + end() + } + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (state == STATE_UNDETERMINED) { + resetProgress() + rotationGestureDetector = RotationGestureDetector(gestureListener) + + // set the anchor to the position of the first pointer as NaN causes the event not to arrive + this.anchorX = event.x + this.anchorY = event.y + + begin() + } + rotationGestureDetector?.onTouchEvent(sourceEvent) + rotationGestureDetector?.let { + val point = transformPoint(PointF(it.anchorX, it.anchorY)) + anchorX = point.x + anchorY = point.y + } + if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) { + if (state == STATE_ACTIVE) { + end() + } else { + fail() + } + } + } + + override fun activate(force: Boolean) { + // reset rotation if the handler has not yet activated + if (state != STATE_ACTIVE) { + resetProgress() + } + super.activate(force) + } + + override fun onReset() { + rotationGestureDetector = null + anchorX = Float.NaN + anchorY = Float.NaN + resetProgress() + } + + override fun resetProgress() { + velocity = 0.0 + rotation = 0.0 + } + + companion object { + private const val ROTATION_RECOGNITION_THRESHOLD = Math.PI / 36.0 // 5 deg in radians + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ScaleGestureDetector.java b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ScaleGestureDetector.java new file mode 100644 index 00000000000000..46c56419afa744 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ScaleGestureDetector.java @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Copied from https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ScaleGestureDetector.java + * Modified line 189 to set initial min span to 0 instead of copying it from the system configuration + */ + +package abi49_0_0.com.swmansion.gesturehandler.core; + +import android.content.Context; +import android.os.Build; +import android.os.Handler; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +/** + * Detects scaling transformation gestures using the supplied {@link MotionEvent}s. + * The {@link OnScaleGestureListener} callback will notify users when a particular + * gesture event has occurred. + * + * This class should only be used with {@link MotionEvent}s reported via touch. + * + * To use this class: + *

    + *
  • Create an instance of the {@code ScaleGestureDetector} for your + * {@link View} + *
  • In the {@link View#onTouchEvent(MotionEvent)} method ensure you call + * {@link #onTouchEvent(MotionEvent)}. The methods defined in your + * callback will be executed when the events occur. + *
+ */ +public class ScaleGestureDetector { + private static final String TAG = "ScaleGestureDetector"; + + /** + * The listener for receiving notifications when gestures occur. + * If you want to listen for all the different gestures then implement + * this interface. If you only want to listen for a subset it might + * be easier to extend {@link SimpleOnScaleGestureListener}. + * + * An application will receive events in the following order: + *
    + *
  • One {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} + *
  • Zero or more {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} + *
  • One {@link OnScaleGestureListener#onScaleEnd(ScaleGestureDetector)} + *
+ */ + public interface OnScaleGestureListener { + /** + * Responds to scaling events for a gesture in progress. + * Reported by pointer motion. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return Whether or not the detector should consider this event + * as handled. If an event was not handled, the detector + * will continue to accumulate movement until an event is + * handled. This can be useful if an application, for example, + * only wants to update scaling factors if the change is + * greater than 0.01. + */ + public boolean onScale(ScaleGestureDetector detector); + + /** + * Responds to the beginning of a scaling gesture. Reported by + * new pointers going down. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return Whether or not the detector should continue recognizing + * this gesture. For example, if a gesture is beginning + * with a focal point outside of a region where it makes + * sense, onScaleBegin() may return false to ignore the + * rest of the gesture. + */ + public boolean onScaleBegin(ScaleGestureDetector detector); + + /** + * Responds to the end of a scale gesture. Reported by existing + * pointers going up. + * + * Once a scale has ended, {@link ScaleGestureDetector#getFocusX()} + * and {@link ScaleGestureDetector#getFocusY()} will return focal point + * of the pointers remaining on the screen. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + */ + public void onScaleEnd(ScaleGestureDetector detector); + } + + /** + * A convenience class to extend when you only want to listen for a subset + * of scaling-related events. This implements all methods in + * {@link OnScaleGestureListener} but does nothing. + * {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} returns + * {@code false} so that a subclass can retrieve the accumulated scale + * factor in an overridden onScaleEnd. + * {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} returns + * {@code true}. + */ + public static class SimpleOnScaleGestureListener implements OnScaleGestureListener { + + public boolean onScale(ScaleGestureDetector detector) { + return false; + } + + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + public void onScaleEnd(ScaleGestureDetector detector) { + // Intentionally empty + } + } + + private final Context mContext; + private final OnScaleGestureListener mListener; + + private float mFocusX; + private float mFocusY; + + private boolean mQuickScaleEnabled; + private boolean mStylusScaleEnabled; + + private float mCurrSpan; + private float mPrevSpan; + private float mInitialSpan; + private float mCurrSpanX; + private float mCurrSpanY; + private float mPrevSpanX; + private float mPrevSpanY; + private long mCurrTime; + private long mPrevTime; + private boolean mInProgress; + private int mSpanSlop; + private int mMinSpan; + + private final Handler mHandler; + + private float mAnchoredScaleStartX; + private float mAnchoredScaleStartY; + private int mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE; + + private static final long TOUCH_STABILIZE_TIME = 128; // ms + private static final float SCALE_FACTOR = .5f; + private static final int ANCHORED_SCALE_MODE_NONE = 0; + private static final int ANCHORED_SCALE_MODE_DOUBLE_TAP = 1; + private static final int ANCHORED_SCALE_MODE_STYLUS = 2; + + + private GestureDetector mGestureDetector; + + private boolean mEventBeforeOrAboveStartingGestureEvent; + + /** + * Creates a ScaleGestureDetector with the supplied listener. + * You may only use this constructor from a {@link android.os.Looper Looper} thread. + * + * @param context the application's context + * @param listener the listener invoked for all the callbacks, this must + * not be null. + * + * @throws NullPointerException if {@code listener} is null. + */ + public ScaleGestureDetector(Context context, OnScaleGestureListener listener) { + this(context, listener, null); + } + + /** + * Creates a ScaleGestureDetector with the supplied listener. + * @see android.os.Handler#Handler() + * + * @param context the application's context + * @param listener the listener invoked for all the callbacks, this must + * not be null. + * @param handler the handler to use for running deferred listener events. + * + * @throws NullPointerException if {@code listener} is null. + */ + public ScaleGestureDetector(Context context, OnScaleGestureListener listener, + Handler handler) { + mContext = context; + mListener = listener; + final ViewConfiguration viewConfiguration = ViewConfiguration.get(context); + mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2; + mMinSpan = 0; // set to zero, to allow for scaling when distance between fingers is small + mHandler = handler; + // Quick scale is enabled by default after JB_MR2 + final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; + if (targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR2) { + setQuickScaleEnabled(true); + } + // Stylus scale is enabled by default after LOLLIPOP_MR1 + if (targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + setStylusScaleEnabled(true); + } + } + + /** + * Accepts MotionEvents and dispatches events to a {@link OnScaleGestureListener} + * when appropriate. + * + *

Applications should pass a complete and consistent event stream to this method. + * A complete and consistent event stream involves all MotionEvents from the initial + * ACTION_DOWN to the final ACTION_UP or ACTION_CANCEL.

+ * + * @param event The event to process + * @return true if the event was processed and the detector wants to receive the + * rest of the MotionEvents in this event stream. + */ + public boolean onTouchEvent(MotionEvent event) { + mCurrTime = event.getEventTime(); + + final int action = event.getActionMasked(); + + // Forward the event to check for double tap gesture + if (mQuickScaleEnabled) { + mGestureDetector.onTouchEvent(event); + } + + final int count = event.getPointerCount(); + final boolean isStylusButtonDown = + (event.getButtonState() & MotionEvent.BUTTON_STYLUS_PRIMARY) != 0; + + final boolean anchoredScaleCancelled = + mAnchoredScaleMode == ANCHORED_SCALE_MODE_STYLUS && !isStylusButtonDown; + final boolean streamComplete = action == MotionEvent.ACTION_UP || + action == MotionEvent.ACTION_CANCEL || anchoredScaleCancelled; + + if (action == MotionEvent.ACTION_DOWN || streamComplete) { + // Reset any scale in progress with the listener. + // If it's an ACTION_DOWN we're beginning a new event stream. + // This means the app probably didn't give us all the events. Shame on it. + if (mInProgress) { + mListener.onScaleEnd(this); + mInProgress = false; + mInitialSpan = 0; + mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE; + } else if (inAnchoredScaleMode() && streamComplete) { + mInProgress = false; + mInitialSpan = 0; + mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE; + } + + if (streamComplete) { + return true; + } + } + + if (!mInProgress && mStylusScaleEnabled && !inAnchoredScaleMode() + && !streamComplete && isStylusButtonDown) { + // Start of a button scale gesture + mAnchoredScaleStartX = event.getX(); + mAnchoredScaleStartY = event.getY(); + mAnchoredScaleMode = ANCHORED_SCALE_MODE_STYLUS; + mInitialSpan = 0; + } + + final boolean configChanged = action == MotionEvent.ACTION_DOWN || + action == MotionEvent.ACTION_POINTER_UP || + action == MotionEvent.ACTION_POINTER_DOWN || anchoredScaleCancelled; + + final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP; + final int skipIndex = pointerUp ? event.getActionIndex() : -1; + + // Determine focal point + float sumX = 0, sumY = 0; + final int div = pointerUp ? count - 1 : count; + final float focusX; + final float focusY; + if (inAnchoredScaleMode()) { + // In anchored scale mode, the focal pt is always where the double tap + // or button down gesture started + focusX = mAnchoredScaleStartX; + focusY = mAnchoredScaleStartY; + if (event.getY() < focusY) { + mEventBeforeOrAboveStartingGestureEvent = true; + } else { + mEventBeforeOrAboveStartingGestureEvent = false; + } + } else { + for (int i = 0; i < count; i++) { + if (skipIndex == i) continue; + sumX += event.getX(i); + sumY += event.getY(i); + } + + focusX = sumX / div; + focusY = sumY / div; + } + + // Determine average deviation from focal point + float devSumX = 0, devSumY = 0; + for (int i = 0; i < count; i++) { + if (skipIndex == i) continue; + + // Convert the resulting diameter into a radius. + devSumX += Math.abs(event.getX(i) - focusX); + devSumY += Math.abs(event.getY(i) - focusY); + } + final float devX = devSumX / div; + final float devY = devSumY / div; + + // Span is the average distance between touch points through the focal point; + // i.e. the diameter of the circle with a radius of the average deviation from + // the focal point. + final float spanX = devX * 2; + final float spanY = devY * 2; + final float span; + if (inAnchoredScaleMode()) { + span = spanY; + } else { + span = (float) Math.hypot(spanX, spanY); + } + + // Dispatch begin/end events as needed. + // If the configuration changes, notify the app to reset its current state by beginning + // a fresh scale event stream. + final boolean wasInProgress = mInProgress; + mFocusX = focusX; + mFocusY = focusY; + if (!inAnchoredScaleMode() && mInProgress && (span < mMinSpan || configChanged)) { + mListener.onScaleEnd(this); + mInProgress = false; + mInitialSpan = span; + } + if (configChanged) { + mPrevSpanX = mCurrSpanX = spanX; + mPrevSpanY = mCurrSpanY = spanY; + mInitialSpan = mPrevSpan = mCurrSpan = span; + } + + final int minSpan = inAnchoredScaleMode() ? mSpanSlop : mMinSpan; + if (!mInProgress && span >= minSpan && + (wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) { + mPrevSpanX = mCurrSpanX = spanX; + mPrevSpanY = mCurrSpanY = spanY; + mPrevSpan = mCurrSpan = span; + mPrevTime = mCurrTime; + mInProgress = mListener.onScaleBegin(this); + } + + // Handle motion; focal point and span/scale factor are changing. + if (action == MotionEvent.ACTION_MOVE) { + mCurrSpanX = spanX; + mCurrSpanY = spanY; + mCurrSpan = span; + + boolean updatePrev = true; + + if (mInProgress) { + updatePrev = mListener.onScale(this); + } + + if (updatePrev) { + mPrevSpanX = mCurrSpanX; + mPrevSpanY = mCurrSpanY; + mPrevSpan = mCurrSpan; + mPrevTime = mCurrTime; + } + } + + return true; + } + + private boolean inAnchoredScaleMode() { + return mAnchoredScaleMode != ANCHORED_SCALE_MODE_NONE; + } + + /** + * Set whether the associated {@link OnScaleGestureListener} should receive onScale callbacks + * when the user performs a doubleTap followed by a swipe. Note that this is enabled by default + * if the app targets API 19 and newer. + * @param scales true to enable quick scaling, false to disable + */ + public void setQuickScaleEnabled(boolean scales) { + mQuickScaleEnabled = scales; + if (mQuickScaleEnabled && mGestureDetector == null) { + GestureDetector.SimpleOnGestureListener gestureListener = + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(MotionEvent e) { + // Double tap: start watching for a swipe + mAnchoredScaleStartX = e.getX(); + mAnchoredScaleStartY = e.getY(); + mAnchoredScaleMode = ANCHORED_SCALE_MODE_DOUBLE_TAP; + return true; + } + }; + mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler); + } + } + + /** + * Return whether the quick scale gesture, in which the user performs a double tap followed by a + * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}. + */ + public boolean isQuickScaleEnabled() { + return mQuickScaleEnabled; + } + + /** + * Sets whether the associates {@link OnScaleGestureListener} should receive + * onScale callbacks when the user uses a stylus and presses the button. + * Note that this is enabled by default if the app targets API 23 and newer. + * + * @param scales true to enable stylus scaling, false to disable. + */ + public void setStylusScaleEnabled(boolean scales) { + mStylusScaleEnabled = scales; + } + + /** + * Return whether the stylus scale gesture, in which the user uses a stylus and presses the + * button, should perform scaling. {@see #setStylusScaleEnabled(boolean)} + */ + public boolean isStylusScaleEnabled() { + return mStylusScaleEnabled; + } + + /** + * Returns {@code true} if a scale gesture is in progress. + */ + public boolean isInProgress() { + return mInProgress; + } + + /** + * Get the X coordinate of the current gesture's focal point. + * If a gesture is in progress, the focal point is between + * each of the pointers forming the gesture. + * + * If {@link #isInProgress()} would return false, the result of this + * function is undefined. + * + * @return X coordinate of the focal point in pixels. + */ + public float getFocusX() { + return mFocusX; + } + + /** + * Get the Y coordinate of the current gesture's focal point. + * If a gesture is in progress, the focal point is between + * each of the pointers forming the gesture. + * + * If {@link #isInProgress()} would return false, the result of this + * function is undefined. + * + * @return Y coordinate of the focal point in pixels. + */ + public float getFocusY() { + return mFocusY; + } + + /** + * Return the average distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpan() { + return mCurrSpan; + } + + /** + * Return the average X distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpanX() { + return mCurrSpanX; + } + + /** + * Return the average Y distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpanY() { + return mCurrSpanY; + } + + /** + * Return the previous average distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpan() { + return mPrevSpan; + } + + /** + * Return the previous average X distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpanX() { + return mPrevSpanX; + } + + /** + * Return the previous average Y distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpanY() { + return mPrevSpanY; + } + + /** + * Return the scaling factor from the previous scale event to the current + * event. This value is defined as + * ({@link #getCurrentSpan()} / {@link #getPreviousSpan()}). + * + * @return The current scaling factor. + */ + public float getScaleFactor() { + if (inAnchoredScaleMode()) { + // Drag is moving up; the further away from the gesture + // start, the smaller the span should be, the closer, + // the larger the span, and therefore the larger the scale + final boolean scaleUp = + (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) || + (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan)); + final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR); + return mPrevSpan <= mSpanSlop ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff); + } + return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1; + } + + /** + * Return the time difference in milliseconds between the previous + * accepted scaling event and the current scaling event. + * + * @return Time difference since the last scaling event in milliseconds. + */ + public long getTimeDelta() { + return mCurrTime - mPrevTime; + } + + /** + * Return the event time of the current event being processed. + * + * @return Current event time in milliseconds. + */ + public long getEventTime() { + return mCurrTime; + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/TapGestureHandler.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/TapGestureHandler.kt new file mode 100644 index 00000000000000..0d13f36b4bcf3f --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/TapGestureHandler.kt @@ -0,0 +1,168 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.os.Handler +import android.os.Looper +import android.view.MotionEvent +import abi49_0_0.com.swmansion.gesturehandler.core.GestureUtils.getLastPointerX +import abi49_0_0.com.swmansion.gesturehandler.core.GestureUtils.getLastPointerY +import kotlin.math.abs + +class TapGestureHandler : GestureHandler() { + private var maxDeltaX = MAX_VALUE_IGNORE + private var maxDeltaY = MAX_VALUE_IGNORE + private var maxDistSq = MAX_VALUE_IGNORE + private var maxDurationMs = DEFAULT_MAX_DURATION_MS + private var maxDelayMs = DEFAULT_MAX_DELAY_MS + private var numberOfTaps = DEFAULT_NUMBER_OF_TAPS + private var minNumberOfPointers = DEFAULT_MIN_NUMBER_OF_POINTERS + private var currentMaxNumberOfPointers = 1 + private var startX = 0f + private var startY = 0f + private var offsetX = 0f + private var offsetY = 0f + private var lastX = 0f + private var lastY = 0f + private var handler: Handler? = null + private var tapsSoFar = 0 + private val failDelayed = Runnable { fail() } + + init { + setShouldCancelWhenOutside(true) + } + + override fun resetConfig() { + super.resetConfig() + maxDeltaX = MAX_VALUE_IGNORE + maxDeltaY = MAX_VALUE_IGNORE + maxDistSq = MAX_VALUE_IGNORE + maxDurationMs = DEFAULT_MAX_DURATION_MS + maxDelayMs = DEFAULT_MAX_DELAY_MS + numberOfTaps = DEFAULT_NUMBER_OF_TAPS + minNumberOfPointers = DEFAULT_MIN_NUMBER_OF_POINTERS + } + + fun setNumberOfTaps(numberOfTaps: Int) = apply { + this.numberOfTaps = numberOfTaps + } + + fun setMaxDelayMs(maxDelayMs: Long) = apply { + this.maxDelayMs = maxDelayMs + } + + fun setMaxDurationMs(maxDurationMs: Long) = apply { + this.maxDurationMs = maxDurationMs + } + + fun setMaxDx(deltaX: Float) = apply { + maxDeltaX = deltaX + } + + fun setMaxDy(deltaY: Float) = apply { + maxDeltaY = deltaY + } + + fun setMaxDist(maxDist: Float) = apply { + maxDistSq = maxDist * maxDist + } + + fun setMinNumberOfPointers(minNumberOfPointers: Int) = apply { + this.minNumberOfPointers = minNumberOfPointers + } + + private fun startTap() { + if (handler == null) { + handler = Handler(Looper.getMainLooper()) // TODO: lazy init (handle else branch correctly) + } else { + handler!!.removeCallbacksAndMessages(null) + } + handler!!.postDelayed(failDelayed, maxDurationMs) + } + + private fun endTap() { + if (handler == null) { + handler = Handler(Looper.getMainLooper()) + } else { + handler!!.removeCallbacksAndMessages(null) + } + if (++tapsSoFar == numberOfTaps && currentMaxNumberOfPointers >= minNumberOfPointers) { + activate() + } else { + handler!!.postDelayed(failDelayed, maxDelayMs) + } + } + + private fun shouldFail(): Boolean { + val dx = lastX - startX + offsetX + if (maxDeltaX != MAX_VALUE_IGNORE && abs(dx) > maxDeltaX) { + return true + } + val dy = lastY - startY + offsetY + if (maxDeltaY != MAX_VALUE_IGNORE && abs(dy) > maxDeltaY) { + return true + } + val dist = dy * dy + dx * dx + return maxDistSq != MAX_VALUE_IGNORE && dist > maxDistSq + } + + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + val state = state + val action = sourceEvent.actionMasked + if (state == STATE_UNDETERMINED) { + offsetX = 0f + offsetY = 0f + startX = getLastPointerX(sourceEvent, true) + startY = getLastPointerY(sourceEvent, true) + } + if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) { + offsetX += lastX - startX + offsetY += lastY - startY + lastX = getLastPointerX(sourceEvent, true) + lastY = getLastPointerY(sourceEvent, true) + startX = lastX + startY = lastY + } else { + lastX = getLastPointerX(sourceEvent, true) + lastY = getLastPointerY(sourceEvent, true) + } + if (currentMaxNumberOfPointers < sourceEvent.pointerCount) { + currentMaxNumberOfPointers = sourceEvent.pointerCount + } + if (shouldFail()) { + fail() + } else if (state == STATE_UNDETERMINED) { + if (action == MotionEvent.ACTION_DOWN) { + begin() + } + startTap() + } else if (state == STATE_BEGAN) { + if (action == MotionEvent.ACTION_UP) { + endTap() + } else if (action == MotionEvent.ACTION_DOWN) { + startTap() + } + } + } + + override fun activate(force: Boolean) { + super.activate(force) + end() + } + + override fun onCancel() { + handler?.removeCallbacksAndMessages(null) + } + + override fun onReset() { + tapsSoFar = 0 + currentMaxNumberOfPointers = 0 + handler?.removeCallbacksAndMessages(null) + } + + companion object { + private const val MAX_VALUE_IGNORE = Float.MIN_VALUE + private const val DEFAULT_MAX_DURATION_MS: Long = 500 + private const val DEFAULT_MAX_DELAY_MS: Long = 200 + private const val DEFAULT_NUMBER_OF_TAPS = 1 + private const val DEFAULT_MIN_NUMBER_OF_POINTERS = 1 + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ViewConfigurationHelper.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ViewConfigurationHelper.kt new file mode 100644 index 00000000000000..80dfc77d19bc50 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/core/ViewConfigurationHelper.kt @@ -0,0 +1,10 @@ +package abi49_0_0.com.swmansion.gesturehandler.core + +import android.view.View +import android.view.ViewGroup + +interface ViewConfigurationHelper { + fun getPointerEventsConfigForView(view: View): PointerEventsConfig + fun getChildInDrawingOrderAtIndex(parent: ViewGroup, index: Int): View + fun isViewClippingChildren(view: ViewGroup): Boolean +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/Extensions.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/Extensions.kt new file mode 100644 index 00000000000000..181752d256d11d --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/Extensions.kt @@ -0,0 +1,11 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.modules.core.DeviceEventManagerModule +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule + +val ReactContext.deviceEventEmitter: DeviceEventManagerModule.RCTDeviceEventEmitter + get() = this.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + +val ReactContext.UIManager: UIManagerModule + get() = this.getNativeModule(UIManagerModule::class.java)!! diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt new file mode 100644 index 00000000000000..aacc7080e1f8cd --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt @@ -0,0 +1,392 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.annotation.SuppressLint +import android.annotation.TargetApi +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.graphics.drawable.PaintDrawable +import android.graphics.drawable.RippleDrawable +import android.graphics.drawable.ShapeDrawable +import android.graphics.drawable.shapes.RectShape +import android.os.Build +import android.util.TypedValue +import android.view.MotionEvent +import android.view.View +import android.view.View.OnClickListener +import android.view.ViewGroup +import androidx.core.view.children +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.PixelUtil +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate +import abi49_0_0.com.facebook.react.uimanager.ViewProps +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.viewmanagers.RNGestureHandlerButtonManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNGestureHandlerButtonManagerInterface +import abi49_0_0.com.swmansion.gesturehandler.core.NativeViewGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager.ButtonViewGroup + +@ReactModule(name = RNGestureHandlerButtonViewManager.REACT_CLASS) +class RNGestureHandlerButtonViewManager : ViewGroupManager(), RNGestureHandlerButtonManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = RNGestureHandlerButtonManagerDelegate(this) + } + + override fun getName() = REACT_CLASS + + public override fun createViewInstance(context: ThemedReactContext) = ButtonViewGroup(context) + + @TargetApi(Build.VERSION_CODES.M) + @ReactProp(name = "foreground") + override fun setForeground(view: ButtonViewGroup, useDrawableOnForeground: Boolean) { + view.useDrawableOnForeground = useDrawableOnForeground + } + + @ReactProp(name = "borderless") + override fun setBorderless(view: ButtonViewGroup, useBorderlessDrawable: Boolean) { + view.useBorderlessDrawable = useBorderlessDrawable + } + + @ReactProp(name = "enabled") + override fun setEnabled(view: ButtonViewGroup, enabled: Boolean) { + view.isEnabled = enabled + } + + @ReactProp(name = ViewProps.BORDER_RADIUS) + override fun setBorderRadius(view: ButtonViewGroup, borderRadius: Float) { + view.borderRadius = borderRadius + } + + @ReactProp(name = "rippleColor") + override fun setRippleColor(view: ButtonViewGroup, rippleColor: Int?) { + view.rippleColor = rippleColor + } + + @ReactProp(name = "rippleRadius") + override fun setRippleRadius(view: ButtonViewGroup, rippleRadius: Int) { + view.rippleRadius = rippleRadius + } + + @ReactProp(name = "exclusive") + override fun setExclusive(view: ButtonViewGroup, exclusive: Boolean) { + view.exclusive = exclusive + } + + @ReactProp(name = "touchSoundDisabled") + override fun setTouchSoundDisabled(view: ButtonViewGroup, touchSoundDisabled: Boolean) { + view.isSoundEffectsEnabled = !touchSoundDisabled + } + + override fun onAfterUpdateTransaction(view: ButtonViewGroup) { + view.updateBackground() + } + + override fun getDelegate(): ViewManagerDelegate? { + return mDelegate + } + + class ButtonViewGroup(context: Context?) : + ViewGroup(context), + NativeViewGestureHandler.NativeViewGestureHandlerHook { + // Using object because of handling null representing no value set. + var rippleColor: Int? = null + set(color) = withBackgroundUpdate { + field = color + } + + var rippleRadius: Int? = null + set(radius) = withBackgroundUpdate { + field = radius + } + var useDrawableOnForeground = false + set(useForeground) = withBackgroundUpdate { + field = useForeground + } + var useBorderlessDrawable = false + var borderRadius = 0f + set(radius) = withBackgroundUpdate { + field = radius * resources.displayMetrics.density + } + var exclusive = true + + private var _backgroundColor = Color.TRANSPARENT + private var needBackgroundUpdate = false + private var lastEventTime = -1L + private var lastAction = -1 + + var isTouched = false + + init { + // we attach empty click listener to trigger tap sounds (see View#performClick()) + setOnClickListener(dummyClickListener) + isClickable = true + isFocusable = true + needBackgroundUpdate = true + } + + private inline fun withBackgroundUpdate(block: () -> Unit) { + block() + needBackgroundUpdate = true + } + + override fun setBackgroundColor(color: Int) = withBackgroundUpdate { + _backgroundColor = color + } + + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { + if (super.onInterceptTouchEvent(ev)) { + return true + } + // We call `onTouchEvent` and wait until button changes state to `pressed`, if it's pressed + // we return true so that the gesture handler can activate. + onTouchEvent(ev) + return isPressed + } + + /** + * Buttons in RN are wrapped in NativeViewGestureHandler which manages + * calling onTouchEvent after activation of the handler. Problem is, in order to verify that + * underlying button implementation is interested in receiving touches we have to call onTouchEvent + * and check if button is pressed. + * + * This leads to invoking onTouchEvent twice which isn't idempotent in View - it calls OnClickListener + * and plays sound effect if OnClickListener was set. + * + * To mitigate this behavior we use lastEventTime and lastAction variables to check that we already handled + * the event in [onInterceptTouchEvent]. We assume here that different events + * will have different event times or actions. + * Events with same event time can occur on some devices for different actions. + * (e.g. move and up in one gesture; move and cancel) + * + * Reference: + * [com.swmansion.gesturehandler.NativeViewGestureHandler.onHandle] */ + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_CANCEL) { + tryFreeingResponder() + } + + val eventTime = event.eventTime + val action = event.action + // always true when lastEventTime or lastAction have default value (-1) + if (lastEventTime != eventTime || lastAction != action) { + lastEventTime = eventTime + lastAction = action + return super.onTouchEvent(event) + } + return false + } + + fun updateBackground() { + if (!needBackgroundUpdate) { + return + } + needBackgroundUpdate = false + + if (_backgroundColor == Color.TRANSPARENT) { + // reset background + background = null + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // reset foreground + foreground = null + } + + val selectable = createSelectableDrawable() + + if (borderRadius != 0f) { + // Radius-connected lines below ought to be considered + // as a temporary solution. It do not allow to set + // different radius on each corner. However, I suppose it's fairly + // fine for button-related use cases. + // Therefore it might be used as long as: + // 1. ReactViewManager is not a generic class with a possibility to handle another ViewGroup + // 2. There's no way to force native behavior of ReactViewGroup's superclass's onTouchEvent + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && selectable is RippleDrawable) { + val mask = PaintDrawable(Color.WHITE) + mask.setCornerRadius(borderRadius) + selectable.setDrawableByLayerId(android.R.id.mask, mask) + } + } + + if (useDrawableOnForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + foreground = selectable + if (_backgroundColor != Color.TRANSPARENT) { + setBackgroundColor(_backgroundColor) + } + } else if (_backgroundColor == Color.TRANSPARENT && rippleColor == null) { + background = selectable + } else { + val colorDrawable = PaintDrawable(_backgroundColor) + + if (borderRadius != 0f) { + colorDrawable.setCornerRadius(borderRadius) + } + + val layerDrawable = LayerDrawable(if (selectable != null) arrayOf(colorDrawable, selectable) else arrayOf(colorDrawable)) + background = layerDrawable + } + } + + private fun createSelectableDrawable(): Drawable? { + // TODO: remove once support for RN 0.63 is dropped, since 0.64 minSdkVersion is 21 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + context.theme.resolveAttribute(android.R.attr.selectableItemBackground, resolveOutValue, true) + @Suppress("Deprecation") + return resources.getDrawable(resolveOutValue.resourceId) + } + + // Since Android 13, alpha channel in RippleDrawable is clamped between [128, 255] + // see https://github.com/aosp-mirror/platform_frameworks_base/blob/c1bd0480261460584753508327ca8a0c6fc80758/graphics/java/android/graphics/drawable/RippleDrawable.java#L1012 + if (rippleColor == Color.TRANSPARENT && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + return null + } + + val states = arrayOf(intArrayOf(android.R.attr.state_enabled)) + val rippleRadius = rippleRadius + val colorStateList = if (rippleColor != null) { + val colors = intArrayOf(rippleColor!!) + ColorStateList(states, colors) + } else { + // if rippleColor is null, reapply the default color + context.theme.resolveAttribute(android.R.attr.colorControlHighlight, resolveOutValue, true) + val colors = intArrayOf(resolveOutValue.data) + ColorStateList(states, colors) + } + + val drawable = RippleDrawable( + colorStateList, + null, + if (useBorderlessDrawable) null else ShapeDrawable(RectShape()) + ) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && rippleRadius != null) { + drawable.radius = PixelUtil.toPixelFromDIP(rippleRadius.toFloat()).toInt() + } + + return drawable + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + // No-op + } + + override fun drawableHotspotChanged(x: Float, y: Float) { + if (touchResponder == null || touchResponder === this) { + super.drawableHotspotChanged(x, y) + } + } + + override fun canBegin(): Boolean { + val isResponder = tryGrabbingResponder() + if (isResponder) { + isTouched = true + } + return isResponder + } + + override fun afterGestureEnd(event: MotionEvent) { + tryFreeingResponder() + isTouched = false + } + + private fun tryFreeingResponder() { + if (touchResponder === this) { + touchResponder = null + soundResponder = this + } + } + + private fun tryGrabbingResponder(): Boolean { + if (isChildTouched()) { + return false + } + + if (touchResponder == null) { + touchResponder = this + return true + } + return if (exclusive) { + touchResponder === this + } else { + !(touchResponder?.exclusive ?: false) + } + } + + private fun isChildTouched(children: Sequence = this.children): Boolean { + for (child in children) { + if (child is ButtonViewGroup && (child.isTouched || child.isPressed)) { + return true + } else if (child is ViewGroup) { + if (isChildTouched(child.children)) { + return true + } + } + } + + return false + } + + override fun performClick(): Boolean { + // don't preform click when a child button is pressed (mainly to prevent sound effect of + // a parent button from playing) + return if (!isChildTouched() && soundResponder == this) { + tryFreeingResponder() + soundResponder = null + super.performClick() + } else { + false + } + } + + override fun setPressed(pressed: Boolean) { + // there is a possibility of this method being called before NativeViewGestureHandler has + // opportunity to call canStart, in that case we need to grab responder in case the gesture + // will activate + // when canStart is called eventually, tryGrabbingResponder will return true if the button + // already is a responder + if (pressed) { + if (tryGrabbingResponder()) { + soundResponder = this + } + } + + // button can be pressed alongside other button if both are non-exclusive and it doesn't have + // any pressed children (to prevent pressing the parent when children is pressed). + val canBePressedAlongsideOther = !exclusive && touchResponder?.exclusive != true && !isChildTouched() + + if (!pressed || touchResponder === this || canBePressedAlongsideOther) { + // we set pressed state only for current responder or any non-exclusive button when responder + // is null or non-exclusive, assuming it doesn't have pressed children + isTouched = pressed + super.setPressed(pressed) + } + if (!pressed && touchResponder === this) { + // if the responder is no longer pressed we release button responder + isTouched = false + } + } + + override fun dispatchDrawableHotspotChanged(x: Float, y: Float) { + // No-op + // by default Viewgroup would pass hotspot change events + } + + companion object { + var resolveOutValue = TypedValue() + var touchResponder: ButtonViewGroup? = null + var soundResponder: ButtonViewGroup? = null + var dummyClickListener = OnClickListener { } + } + } + + companion object { + const val REACT_CLASS = "RNGestureHandlerButton" + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.kt new file mode 100644 index 00000000000000..71aaa80e1bc0d2 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.kt @@ -0,0 +1,15 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.content.Context +import android.util.AttributeSet +import abi49_0_0.com.facebook.react.ReactRootView + +@Deprecated(message = "Use component instead. Check gesture handler installation instructions in documentation for more information.") +class RNGestureHandlerEnabledRootView : ReactRootView { + constructor(context: Context?) : super(context) {} + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {} + + init { + throw UnsupportedOperationException("Your application is configured to use RNGestureHandlerEnabledRootView which is no longer supported. You can see how to migrate to here: https://docs.swmansion.com/react-native-gesture-handler/docs/guides/migrating-off-rnghenabledroot") + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt new file mode 100644 index 00000000000000..ad8ae5db561981 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt @@ -0,0 +1,77 @@ +// 1. RCTEventEmitter was deprecated in favor of RCTModernEventEmitter interface +// 2. Event#init() with only viewTag was deprecated in favor of two arg c-tor +// 3. Event#receiveEvent() with 3 args was deprecated in favor of 4 args version +// ref: https://github.com/facebook/react-native/commit/2fbbdbb2ce897e8da3f471b08b93f167d566db1d +@file:Suppress("DEPRECATION") + +package abi49_0_0.com.swmansion.gesturehandler.react + +import androidx.core.util.Pools +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler + +class RNGestureHandlerEvent private constructor() : Event() { + private var extraData: WritableMap? = null + private var coalescingKey: Short = 0 + + // On the new architecture, native animated expects event names prefixed with `top` instead of `on`, + // since we know when the native animated node is the target of the event we can use the different + // event name where appropriate. + // TODO: This is a workaround not as solution, but doing this properly would require a total overhaul of + // how GH sends events (which needs to be done, but maybe wait until the RN's apis stop changing) + private var useTopPrefixedName: Boolean = false + + private fun > init( + handler: T, + dataExtractor: RNGestureHandlerEventDataExtractor?, + useNativeAnimatedName: Boolean + ) { + super.init(handler.view!!.id) + extraData = createEventData(handler, dataExtractor) + coalescingKey = handler.eventCoalescingKey + this.useTopPrefixedName = useNativeAnimatedName + } + + override fun onDispose() { + extraData = null + EVENTS_POOL.release(this) + } + + override fun getEventName() = if (useTopPrefixedName) NATIVE_ANIMATED_EVENT_NAME else EVENT_NAME + + override fun canCoalesce() = true + + override fun getCoalescingKey() = coalescingKey + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, EVENT_NAME, extraData) + } + + companion object { + const val EVENT_NAME = "onGestureHandlerEvent" + const val NATIVE_ANIMATED_EVENT_NAME = "topGestureHandlerEvent" + private const val TOUCH_EVENTS_POOL_SIZE = 7 // magic + private val EVENTS_POOL = Pools.SynchronizedPool(TOUCH_EVENTS_POOL_SIZE) + + fun > obtain( + handler: T, + dataExtractor: RNGestureHandlerEventDataExtractor?, + useTopPrefixedName: Boolean = false + ): RNGestureHandlerEvent = + (EVENTS_POOL.acquire() ?: RNGestureHandlerEvent()).apply { + init(handler, dataExtractor, useTopPrefixedName) + } + + fun > createEventData( + handler: T, + dataExtractor: RNGestureHandlerEventDataExtractor? + ): WritableMap = Arguments.createMap().apply { + dataExtractor?.extractEventData(handler, this) + putInt("handlerTag", handler.tag) + putInt("state", handler.state) + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEventDataExtractor.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEventDataExtractor.kt new file mode 100644 index 00000000000000..6c279021dde043 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerEventDataExtractor.kt @@ -0,0 +1,8 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler + +interface RNGestureHandlerEventDataExtractor> { + fun extractEventData(handler: T, eventData: WritableMap) +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerInteractionManager.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerInteractionManager.kt new file mode 100644 index 00000000000000..a406023bdb1e7f --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerInteractionManager.kt @@ -0,0 +1,67 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.util.SparseArray +import abi49_0_0.com.facebook.react.bridge.ReadableMap +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandlerInteractionController +import abi49_0_0.com.swmansion.gesturehandler.core.NativeViewGestureHandler + +class RNGestureHandlerInteractionManager : GestureHandlerInteractionController { + private val waitForRelations = SparseArray() + private val simultaneousRelations = SparseArray() + fun dropRelationsForHandlerWithTag(handlerTag: Int) { + waitForRelations.remove(handlerTag) + simultaneousRelations.remove(handlerTag) + } + + private fun convertHandlerTagsArray(config: ReadableMap, key: String): IntArray { + val array = config.getArray(key)!! + return IntArray(array.size()).also { + for (i in it.indices) { + it[i] = array.getInt(i) + } + } + } + + fun configureInteractions(handler: GestureHandler<*>, config: ReadableMap) { + handler.setInteractionController(this) + if (config.hasKey(KEY_WAIT_FOR)) { + val tags = convertHandlerTagsArray(config, KEY_WAIT_FOR) + waitForRelations.put(handler.tag, tags) + } + if (config.hasKey(KEY_SIMULTANEOUS_HANDLERS)) { + val tags = convertHandlerTagsArray(config, KEY_SIMULTANEOUS_HANDLERS) + simultaneousRelations.put(handler.tag, tags) + } + } + + override fun shouldWaitForHandlerFailure(handler: GestureHandler<*>, otherHandler: GestureHandler<*>) = + waitForRelations[handler.tag]?.any { tag -> tag == otherHandler.tag } ?: false + + override fun shouldRequireHandlerToWaitForFailure( + handler: GestureHandler<*>, + otherHandler: GestureHandler<*>, + ) = false + + override fun shouldHandlerBeCancelledBy(handler: GestureHandler<*>, otherHandler: GestureHandler<*>): Boolean { + if (otherHandler is NativeViewGestureHandler) { + return otherHandler.disallowInterruption + } + + return false + } + override fun shouldRecognizeSimultaneously( + handler: GestureHandler<*>, + otherHandler: GestureHandler<*>, + ) = simultaneousRelations[handler.tag]?.any { tag -> tag == otherHandler.tag } ?: false + + fun reset() { + waitForRelations.clear() + simultaneousRelations.clear() + } + + companion object { + private const val KEY_WAIT_FOR = "waitFor" + private const val KEY_SIMULTANEOUS_HANDLERS = "simultaneousHandlers" + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt new file mode 100644 index 00000000000000..dcafe44519f8f3 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt @@ -0,0 +1,735 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.content.Context +import android.util.Log +import android.view.MotionEvent +import abi49_0_0.com.facebook.react.ReactRootView +import abi49_0_0.com.facebook.react.bridge.JSApplicationIllegalArgumentException +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule +import abi49_0_0.com.facebook.react.bridge.ReactMethod +import abi49_0_0.com.facebook.react.bridge.ReadableMap +import abi49_0_0.com.facebook.react.bridge.ReadableType +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.PixelUtil +import abi49_0_0.com.facebook.react.uimanager.events.Event +import com.facebook.soloader.SoLoader +import abi49_0_0.com.swmansion.common.GestureHandlerStateManager +import abi49_0_0.com.swmansion.gesturehandler.BuildConfig +import abi49_0_0.com.swmansion.gesturehandler.ReanimatedEventDispatcher +import abi49_0_0.com.swmansion.gesturehandler.core.FlingGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.LongPressGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.ManualGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.NativeViewGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.OnTouchEventListener +import abi49_0_0.com.swmansion.gesturehandler.core.PanGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.PinchGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.RotationGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.TapGestureHandler +import abi49_0_0.com.swmansion.gesturehandler.dispatchEvent + +// NativeModule.onCatalystInstanceDestroy() was deprecated in favor of NativeModule.invalidate() +// ref: https://github.com/facebook/react-native/commit/18c8417290823e67e211bde241ae9dde27b72f17 + +// UIManagerModule.resolveRootTagFromReactTag() was deprecated and will be removed in the next RN release +// ref: https://github.com/facebook/react-native/commit/acbf9e18ea666b07c1224a324602a41d0a66985e +@Suppress("DEPRECATION") +@ReactModule(name = RNGestureHandlerModule.MODULE_NAME) +class RNGestureHandlerModule(reactContext: ReactApplicationContext?) : + ReactContextBaseJavaModule(reactContext), GestureHandlerStateManager { + private abstract class HandlerFactory> : RNGestureHandlerEventDataExtractor { + abstract val type: Class + abstract val name: String + abstract fun create(context: Context?): T + open fun configure(handler: T, config: ReadableMap) { + handler.resetConfig() + if (config.hasKey(KEY_SHOULD_CANCEL_WHEN_OUTSIDE)) { + handler.setShouldCancelWhenOutside(config.getBoolean(KEY_SHOULD_CANCEL_WHEN_OUTSIDE)) + } + if (config.hasKey(KEY_ENABLED)) { + handler.setEnabled(config.getBoolean(KEY_ENABLED)) + } + if (config.hasKey(KEY_HIT_SLOP)) { + handleHitSlopProperty(handler, config) + } + if (config.hasKey(KEY_NEEDS_POINTER_DATA)) { + handler.needsPointerData = config.getBoolean(KEY_NEEDS_POINTER_DATA) + } + if (config.hasKey(KEY_MANUAL_ACTIVATION)) { + handler.setManualActivation(config.getBoolean(KEY_MANUAL_ACTIVATION)) + } + } + + override fun extractEventData(handler: T, eventData: WritableMap) { + eventData.putDouble("numberOfPointers", handler.numberOfPointers.toDouble()) + } + } + + private class NativeViewGestureHandlerFactory : HandlerFactory() { + override val type = NativeViewGestureHandler::class.java + override val name = "NativeViewGestureHandler" + + override fun create(context: Context?): NativeViewGestureHandler { + return NativeViewGestureHandler() + } + + override fun configure(handler: NativeViewGestureHandler, config: ReadableMap) { + super.configure(handler, config) + if (config.hasKey(KEY_NATIVE_VIEW_SHOULD_ACTIVATE_ON_START)) { + handler.setShouldActivateOnStart( + config.getBoolean(KEY_NATIVE_VIEW_SHOULD_ACTIVATE_ON_START) + ) + } + if (config.hasKey(KEY_NATIVE_VIEW_DISALLOW_INTERRUPTION)) { + handler.setDisallowInterruption(config.getBoolean(KEY_NATIVE_VIEW_DISALLOW_INTERRUPTION)) + } + } + + override fun extractEventData(handler: NativeViewGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + eventData.putBoolean("pointerInside", handler.isWithinBounds) + } + } + + private class TapGestureHandlerFactory : HandlerFactory() { + override val type = TapGestureHandler::class.java + override val name = "TapGestureHandler" + + override fun create(context: Context?): TapGestureHandler { + return TapGestureHandler() + } + + override fun configure(handler: TapGestureHandler, config: ReadableMap) { + super.configure(handler, config) + if (config.hasKey(KEY_TAP_NUMBER_OF_TAPS)) { + handler.setNumberOfTaps(config.getInt(KEY_TAP_NUMBER_OF_TAPS)) + } + if (config.hasKey(KEY_TAP_MAX_DURATION_MS)) { + handler.setMaxDurationMs(config.getInt(KEY_TAP_MAX_DURATION_MS).toLong()) + } + if (config.hasKey(KEY_TAP_MAX_DELAY_MS)) { + handler.setMaxDelayMs(config.getInt(KEY_TAP_MAX_DELAY_MS).toLong()) + } + if (config.hasKey(KEY_TAP_MAX_DELTA_X)) { + handler.setMaxDx(PixelUtil.toPixelFromDIP(config.getDouble(KEY_TAP_MAX_DELTA_X))) + } + if (config.hasKey(KEY_TAP_MAX_DELTA_Y)) { + handler.setMaxDy(PixelUtil.toPixelFromDIP(config.getDouble(KEY_TAP_MAX_DELTA_Y))) + } + if (config.hasKey(KEY_TAP_MAX_DIST)) { + handler.setMaxDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_TAP_MAX_DIST))) + } + if (config.hasKey(KEY_TAP_MIN_POINTERS)) { + handler.setMinNumberOfPointers(config.getInt(KEY_TAP_MIN_POINTERS)) + } + } + + override fun extractEventData(handler: TapGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + with(eventData) { + putDouble("x", PixelUtil.toDIPFromPixel(handler.lastRelativePositionX).toDouble()) + putDouble("y", PixelUtil.toDIPFromPixel(handler.lastRelativePositionY).toDouble()) + putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowX).toDouble()) + putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowY).toDouble()) + } + } + } + + private class LongPressGestureHandlerFactory : HandlerFactory() { + override val type = LongPressGestureHandler::class.java + override val name = "LongPressGestureHandler" + + override fun create(context: Context?): LongPressGestureHandler { + return LongPressGestureHandler((context)!!) + } + + override fun configure(handler: LongPressGestureHandler, config: ReadableMap) { + super.configure(handler, config) + if (config.hasKey(KEY_LONG_PRESS_MIN_DURATION_MS)) { + handler.minDurationMs = config.getInt(KEY_LONG_PRESS_MIN_DURATION_MS).toLong() + } + if (config.hasKey(KEY_LONG_PRESS_MAX_DIST)) { + handler.setMaxDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_LONG_PRESS_MAX_DIST))) + } + } + + override fun extractEventData(handler: LongPressGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + with(eventData) { + putDouble("x", PixelUtil.toDIPFromPixel(handler.lastRelativePositionX).toDouble()) + putDouble("y", PixelUtil.toDIPFromPixel(handler.lastRelativePositionY).toDouble()) + putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowX).toDouble()) + putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowY).toDouble()) + putInt("duration", handler.duration) + } + } + } + + private class PanGestureHandlerFactory : HandlerFactory() { + override val type = PanGestureHandler::class.java + override val name = "PanGestureHandler" + + override fun create(context: Context?): PanGestureHandler { + return PanGestureHandler(context) + } + + override fun configure(handler: PanGestureHandler, config: ReadableMap) { + super.configure(handler, config) + var hasCustomActivationCriteria = false + if (config.hasKey(KEY_PAN_ACTIVE_OFFSET_X_START)) { + handler.setActiveOffsetXStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_X_START))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_ACTIVE_OFFSET_X_END)) { + handler.setActiveOffsetXEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_X_END))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_X_START)) { + handler.setFailOffsetXStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_X_START))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_X_END)) { + handler.setFailOffsetXEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_X_END))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_ACTIVE_OFFSET_Y_START)) { + handler.setActiveOffsetYStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_Y_START))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_ACTIVE_OFFSET_Y_END)) { + handler.setActiveOffsetYEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_ACTIVE_OFFSET_Y_END))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_Y_START)) { + handler.setFailOffsetYStart(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_Y_START))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_FAIL_OFFSET_RANGE_Y_END)) { + handler.setFailOffsetYEnd(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_FAIL_OFFSET_RANGE_Y_END))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_MIN_VELOCITY)) { + // This value is actually in DPs/ms, but we can use the same function as for converting + // from DPs to pixels as the unit we're converting is in the numerator + handler.setMinVelocity(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_VELOCITY))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_MIN_VELOCITY_X)) { + handler.setMinVelocityX(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_VELOCITY_X))) + hasCustomActivationCriteria = true + } + if (config.hasKey(KEY_PAN_MIN_VELOCITY_Y)) { + handler.setMinVelocityY(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_VELOCITY_Y))) + hasCustomActivationCriteria = true + } + + // PanGestureHandler sets minDist by default, if there are custom criteria specified we want + // to reset that setting and use provided criteria instead. + if (config.hasKey(KEY_PAN_MIN_DIST)) { + handler.setMinDist(PixelUtil.toPixelFromDIP(config.getDouble(KEY_PAN_MIN_DIST))) + } else if (hasCustomActivationCriteria) { + handler.setMinDist(Float.MAX_VALUE) + } + if (config.hasKey(KEY_PAN_MIN_POINTERS)) { + handler.setMinPointers(config.getInt(KEY_PAN_MIN_POINTERS)) + } + if (config.hasKey(KEY_PAN_MAX_POINTERS)) { + handler.setMaxPointers(config.getInt(KEY_PAN_MAX_POINTERS)) + } + if (config.hasKey(KEY_PAN_AVG_TOUCHES)) { + handler.setAverageTouches(config.getBoolean(KEY_PAN_AVG_TOUCHES)) + } + if (config.hasKey(KEY_PAN_ACTIVATE_AFTER_LONG_PRESS)) { + handler.setActivateAfterLongPress(config.getInt(KEY_PAN_ACTIVATE_AFTER_LONG_PRESS).toLong()) + } + } + + override fun extractEventData(handler: PanGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + with(eventData) { + putDouble("x", PixelUtil.toDIPFromPixel(handler.lastRelativePositionX).toDouble()) + putDouble("y", PixelUtil.toDIPFromPixel(handler.lastRelativePositionY).toDouble()) + putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowX).toDouble()) + putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowY).toDouble()) + putDouble("translationX", PixelUtil.toDIPFromPixel(handler.translationX).toDouble()) + putDouble("translationY", PixelUtil.toDIPFromPixel(handler.translationY).toDouble()) + putDouble("velocityX", PixelUtil.toDIPFromPixel(handler.velocityX).toDouble()) + putDouble("velocityY", PixelUtil.toDIPFromPixel(handler.velocityY).toDouble()) + } + } + } + + private class PinchGestureHandlerFactory : HandlerFactory() { + override val type = PinchGestureHandler::class.java + override val name = "PinchGestureHandler" + + override fun create(context: Context?): PinchGestureHandler { + return PinchGestureHandler() + } + + override fun extractEventData(handler: PinchGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + with(eventData) { + putDouble("scale", handler.scale) + putDouble("focalX", PixelUtil.toDIPFromPixel(handler.focalPointX).toDouble()) + putDouble("focalY", PixelUtil.toDIPFromPixel(handler.focalPointY).toDouble()) + putDouble("velocity", handler.velocity) + } + } + } + + private class FlingGestureHandlerFactory : HandlerFactory() { + override val type = FlingGestureHandler::class.java + override val name = "FlingGestureHandler" + + override fun create(context: Context?): FlingGestureHandler { + return FlingGestureHandler() + } + + override fun configure(handler: FlingGestureHandler, config: ReadableMap) { + super.configure(handler, config) + if (config.hasKey(KEY_NUMBER_OF_POINTERS)) { + handler.numberOfPointersRequired = config.getInt(KEY_NUMBER_OF_POINTERS) + } + if (config.hasKey(KEY_DIRECTION)) { + handler.direction = config.getInt(KEY_DIRECTION) + } + } + + override fun extractEventData(handler: FlingGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + with(eventData) { + putDouble("x", PixelUtil.toDIPFromPixel(handler.lastRelativePositionX).toDouble()) + putDouble("y", PixelUtil.toDIPFromPixel(handler.lastRelativePositionY).toDouble()) + putDouble("absoluteX", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowX).toDouble()) + putDouble("absoluteY", PixelUtil.toDIPFromPixel(handler.lastPositionInWindowY).toDouble()) + } + } + } + + private class RotationGestureHandlerFactory : HandlerFactory() { + override val type = RotationGestureHandler::class.java + override val name = "RotationGestureHandler" + + override fun create(context: Context?): RotationGestureHandler { + return RotationGestureHandler() + } + + override fun extractEventData(handler: RotationGestureHandler, eventData: WritableMap) { + super.extractEventData(handler, eventData) + with(eventData) { + putDouble("rotation", handler.rotation) + putDouble("anchorX", PixelUtil.toDIPFromPixel(handler.anchorX).toDouble()) + putDouble("anchorY", PixelUtil.toDIPFromPixel(handler.anchorY).toDouble()) + putDouble("velocity", handler.velocity) + } + } + } + + private class ManualGestureHandlerFactory : HandlerFactory() { + override val type = ManualGestureHandler::class.java + override val name = "ManualGestureHandler" + + override fun create(context: Context?): ManualGestureHandler { + return ManualGestureHandler() + } + } + + private val eventListener = object : OnTouchEventListener { + override fun > onHandlerUpdate(handler: T, event: MotionEvent) { + this@RNGestureHandlerModule.onHandlerUpdate(handler) + } + + override fun > onStateChange(handler: T, newState: Int, oldState: Int) { + this@RNGestureHandlerModule.onStateChange(handler, newState, oldState) + } + + override fun > onTouchEvent(handler: T) { + this@RNGestureHandlerModule.onTouchEvent(handler) + } + } + private val handlerFactories = arrayOf>( + NativeViewGestureHandlerFactory(), + TapGestureHandlerFactory(), + LongPressGestureHandlerFactory(), + PanGestureHandlerFactory(), + PinchGestureHandlerFactory(), + RotationGestureHandlerFactory(), + FlingGestureHandlerFactory(), + ManualGestureHandlerFactory(), + ) + val registry: RNGestureHandlerRegistry = RNGestureHandlerRegistry() + private val interactionManager = RNGestureHandlerInteractionManager() + private val roots: MutableList = ArrayList() + private val reanimatedEventDispatcher = ReanimatedEventDispatcher() + override fun getName() = MODULE_NAME + + @ReactMethod + @Suppress("UNCHECKED_CAST") + fun > createGestureHandler( + handlerName: String, + handlerTag: Int, + config: ReadableMap, + ) { + for (handlerFactory in handlerFactories as Array>) { + if (handlerFactory.name == handlerName) { + val handler = handlerFactory.create(reactApplicationContext).apply { + tag = handlerTag + setOnTouchEventListener(eventListener) + } + registry.registerHandler(handler) + interactionManager.configureInteractions(handler, config) + handlerFactory.configure(handler, config) + return + } + } + throw JSApplicationIllegalArgumentException("Invalid handler name $handlerName") + } + + @ReactMethod + fun attachGestureHandler(handlerTag: Int, viewTag: Int, actionType: Int) { + // We don't have to handle view flattening in any special way since handlers are stored as + // a map: viewTag -> [handler]. If the view with attached handlers was to be flattened + // then that viewTag simply wouldn't be visited when traversing the view hierarchy in the + // Orchestrator effectively ignoring all handlers attached to flattened views. + if (!registry.attachHandlerToView(handlerTag, viewTag, actionType)) { + throw JSApplicationIllegalArgumentException("Handler with tag $handlerTag does not exists") + } + } + + @ReactMethod + @Suppress("UNCHECKED_CAST") + fun > updateGestureHandler(handlerTag: Int, config: ReadableMap) { + val handler = registry.getHandler(handlerTag) as T? + if (handler != null) { + val factory = findFactoryForHandler(handler) + if (factory != null) { + interactionManager.dropRelationsForHandlerWithTag(handlerTag) + interactionManager.configureInteractions(handler, config) + factory.configure(handler, config) + } + } + } + + @ReactMethod + fun dropGestureHandler(handlerTag: Int) { + interactionManager.dropRelationsForHandlerWithTag(handlerTag) + registry.dropHandler(handlerTag) + } + + @ReactMethod + fun handleSetJSResponder(viewTag: Int, blockNativeResponder: Boolean) { + val rootView = findRootHelperForViewAncestor(viewTag) + rootView?.handleSetJSResponder(viewTag, blockNativeResponder) + } + + @ReactMethod + fun handleClearJSResponder() { + } + + override fun setGestureHandlerState(handlerTag: Int, newState: Int) { + registry.getHandler(handlerTag)?.let { handler -> + when (newState) { + GestureHandler.STATE_ACTIVE -> handler.activate(force = true) + GestureHandler.STATE_BEGAN -> handler.begin() + GestureHandler.STATE_END -> handler.end() + GestureHandler.STATE_FAILED -> handler.fail() + GestureHandler.STATE_CANCELLED -> handler.cancel() + } + } + } + + @ReactMethod(isBlockingSynchronousMethod = true) + fun install(): Boolean { + return try { + SoLoader.loadLibrary("gesturehandler_abi49_0_0") + val jsContext = reactApplicationContext.javaScriptContextHolder + decorateRuntime(jsContext.get()) + true + } catch (exception: Exception) { + Log.w("[RNGestureHandler]", "Could not install JSI bindings.") + false + } + } + + private external fun decorateRuntime(jsiPtr: Long) + + override fun getConstants(): Map { + return mapOf( + "State" to mapOf( + "UNDETERMINED" to GestureHandler.STATE_UNDETERMINED, + "BEGAN" to GestureHandler.STATE_BEGAN, + "ACTIVE" to GestureHandler.STATE_ACTIVE, + "CANCELLED" to GestureHandler.STATE_CANCELLED, + "FAILED" to GestureHandler.STATE_FAILED, + "END" to GestureHandler.STATE_END + ), + "Direction" to mapOf( + "RIGHT" to GestureHandler.DIRECTION_RIGHT, + "LEFT" to GestureHandler.DIRECTION_LEFT, + "UP" to GestureHandler.DIRECTION_UP, + "DOWN" to GestureHandler.DIRECTION_DOWN + ) + ) + } + + override fun onCatalystInstanceDestroy() { + registry.dropAllHandlers() + interactionManager.reset() + synchronized(roots) { + while (roots.isNotEmpty()) { + val sizeBefore: Int = roots.size + val root: RNGestureHandlerRootHelper = roots[0] + root.tearDown() + if (roots.size >= sizeBefore) { + throw IllegalStateException("Expected root helper to get unregistered while tearing down") + } + } + } + super.onCatalystInstanceDestroy() + } + + fun registerRootHelper(root: RNGestureHandlerRootHelper) { + synchronized(roots) { + if (root in roots) { + throw IllegalStateException("Root helper$root already registered") + } + roots.add(root) + } + } + + fun unregisterRootHelper(root: RNGestureHandlerRootHelper) { + synchronized(roots) { roots.remove(root) } + } + + private fun findRootHelperForViewAncestor(viewTag: Int): RNGestureHandlerRootHelper? { + // TODO: remove resolveRootTagFromReactTag as it's deprecated and unavailable on FabricUIManager + val uiManager = reactApplicationContext.UIManager + val rootViewTag = uiManager.resolveRootTagFromReactTag(viewTag) + if (rootViewTag < 1) { + return null + } + synchronized(roots) { + return roots.firstOrNull { + it.rootView is ReactRootView && it.rootView.rootViewTag == rootViewTag + } + } + } + + @Suppress("UNCHECKED_CAST") + private fun > findFactoryForHandler(handler: GestureHandler): HandlerFactory? = + handlerFactories.firstOrNull { it.type == handler.javaClass } as HandlerFactory? + + private fun > onHandlerUpdate(handler: T) { + // triggers onUpdate and onChange callbacks on the JS side + + if (handler.tag < 0) { + // root containers use negative tags, we don't need to dispatch events for them to the JS + return + } + if (handler.state == GestureHandler.STATE_ACTIVE) { + val handlerFactory = findFactoryForHandler(handler) + + if (handler.actionType == GestureHandler.ACTION_TYPE_REANIMATED_WORKLET) { + // Reanimated worklet + val event = RNGestureHandlerEvent.obtain(handler, handlerFactory) + sendEventForReanimated(event) + } else if (handler.actionType == GestureHandler.ACTION_TYPE_NATIVE_ANIMATED_EVENT) { + // Animated with useNativeDriver: true + val event = RNGestureHandlerEvent.obtain( + handler, + handlerFactory, + useTopPrefixedName = BuildConfig.REACT_NATIVE_MINOR_VERSION >= 71 + ) + sendEventForNativeAnimatedEvent(event) + } else if (handler.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_OLD_API) { + // JS function, Animated.event with useNativeDriver: false using old API + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + val data = RNGestureHandlerEvent.createEventData(handler, handlerFactory) + sendEventForDeviceEvent(RNGestureHandlerEvent.EVENT_NAME, data) + } else { + val event = RNGestureHandlerEvent.obtain(handler, handlerFactory) + sendEventForDirectEvent(event) + } + } else if (handler.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_NEW_API) { + // JS function, Animated.event with useNativeDriver: false using new API + val data = RNGestureHandlerEvent.createEventData(handler, handlerFactory) + sendEventForDeviceEvent(RNGestureHandlerEvent.EVENT_NAME, data) + } + } + } + + private fun > onStateChange(handler: T, newState: Int, oldState: Int) { + // triggers onBegin, onStart, onEnd, onFinalize callbacks on the JS side + + if (handler.tag < 0) { + // root containers use negative tags, we don't need to dispatch events for them to the JS + return + } + val handlerFactory = findFactoryForHandler(handler) + + if (handler.actionType == GestureHandler.ACTION_TYPE_REANIMATED_WORKLET) { + // Reanimated worklet + val event = RNGestureHandlerStateChangeEvent.obtain(handler, newState, oldState, handlerFactory) + sendEventForReanimated(event) + } else if (handler.actionType == GestureHandler.ACTION_TYPE_NATIVE_ANIMATED_EVENT || + handler.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_OLD_API + ) { + // JS function or Animated.event with useNativeDriver: false with old API + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + val data = RNGestureHandlerStateChangeEvent.createEventData(handler, handlerFactory, newState, oldState) + sendEventForDeviceEvent(RNGestureHandlerStateChangeEvent.EVENT_NAME, data) + } else { + val event = RNGestureHandlerStateChangeEvent.obtain(handler, newState, oldState, handlerFactory) + sendEventForDirectEvent(event) + } + } else if (handler.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_NEW_API) { + // JS function or Animated.event with useNativeDriver: false with new API + val data = RNGestureHandlerStateChangeEvent.createEventData(handler, handlerFactory, newState, oldState) + sendEventForDeviceEvent(RNGestureHandlerStateChangeEvent.EVENT_NAME, data) + } + } + + private fun > onTouchEvent(handler: T) { + // triggers onTouchesDown, onTouchesMove, onTouchesUp, onTouchesCancelled callbacks on the JS side + + if (handler.tag < 0) { + // root containers use negative tags, we don't need to dispatch events for them to the JS + return + } + if (handler.state == GestureHandler.STATE_BEGAN || handler.state == GestureHandler.STATE_ACTIVE || + handler.state == GestureHandler.STATE_UNDETERMINED || handler.view != null + ) { + if (handler.actionType == GestureHandler.ACTION_TYPE_REANIMATED_WORKLET) { + // Reanimated worklet + val event = RNGestureHandlerTouchEvent.obtain(handler) + sendEventForReanimated(event) + } else if (handler.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_NEW_API) { + // JS function, Animated.event with useNativeDriver: false with new API + val data = RNGestureHandlerTouchEvent.createEventData(handler) + sendEventForDeviceEvent(RNGestureHandlerEvent.EVENT_NAME, data) + } + } + } + + private fun >sendEventForReanimated(event: T) { + // Delivers the event to Reanimated. + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // Send event directly to Reanimated + reanimatedEventDispatcher.sendEvent(event, reactApplicationContext) + } else { + // In the old architecture, Reanimated subscribes for specific direct events. + sendEventForDirectEvent(event) + } + } + + private fun sendEventForNativeAnimatedEvent(event: RNGestureHandlerEvent) { + // Delivers the event to NativeAnimatedModule. + // TODO: send event directly to NativeAnimated[Turbo]Module + // ReactContext.dispatchEvent is an extension function, depending on the architecture it will + // dispatch event using UIManagerModule or FabricUIManager. + reactApplicationContext.dispatchEvent(event) + } + + private fun >sendEventForDirectEvent(event: T) { + // Delivers the event to JS as a direct event. This method is called only on Paper. + reactApplicationContext.dispatchEvent(event) + } + + private fun sendEventForDeviceEvent(eventName: String, data: WritableMap) { + // Delivers the event to JS as a device event. + reactApplicationContext.deviceEventEmitter.emit(eventName, data) + } + + companion object { + const val MODULE_NAME = "RNGestureHandlerModule" + private const val KEY_SHOULD_CANCEL_WHEN_OUTSIDE = "shouldCancelWhenOutside" + private const val KEY_ENABLED = "enabled" + private const val KEY_NEEDS_POINTER_DATA = "needsPointerData" + private const val KEY_MANUAL_ACTIVATION = "manualActivation" + private const val KEY_HIT_SLOP = "hitSlop" + private const val KEY_HIT_SLOP_LEFT = "left" + private const val KEY_HIT_SLOP_TOP = "top" + private const val KEY_HIT_SLOP_RIGHT = "right" + private const val KEY_HIT_SLOP_BOTTOM = "bottom" + private const val KEY_HIT_SLOP_VERTICAL = "vertical" + private const val KEY_HIT_SLOP_HORIZONTAL = "horizontal" + private const val KEY_HIT_SLOP_WIDTH = "width" + private const val KEY_HIT_SLOP_HEIGHT = "height" + private const val KEY_NATIVE_VIEW_SHOULD_ACTIVATE_ON_START = "shouldActivateOnStart" + private const val KEY_NATIVE_VIEW_DISALLOW_INTERRUPTION = "disallowInterruption" + private const val KEY_TAP_NUMBER_OF_TAPS = "numberOfTaps" + private const val KEY_TAP_MAX_DURATION_MS = "maxDurationMs" + private const val KEY_TAP_MAX_DELAY_MS = "maxDelayMs" + private const val KEY_TAP_MAX_DELTA_X = "maxDeltaX" + private const val KEY_TAP_MAX_DELTA_Y = "maxDeltaY" + private const val KEY_TAP_MAX_DIST = "maxDist" + private const val KEY_TAP_MIN_POINTERS = "minPointers" + private const val KEY_LONG_PRESS_MIN_DURATION_MS = "minDurationMs" + private const val KEY_LONG_PRESS_MAX_DIST = "maxDist" + private const val KEY_PAN_ACTIVE_OFFSET_X_START = "activeOffsetXStart" + private const val KEY_PAN_ACTIVE_OFFSET_X_END = "activeOffsetXEnd" + private const val KEY_PAN_FAIL_OFFSET_RANGE_X_START = "failOffsetXStart" + private const val KEY_PAN_FAIL_OFFSET_RANGE_X_END = "failOffsetXEnd" + private const val KEY_PAN_ACTIVE_OFFSET_Y_START = "activeOffsetYStart" + private const val KEY_PAN_ACTIVE_OFFSET_Y_END = "activeOffsetYEnd" + private const val KEY_PAN_FAIL_OFFSET_RANGE_Y_START = "failOffsetYStart" + private const val KEY_PAN_FAIL_OFFSET_RANGE_Y_END = "failOffsetYEnd" + private const val KEY_PAN_MIN_DIST = "minDist" + private const val KEY_PAN_MIN_VELOCITY = "minVelocity" + private const val KEY_PAN_MIN_VELOCITY_X = "minVelocityX" + private const val KEY_PAN_MIN_VELOCITY_Y = "minVelocityY" + private const val KEY_PAN_MIN_POINTERS = "minPointers" + private const val KEY_PAN_MAX_POINTERS = "maxPointers" + private const val KEY_PAN_AVG_TOUCHES = "avgTouches" + private const val KEY_PAN_ACTIVATE_AFTER_LONG_PRESS = "activateAfterLongPress" + private const val KEY_NUMBER_OF_POINTERS = "numberOfPointers" + private const val KEY_DIRECTION = "direction" + + private fun handleHitSlopProperty(handler: GestureHandler<*>, config: ReadableMap) { + if (config.getType(KEY_HIT_SLOP) == ReadableType.Number) { + val hitSlop = PixelUtil.toPixelFromDIP(config.getDouble(KEY_HIT_SLOP)) + handler.setHitSlop(hitSlop, hitSlop, hitSlop, hitSlop, GestureHandler.HIT_SLOP_NONE, GestureHandler.HIT_SLOP_NONE) + } else { + val hitSlop = config.getMap(KEY_HIT_SLOP)!! + var left = GestureHandler.HIT_SLOP_NONE + var top = GestureHandler.HIT_SLOP_NONE + var right = GestureHandler.HIT_SLOP_NONE + var bottom = GestureHandler.HIT_SLOP_NONE + var width = GestureHandler.HIT_SLOP_NONE + var height = GestureHandler.HIT_SLOP_NONE + if (hitSlop.hasKey(KEY_HIT_SLOP_HORIZONTAL)) { + val horizontalPad = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_HORIZONTAL)) + right = horizontalPad + left = right + } + if (hitSlop.hasKey(KEY_HIT_SLOP_VERTICAL)) { + val verticalPad = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_VERTICAL)) + bottom = verticalPad + top = bottom + } + if (hitSlop.hasKey(KEY_HIT_SLOP_LEFT)) { + left = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_LEFT)) + } + if (hitSlop.hasKey(KEY_HIT_SLOP_TOP)) { + top = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_TOP)) + } + if (hitSlop.hasKey(KEY_HIT_SLOP_RIGHT)) { + right = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_RIGHT)) + } + if (hitSlop.hasKey(KEY_HIT_SLOP_BOTTOM)) { + bottom = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_BOTTOM)) + } + if (hitSlop.hasKey(KEY_HIT_SLOP_WIDTH)) { + width = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_WIDTH)) + } + if (hitSlop.hasKey(KEY_HIT_SLOP_HEIGHT)) { + height = PixelUtil.toPixelFromDIP(hitSlop.getDouble(KEY_HIT_SLOP_HEIGHT)) + } + handler.setHitSlop(left, top, right, bottom, width, height) + } + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.kt new file mode 100644 index 00000000000000..41c515ead29955 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.kt @@ -0,0 +1,100 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.util.SparseArray +import android.view.View +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandlerRegistry +import java.util.* + +class RNGestureHandlerRegistry : GestureHandlerRegistry { + private val handlers = SparseArray>() + private val attachedTo = SparseArray() + private val handlersForView = SparseArray>>() + + @Synchronized + fun registerHandler(handler: GestureHandler<*>) { + handlers.put(handler.tag, handler) + } + + @Synchronized + fun getHandler(handlerTag: Int): GestureHandler<*>? { + return handlers[handlerTag] + } + + @Synchronized + fun attachHandlerToView(handlerTag: Int, viewTag: Int, actionType: Int): Boolean { + val handler = handlers[handlerTag] + return handler?.let { + detachHandler(handler) + handler.actionType = actionType + registerHandlerForViewWithTag(viewTag, handler) + true + } ?: false + } + + @Synchronized + private fun registerHandlerForViewWithTag(viewTag: Int, handler: GestureHandler<*>) { + check(attachedTo[handler.tag] == null) { "Handler $handler already attached" } + attachedTo.put(handler.tag, viewTag) + var listToAdd = handlersForView[viewTag] + if (listToAdd == null) { + listToAdd = ArrayList(1) + listToAdd.add(handler) + handlersForView.put(viewTag, listToAdd) + } else { + synchronized(listToAdd) { + listToAdd.add(handler) + } + } + } + + @Synchronized + private fun detachHandler(handler: GestureHandler<*>) { + val attachedToView = attachedTo[handler.tag] + if (attachedToView != null) { + attachedTo.remove(handler.tag) + val attachedHandlers = handlersForView[attachedToView] + if (attachedHandlers != null) { + synchronized(attachedHandlers) { + attachedHandlers.remove(handler) + } + + if (attachedHandlers.size == 0) { + handlersForView.remove(attachedToView) + } + } + } + if (handler.view != null) { + // Handler is in "prepared" state which means it is registered in the orchestrator and can + // receive touch events. This means that before we remove it from the registry we need to + // "cancel" it so that orchestrator does no longer keep a reference to it. + UiThreadUtil.runOnUiThread { handler.cancel() } + } + } + + @Synchronized + fun dropHandler(handlerTag: Int) { + handlers[handlerTag]?.let { + detachHandler(it) + handlers.remove(handlerTag) + } + } + + @Synchronized + fun dropAllHandlers() { + handlers.clear() + attachedTo.clear() + handlersForView.clear() + } + + @Synchronized + fun getHandlersForViewWithTag(viewTag: Int): ArrayList>? { + return handlersForView[viewTag] + } + + @Synchronized + override fun getHandlersForView(view: View): ArrayList>? { + return getHandlersForViewWithTag(view.id) + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt new file mode 100644 index 00000000000000..e0798aadf87718 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt @@ -0,0 +1,134 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.os.SystemClock +import android.util.Log +import android.view.MotionEvent +import android.view.ViewGroup +import android.view.ViewParent +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.facebook.react.common.ReactConstants +import abi49_0_0.com.facebook.react.uimanager.RootView +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandlerOrchestrator + +class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView: ViewGroup) { + private val orchestrator: GestureHandlerOrchestrator? + private val jsGestureHandler: GestureHandler<*>? + val rootView: ViewGroup + private var shouldIntercept = false + private var passingTouch = false + + init { + UiThreadUtil.assertOnUiThread() + val wrappedViewTag = wrappedView.id + check(wrappedViewTag >= 1) { "Expect view tag to be set for $wrappedView" } + val module = context.getNativeModule(RNGestureHandlerModule::class.java)!! + val registry = module.registry + rootView = findRootViewTag(wrappedView) + Log.i( + ReactConstants.TAG, + "[GESTURE HANDLER] Initialize gesture handler for root view $rootView" + ) + orchestrator = GestureHandlerOrchestrator( + wrappedView, registry, RNViewConfigurationHelper() + ).apply { + minimumAlphaForTraversal = MIN_ALPHA_FOR_TOUCH + } + jsGestureHandler = RootViewGestureHandler().apply { tag = -wrappedViewTag } + with(registry) { + registerHandler(jsGestureHandler) + attachHandlerToView(jsGestureHandler.tag, wrappedViewTag, GestureHandler.ACTION_TYPE_JS_FUNCTION_OLD_API) + } + module.registerRootHelper(this) + } + + fun tearDown() { + Log.i( + ReactConstants.TAG, + "[GESTURE HANDLER] Tearing down gesture handler registered for root view $rootView" + ) + val module = context.getNativeModule(RNGestureHandlerModule::class.java)!! + with(module) { + registry.dropHandler(jsGestureHandler!!.tag) + unregisterRootHelper(this@RNGestureHandlerRootHelper) + } + } + + private inner class RootViewGestureHandler : GestureHandler() { + override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + val currentState = state + if (currentState == STATE_UNDETERMINED) { + begin() + shouldIntercept = false + } + if (event.actionMasked == MotionEvent.ACTION_UP) { + end() + } + } + + override fun onCancel() { + shouldIntercept = true + val time = SystemClock.uptimeMillis() + val event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0f, 0f, 0).apply { + action = MotionEvent.ACTION_CANCEL + } + if (rootView is RootView) { + rootView.onChildStartedNativeGesture(event) + } + } + } + + fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) { + // If this method gets called it means that some native view is attempting to grab lock for + // touch event delivery. In that case we cancel all gesture recognizers + if (orchestrator != null && !passingTouch) { + // if we are in the process of delivering touch events via GH orchestrator, we don't want to + // treat it as a native gesture capturing the lock + tryCancelAllHandlers() + } + } + + fun dispatchTouchEvent(ev: MotionEvent): Boolean { + // We mark `mPassingTouch` before we get into `mOrchestrator.onTouchEvent` so that we can tell + // if `requestDisallow` has been called as a result of a normal gesture handling process or + // as a result of one of the gesture handlers activating + passingTouch = true + orchestrator!!.onTouchEvent(ev) + passingTouch = false + return shouldIntercept + } + + private fun tryCancelAllHandlers() { + // In order to cancel handlers we activate handler that is hooked to the root view + jsGestureHandler?.apply { + if (state == GestureHandler.STATE_BEGAN) { + // Try activate main JS handler + activate() + end() + } + } + } + + /*package*/ + fun handleSetJSResponder(viewTag: Int, blockNativeResponder: Boolean) { + if (blockNativeResponder) { + UiThreadUtil.runOnUiThread { tryCancelAllHandlers() } + } + } + + companion object { + private const val MIN_ALPHA_FOR_TOUCH = 0.1f + private fun findRootViewTag(viewGroup: ViewGroup): ViewGroup { + UiThreadUtil.assertOnUiThread() + var parent: ViewParent? = viewGroup + while (parent != null && parent !is RootView) { + parent = parent.parent + } + checkNotNull(parent) { + "View $viewGroup has not been mounted under ReactRootView" + } + return parent as ViewGroup + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootInterface.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootInterface.kt new file mode 100644 index 00000000000000..44eda5383fff55 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootInterface.kt @@ -0,0 +1,5 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +interface RNGestureHandlerRootInterface { + val rootHelper: RNGestureHandlerRootHelper? +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt new file mode 100644 index 00000000000000..c4f2e5b336c250 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt @@ -0,0 +1,68 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.content.Context +import android.util.Log +import android.view.MotionEvent +import android.view.ViewGroup +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.facebook.react.common.ReactConstants +import abi49_0_0.com.facebook.react.uimanager.RootView +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup + +class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) { + private var _enabled = false + private var rootHelper: RNGestureHandlerRootHelper? = null // TODO: resettable lateinit + override fun onAttachedToWindow() { + super.onAttachedToWindow() + _enabled = !hasGestureHandlerEnabledRootView(this) + if (!_enabled) { + Log.i( + ReactConstants.TAG, + "[GESTURE HANDLER] Gesture handler is already enabled for a parent view" + ) + } + if (_enabled && rootHelper == null) { + rootHelper = RNGestureHandlerRootHelper(context as ReactContext, this) + } + } + + fun tearDown() { + rootHelper?.tearDown() + } + + override fun dispatchTouchEvent(ev: MotionEvent) = + if (_enabled && rootHelper!!.dispatchTouchEvent(ev)) { + true + } else super.dispatchTouchEvent(ev) + + override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) { + if (_enabled) { + rootHelper!!.requestDisallowInterceptTouchEvent(disallowIntercept) + } + super.requestDisallowInterceptTouchEvent(disallowIntercept) + } + + companion object { + private fun hasGestureHandlerEnabledRootView(viewGroup: ViewGroup): Boolean { + UiThreadUtil.assertOnUiThread() + + var parent = viewGroup.parent + while (parent != null) { + // our own deprecated root view + @Suppress("DEPRECATION") + if (parent is RNGestureHandlerEnabledRootView || parent is RNGestureHandlerRootView) { + return true + } + // Checks other roots views but it's mainly for ReactModalHostView.DialogRootViewGroup + // since modals are outside RN hierachy and we have to initialize GH's root view for it + // Note that RNGestureHandlerEnabledRootView implements RootView - that's why this check has to be below + if (parent is RootView) { + return false + } + parent = parent.parent + } + return false + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.kt new file mode 100644 index 00000000000000..4bfc150c5e3918 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.kt @@ -0,0 +1,51 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNGestureHandlerRootViewManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNGestureHandlerRootViewManagerInterface + +/** + * React native's view manager used for creating instances of []RNGestureHandlerRootView}. It + * is being used by projects using react-native-navigation where for each screen new root view need + * to be provided. + */ +@ReactModule(name = RNGestureHandlerRootViewManager.REACT_CLASS) +class RNGestureHandlerRootViewManager : + ViewGroupManager(), + RNGestureHandlerRootViewManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = RNGestureHandlerRootViewManagerDelegate(this) + } + + override fun getDelegate(): ViewManagerDelegate { + return mDelegate + } + + override fun getName() = REACT_CLASS + + override fun createViewInstance(reactContext: ThemedReactContext) = RNGestureHandlerRootView(reactContext) + + override fun onDropViewInstance(view: RNGestureHandlerRootView) { + view.tearDown() + } + + /** + * The following event configuration is necessary even if you are not using + * GestureHandlerRootView component directly. + */ + override fun getExportedCustomDirectEventTypeConstants(): Map> = mutableMapOf( + RNGestureHandlerEvent.EVENT_NAME to + mutableMapOf("registrationName" to RNGestureHandlerEvent.EVENT_NAME), + RNGestureHandlerStateChangeEvent.EVENT_NAME to + mutableMapOf("registrationName" to RNGestureHandlerStateChangeEvent.EVENT_NAME) + ) + + companion object { + const val REACT_CLASS = "RNGestureHandlerRootView" + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.kt new file mode 100644 index 00000000000000..498c4c818ee3d1 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.kt @@ -0,0 +1,72 @@ +// 1. RCTEventEmitter was deprecated in favor of RCTModernEventEmitter interface +// 2. Event#init() with only viewTag was deprecated in favor of two arg c-tor +// 3. Event#receiveEvent() with 3 args was deprecated in favor of 4 args version +// ref: https://github.com/facebook/react-native/commit/2fbbdbb2ce897e8da3f471b08b93f167d566db1d +@file:Suppress("DEPRECATION") + +package abi49_0_0.com.swmansion.gesturehandler.react + +import androidx.core.util.Pools +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler + +class RNGestureHandlerStateChangeEvent private constructor() : Event() { + private var extraData: WritableMap? = null + private fun > init( + handler: T, + newState: Int, + oldState: Int, + dataExtractor: RNGestureHandlerEventDataExtractor?, + ) { + super.init(handler.view!!.id) + extraData = createEventData(handler, dataExtractor, newState, oldState) + } + + override fun onDispose() { + extraData = null + EVENTS_POOL.release(this) + } + + override fun getEventName() = EVENT_NAME + + // TODO: coalescing + override fun canCoalesce() = false + + // TODO: coalescing + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, EVENT_NAME, extraData) + } + + companion object { + const val EVENT_NAME = "onGestureHandlerStateChange" + private const val TOUCH_EVENTS_POOL_SIZE = 7 // magic + private val EVENTS_POOL = Pools.SynchronizedPool(TOUCH_EVENTS_POOL_SIZE) + + fun > obtain( + handler: T, + newState: Int, + oldState: Int, + dataExtractor: RNGestureHandlerEventDataExtractor?, + ): RNGestureHandlerStateChangeEvent = + (EVENTS_POOL.acquire() ?: RNGestureHandlerStateChangeEvent()).apply { + init(handler, newState, oldState, dataExtractor) + } + + fun > createEventData( + handler: T, + dataExtractor: RNGestureHandlerEventDataExtractor?, + newState: Int, + oldState: Int, + ): WritableMap = Arguments.createMap().apply { + dataExtractor?.extractEventData(handler, this) + putInt("handlerTag", handler.tag) + putInt("state", newState) + putInt("oldState", oldState) + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerTouchEvent.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerTouchEvent.kt new file mode 100644 index 00000000000000..be7c5564fee5df --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNGestureHandlerTouchEvent.kt @@ -0,0 +1,69 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import androidx.core.util.Pools +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter +import abi49_0_0.com.swmansion.gesturehandler.core.GestureHandler + +class RNGestureHandlerTouchEvent private constructor() : Event() { + private var extraData: WritableMap? = null + private var coalescingKey: Short = 0 + private fun > init(handler: T) { + super.init(handler.view!!.id) + extraData = createEventData(handler) + coalescingKey = handler.eventCoalescingKey + } + + override fun onDispose() { + extraData = null + EVENTS_POOL.release(this) + } + + override fun getEventName() = EVENT_NAME + + override fun canCoalesce() = true + + override fun getCoalescingKey() = coalescingKey + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, EVENT_NAME, extraData) + } + + companion object { + const val EVENT_UNDETERMINED = 0 + const val EVENT_TOUCH_DOWN = 1 + const val EVENT_TOUCH_MOVE = 2 + const val EVENT_TOUCH_UP = 3 + const val EVENT_TOUCH_CANCELLED = 4 + + const val EVENT_NAME = "onGestureHandlerEvent" + private const val TOUCH_EVENTS_POOL_SIZE = 7 // magic + private val EVENTS_POOL = Pools.SynchronizedPool(TOUCH_EVENTS_POOL_SIZE) + + fun > obtain(handler: T): RNGestureHandlerTouchEvent = + (EVENTS_POOL.acquire() ?: RNGestureHandlerTouchEvent()).apply { + init(handler) + } + + fun > createEventData(handler: T,): WritableMap = Arguments.createMap().apply { + putInt("handlerTag", handler.tag) + putInt("state", handler.state) + putInt("numberOfTouches", handler.trackedPointersCount) + putInt("eventType", handler.touchEventType) + + handler.consumeChangedTouchesPayload()?.let { + putArray("changedTouches", it) + } + + handler.consumeAllTouchesPayload()?.let { + putArray("allTouches", it) + } + + if (handler.isAwaiting && handler.state == GestureHandler.STATE_ACTIVE) { + putInt("state", GestureHandler.STATE_BEGAN) + } + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNViewConfigurationHelper.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNViewConfigurationHelper.kt new file mode 100644 index 00000000000000..691aefea68233c --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/java/abi49_0_0/com/swmansion/gesturehandler/react/RNViewConfigurationHelper.kt @@ -0,0 +1,51 @@ +package abi49_0_0.com.swmansion.gesturehandler.react + +import android.view.View +import android.view.ViewGroup +import abi49_0_0.com.facebook.react.uimanager.PointerEvents +import abi49_0_0.com.facebook.react.uimanager.ReactPointerEventsView +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup +import abi49_0_0.com.swmansion.gesturehandler.core.PointerEventsConfig +import abi49_0_0.com.swmansion.gesturehandler.core.ViewConfigurationHelper + +class RNViewConfigurationHelper : ViewConfigurationHelper { + override fun getPointerEventsConfigForView(view: View): PointerEventsConfig { + val pointerEvents: PointerEvents = + if (view is ReactPointerEventsView) { + (view as ReactPointerEventsView).pointerEvents + } else PointerEvents.AUTO + + // Views that are disabled should never be the target of pointer events. However, their children + // can be because some views (SwipeRefreshLayout) use enabled but still have children that can + // be valid targets. + if (!view.isEnabled) { + if (pointerEvents == PointerEvents.AUTO) { + return PointerEventsConfig.BOX_NONE + } else if (pointerEvents == PointerEvents.BOX_ONLY) { + return PointerEventsConfig.NONE + } + } + + return when (pointerEvents) { + PointerEvents.BOX_ONLY -> PointerEventsConfig.BOX_ONLY + PointerEvents.BOX_NONE -> PointerEventsConfig.BOX_NONE + PointerEvents.NONE -> PointerEventsConfig.NONE + PointerEvents.AUTO -> PointerEventsConfig.AUTO + } + } + + override fun getChildInDrawingOrderAtIndex(parent: ViewGroup, index: Int): View { + return if (parent is ReactViewGroup) { + parent.getChildAt(parent.getZIndexMappedChildIndex(index)) + } else parent.getChildAt(index) + } + + override fun isViewClippingChildren(view: ViewGroup): Boolean { + if (view.clipChildren) { + return true + } + return if (view is ReactViewGroup) { + "hidden" == view.overflow + } else false + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/jni/CMakeLists.txt b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/jni/CMakeLists.txt new file mode 100644 index 00000000000000..33e86d4e5fe884 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/jni/CMakeLists.txt @@ -0,0 +1,25 @@ +project(GestureHandler) +cmake_minimum_required(VERSION 3.9.0) + +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_CXX_STANDARD 17) + +set(REACT_ANDROID_DIR "${REACT_NATIVE_DIR}/ReactAndroid") + +include(${REACT_ANDROID_DIR}/cmake-utils/folly-flags.cmake) +add_compile_options(${folly_FLAGS}) + +add_library(gesturehandler + SHARED + cpp-adapter.cpp +) + +find_package(ReactAndroid REQUIRED CONFIG) + +target_link_libraries( + gesturehandler + ReactAndroid::react_render_core_abi49_0_0 + ReactAndroid::react_render_uimanager_abi49_0_0 + ReactAndroid::jsi_abi49_0_0 + ReactAndroid::react_nativemodule_core_abi49_0_0 +) diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/main/jni/cpp-adapter.cpp b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/jni/cpp-adapter.cpp new file mode 100644 index 00000000000000..6b1d41780d327f --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/main/jni/cpp-adapter.cpp @@ -0,0 +1,44 @@ +#include +#include + +#include + +using namespace facebook; +using namespace react; + +void decorateRuntime(jsi::Runtime &runtime) { + auto isFormsStackingContext = jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "isFormsStackingContext"), + 1, + [](jsi::Runtime &runtime, + const jsi::Value &thisValue, + const jsi::Value *arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isObject()) { + return jsi::Value::null(); + } + + auto shadowNode = arguments[0] + .asObject(runtime) + .getHostObject(runtime) + ->shadowNode; + bool isFormsStackingContext = shadowNode->getTraits().check( + ShadowNodeTraits::FormsStackingContext); + + return jsi::Value(isFormsStackingContext); + }); + runtime.global().setProperty( + runtime, "isFormsStackingContext", std::move(isFormsStackingContext)); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_swmansion_gesturehandler_react_RNGestureHandlerModule_decorateRuntime( + JNIEnv *env, + jobject clazz, + jlong jsiPtr) { + jsi::Runtime *runtime = reinterpret_cast(jsiPtr); + if (runtime) { + decorateRuntime(*runtime); + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java new file mode 100644 index 00000000000000..e9c061fc5f904f --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java @@ -0,0 +1,50 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GeneratePropsJavaDelegate.js + */ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ColorPropConverter; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNGestureHandlerButtonManagerDelegate & RNGestureHandlerButtonManagerInterface> extends BaseViewManagerDelegate { + public RNGestureHandlerButtonManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "exclusive": + mViewManager.setExclusive(view, value == null ? true : (boolean) value); + break; + case "foreground": + mViewManager.setForeground(view, value == null ? false : (boolean) value); + break; + case "borderless": + mViewManager.setBorderless(view, value == null ? false : (boolean) value); + break; + case "enabled": + mViewManager.setEnabled(view, value == null ? true : (boolean) value); + break; + case "rippleColor": + mViewManager.setRippleColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "rippleRadius": + mViewManager.setRippleRadius(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "touchSoundDisabled": + mViewManager.setTouchSoundDisabled(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java new file mode 100644 index 00000000000000..50c64dd5301b1a --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java @@ -0,0 +1,23 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface RNGestureHandlerButtonManagerInterface { + void setExclusive(T view, boolean value); + void setForeground(T view, boolean value); + void setBorderless(T view, boolean value); + void setEnabled(T view, boolean value); + void setRippleColor(T view, @Nullable Integer value); + void setRippleRadius(T view, int value); + void setTouchSoundDisabled(T view, boolean value); +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerRootViewManagerDelegate.java b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerRootViewManagerDelegate.java new file mode 100644 index 00000000000000..f717b1aecc0e98 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerRootViewManagerDelegate.java @@ -0,0 +1,25 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNGestureHandlerRootViewManagerDelegate & RNGestureHandlerRootViewManagerInterface> extends BaseViewManagerDelegate { + public RNGestureHandlerRootViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + super.setProperty(view, propName, value); + } +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerRootViewManagerInterface.java b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerRootViewManagerInterface.java new file mode 100644 index 00000000000000..eea80b0c4615f3 --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNGestureHandlerRootViewManagerInterface.java @@ -0,0 +1,16 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; + +public interface RNGestureHandlerRootViewManagerInterface { + // No props +} diff --git a/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/swmansion/gesturehandler/ReactContextExtensions.kt b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/swmansion/gesturehandler/ReactContextExtensions.kt new file mode 100644 index 00000000000000..17965d0d964b3b --- /dev/null +++ b/android/vendored/sdk49/react-native-gesture-handler/android/src/paper/java/abi49_0_0/com/swmansion/gesturehandler/ReactContextExtensions.kt @@ -0,0 +1,13 @@ +package abi49_0_0.com.swmansion.gesturehandler + +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule +import abi49_0_0.com.facebook.react.uimanager.events.Event + +fun ReactContext.dispatchEvent(event: Event<*>) { + try { + this.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher.dispatchEvent(event) + } catch (e: NullPointerException) { + throw Exception("Couldn't get an instance of UIManagerModule. Gesture Handler is unable to send an event.", e) + } +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/build.gradle b/android/vendored/sdk49/react-native-pager-view/android/build.gradle new file mode 100644 index 00000000000000..1971db3ea92868 --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/build.gradle @@ -0,0 +1,168 @@ +buildscript { + // Buildscript is evaluated before everything else so we can't use getExtOrDefault + def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['PagerView_kotlinVersion'] + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.2.1' + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +def isNewArchitectureEnabled() { + return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + + +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} + +def getExtOrDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['PagerView_' + name] +} + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['PagerView_' + name]).toInteger() +} + +android { + compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') + + defaultConfig { + minSdkVersion getExtOrIntegerDefault('minSdkVersion') + targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable 'GradleCompatible' + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + sourceSets { + main { + if (isNewArchitectureEnabled()) { + java.srcDirs += [ + "src/fabric/java", + "${project.buildDir}/generated/source/codegen/java" + ] + } else { + java.srcDirs += ["src/paper/java"] + } + } + } +} + +repositories { + mavenCentral() + google() + + def found = false + def defaultDir = null + def androidSourcesName = 'React Native sources' + + if (rootProject.ext.has('reactNativeAndroidRoot')) { + defaultDir = rootProject.ext.get('reactNativeAndroidRoot') + } else { + defaultDir = new File( + projectDir, + '/../../../node_modules/versioned-react-native/packages/react-native/android' + ) + } + + if (defaultDir.exists()) { + maven { + url defaultDir.toString() + name androidSourcesName + } + + logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}") + found = true + } else { + def parentDir = rootProject.projectDir + + 1.upto(5, { + if (found) return true + parentDir = parentDir.parentFile + + def androidSourcesDir = new File( + parentDir, + 'node_modules/react-native' + ) + + def androidPrebuiltBinaryDir = new File( + parentDir, + 'node_modules/versioned-react-native/packages/react-native/android' + ) + + if (androidPrebuiltBinaryDir.exists()) { + maven { + url androidPrebuiltBinaryDir.toString() + name androidSourcesName + } + + logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}") + found = true + } else if (androidSourcesDir.exists()) { + maven { + url androidSourcesDir.toString() + name androidSourcesName + } + + logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}") + found = true + } + }) + } + + if (!found) { + throw new GradleException( + "${project.name}: unable to locate React Native android sources. " + + "Ensure you have you installed React Native as a dependency in your project and try again." + ) + } +} + +def kotlin_version = getExtOrDefault('kotlinVersion') + +dependencies { + //noinspection GradleDynamicVersion + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.viewpager2:viewpager2:1.0.0' +} + +if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src") + libraryName = "RNCViewPager" + codegenJavaPackageName = "com.reactnativepagerview" + } +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/fabric/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManager.kt b/android/vendored/sdk49/react-native-pager-view/android/src/fabric/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManager.kt new file mode 100644 index 00000000000000..3e9d05f7ff793d --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/fabric/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManager.kt @@ -0,0 +1,204 @@ +package abi49_0_0.com.reactnativepagerview + +import android.view.View +import android.view.ViewGroup +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.facebook.infer.annotation.Assertions +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.ReadableArray +import abi49_0_0.com.facebook.react.common.MapBuilder +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.* +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.viewmanagers.RNCViewPagerManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNCViewPagerManagerInterface +import abi49_0_0.com.reactnativepagerview.event.PageScrollEvent +import abi49_0_0.com.reactnativepagerview.event.PageScrollStateChangedEvent +import abi49_0_0.com.reactnativepagerview.event.PageSelectedEvent + + +@ReactModule(name = PagerViewViewManagerImpl.NAME) +class PagerViewViewManager : ViewGroupManager(), RNCViewPagerManagerInterface { + private val mDelegate: ViewManagerDelegate = RNCViewPagerManagerDelegate(this) + + override fun getDelegate() = mDelegate + + override fun getName(): String { + return PagerViewViewManagerImpl.NAME + } + + override fun receiveCommand(root: NestedScrollableHost, commandId: String?, args: ReadableArray?) { + mDelegate.receiveCommand(root, commandId, args) + } + + public override fun createViewInstance(reactContext: ThemedReactContext): NestedScrollableHost { + val host = NestedScrollableHost(reactContext) + host.id = View.generateViewId() + host.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + host.isSaveEnabled = false + val vp = ViewPager2(reactContext) + vp.adapter = ViewPagerAdapter() + //https://github.com/callstack/react-native-viewpager/issues/183 + vp.isSaveEnabled = false + + vp.post { + vp.registerOnPageChangeCallback(object : OnPageChangeCallback() { + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + super.onPageScrolled(position, positionOffset, positionOffsetPixels) + UIManagerHelper.getEventDispatcherForReactTag(reactContext, host.id)?.dispatchEvent( + PageScrollEvent(host.id, position, positionOffset) + ) + } + + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + UIManagerHelper.getEventDispatcherForReactTag(reactContext, host.id)?.dispatchEvent( + PageSelectedEvent(host.id, position) + ) + } + + override fun onPageScrollStateChanged(state: Int) { + super.onPageScrollStateChanged(state) + val pageScrollState: String = when (state) { + ViewPager2.SCROLL_STATE_IDLE -> "idle" + ViewPager2.SCROLL_STATE_DRAGGING -> "dragging" + ViewPager2.SCROLL_STATE_SETTLING -> "settling" + else -> throw IllegalStateException("Unsupported pageScrollState") + } + UIManagerHelper.getEventDispatcherForReactTag(reactContext, host.id)?.dispatchEvent( + PageScrollStateChangedEvent(host.id, pageScrollState) + ) + } + }) + UIManagerHelper.getEventDispatcherForReactTag(reactContext, host.id)?.dispatchEvent( + PageSelectedEvent(host.id, vp.currentItem) + ) + } + host.addView(vp) + return host + } + + override fun addView(host: NestedScrollableHost, child: View?, index: Int) { + PagerViewViewManagerImpl.addView(host, child, index) + } + + override fun getChildCount(parent: NestedScrollableHost) = PagerViewViewManagerImpl.getChildCount(parent) + + override fun getChildAt(parent: NestedScrollableHost, index: Int): View { + return PagerViewViewManagerImpl.getChildAt(parent, index) + } + + override fun removeView(parent: NestedScrollableHost, view: View) { + PagerViewViewManagerImpl.removeView(parent, view) + } + + override fun removeAllViews(parent: NestedScrollableHost) { + PagerViewViewManagerImpl.removeAllViews(parent) + } + + override fun removeViewAt(parent: NestedScrollableHost, index: Int) { + PagerViewViewManagerImpl.removeViewAt(parent, index) + } + + override fun needsCustomLayoutForChildren(): Boolean { + return PagerViewViewManagerImpl.needsCustomLayoutForChildren() + } + + @ReactProp(name = "scrollEnabled", defaultBoolean = true) + override fun setScrollEnabled(view: NestedScrollableHost?, value: Boolean) { + if (view != null) { + PagerViewViewManagerImpl.setScrollEnabled(view, value) + } + } + + @ReactProp(name = "layoutDirection") + override fun setLayoutDirection(view: NestedScrollableHost?, value: String?) { + if (view != null && value != null) { + PagerViewViewManagerImpl.setLayoutDirection(view, value) + } + } + + @ReactProp(name = "initialPage", defaultInt = 0) + override fun setInitialPage(view: NestedScrollableHost?, value: Int) { + if (view != null) { + PagerViewViewManagerImpl.setInitialPage(view, value) + } + } + + @ReactProp(name = "orientation") + override fun setOrientation(view: NestedScrollableHost?, value: String?) { + if (view != null && value != null) { + PagerViewViewManagerImpl.setOrientation(view, value) + } + } + + @ReactProp(name = "offscreenPageLimit", defaultInt = ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT) + override fun setOffscreenPageLimit(view: NestedScrollableHost?, value: Int) { + if (view != null) { + PagerViewViewManagerImpl.setOffscreenPageLimit(view, value) + } + } + + @ReactProp(name = "pageMargin", defaultInt = 0) + override fun setPageMargin(view: NestedScrollableHost?, value: Int) { + if (view != null) { + PagerViewViewManagerImpl.setPageMargin(view, value) + } + } + + @ReactProp(name = "overScrollMode") + override fun setOverScrollMode(view: NestedScrollableHost?, value: String?) { + if (view != null && value != null) { + PagerViewViewManagerImpl.setOverScrollMode(view, value) + } + } + + @ReactProp(name = "overdrag") + override fun setOverdrag(view: NestedScrollableHost?, value: Boolean) { + return + } + + @ReactProp(name = "keyboardDismissMode") + override fun setKeyboardDismissMode(view: NestedScrollableHost?, value: String?) { + return + } + + fun goTo(root: NestedScrollableHost?, selectedPage: Int, scrollWithAnimation: Boolean) { + if (root == null) { + return + } + val view = PagerViewViewManagerImpl.getViewPager(root) + Assertions.assertNotNull(view) + val childCount = view.adapter?.itemCount + val canScroll = childCount != null && childCount > 0 && selectedPage >= 0 && selectedPage < childCount + if (canScroll) { + PagerViewViewManagerImpl.setCurrentItem(view, selectedPage, scrollWithAnimation) + val reactContext = view.context as ReactContext + UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)?.dispatchEvent( + PageSelectedEvent(view.id, selectedPage) + ) + } + } + + override fun setPage(view: NestedScrollableHost?, selectedPage: Int) { + goTo(view, selectedPage, true) + } + + override fun setPageWithoutAnimation(view: NestedScrollableHost?, selectedPage: Int) { + goTo(view, selectedPage, false) + } + + override fun setScrollEnabledImperatively(view: NestedScrollableHost?, scrollEnabled: Boolean) { + if (view != null) { + PagerViewViewManagerImpl.setScrollEnabled(view, scrollEnabled) + } + } + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap> { + return MapBuilder.of( + PageScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScroll"), + PageScrollStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScrollStateChanged"), + PageSelectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageSelected")) + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/react-native-pager-view/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a34ce713bfc587 --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/Helper.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/Helper.kt new file mode 100644 index 00000000000000..4ad022a0fa416f --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/Helper.kt @@ -0,0 +1,21 @@ +package abi49_0_0.com.reactnativepagerview + +import android.content.Context +import android.content.ContextWrapper +import android.view.View +import abi49_0_0.com.facebook.react.bridge.ReactContext + + +class Helper { + companion object { + // https://github.com/facebook/react-native/blob/v0.64.2/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java#L138 + fun getReactContext(view: View): ReactContext? { + var context: Context = view.getContext() + if (context !is ReactContext && context is ContextWrapper) { + context = context.baseContext + } + return if (context is ReactContext) context else null; + } + } + +} \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/NestedScrollableHost.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/NestedScrollableHost.kt new file mode 100644 index 00000000000000..4710aed0836411 --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/NestedScrollableHost.kt @@ -0,0 +1,97 @@ +package abi49_0_0.com.reactnativepagerview + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import android.widget.FrameLayout +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL +import kotlin.math.absoluteValue +import kotlin.math.sign + +/** + * Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem + * where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as + * ViewPager2. The scrollable element needs to be the immediate and only child of this host layout. + * + * This solution has limitations when using multiple levels of nested scrollable elements + * (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2). + */ +class NestedScrollableHost : FrameLayout { + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + public var initialIndex: Int? = null + public var didSetInitialIndex = false + private var touchSlop = 0 + private var initialX = 0f + private var initialY = 0f + private val parentViewPager: ViewPager2? + get() { + var v: View? = parent as? View + while (v != null && v !is ViewPager2) { + v = v.parent as? View + } + return v as? ViewPager2 + } + + private val child: View? get() = if (childCount > 0) getChildAt(0) else null + + init { + touchSlop = ViewConfiguration.get(context).scaledTouchSlop + } + + private fun canChildScroll(orientation: Int, delta: Float): Boolean { + val direction = -delta.sign.toInt() + return when (orientation) { + 0 -> child?.canScrollHorizontally(direction) ?: false + 1 -> child?.canScrollVertically(direction) ?: false + else -> throw IllegalArgumentException() + } + } + + override fun onInterceptTouchEvent(e: MotionEvent): Boolean { + handleInterceptTouchEvent(e) + return super.onInterceptTouchEvent(e) + } + + private fun handleInterceptTouchEvent(e: MotionEvent) { + val orientation = parentViewPager?.orientation ?: return + + // Early return if child can't scroll in same direction as parent + if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) { + return + } + + if (e.action == MotionEvent.ACTION_DOWN) { + initialX = e.x + initialY = e.y + parent.requestDisallowInterceptTouchEvent(true) + } else if (e.action == MotionEvent.ACTION_MOVE) { + val dx = e.x - initialX + val dy = e.y - initialY + val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL + + // assuming ViewPager2 touch-slop is 2x touch-slop of child + val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f + val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f + + if (scaledDx > touchSlop || scaledDy > touchSlop) { + if (isVpHorizontal == (scaledDy > scaledDx)) { + // Gesture is perpendicular, allow all parents to intercept + parent.requestDisallowInterceptTouchEvent(false) + } else { + // Gesture is parallel, query child if movement in that direction is possible + if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) { + // Child can scroll, disallow all parents to intercept + parent.requestDisallowInterceptTouchEvent(true) + } else { + // Child cannot scroll, allow all parents to intercept + parent.requestDisallowInterceptTouchEvent(false) + } + } + } + } + } +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManagerImpl.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManagerImpl.kt new file mode 100644 index 00000000000000..aba8220038821d --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManagerImpl.kt @@ -0,0 +1,160 @@ +package abi49_0_0.com.reactnativepagerview + +import android.view.View +import androidx.viewpager2.widget.ViewPager2 +import abi49_0_0.com.facebook.react.uimanager.PixelUtil + +object PagerViewViewManagerImpl { + const val NAME = "RNCViewPager" + + fun getViewPager(view: NestedScrollableHost): ViewPager2 { + if (view.getChildAt(0) is ViewPager2) { + return view.getChildAt(0) as ViewPager2 + } else { + throw ClassNotFoundException("Could not retrieve ViewPager2 instance") + } + } + + fun setCurrentItem(view: ViewPager2, selectedTab: Int, scrollSmooth: Boolean) { + refreshViewChildrenLayout(view) + view.setCurrentItem(selectedTab, scrollSmooth) + } + + fun addView(host: NestedScrollableHost, child: View?, index: Int) { + if (child == null) { + return + } + val parent = getViewPager(host) + + (parent.adapter as ViewPagerAdapter?)?.addChild(child, index); + + if (parent.currentItem == index) { + // Solves https://github.com/callstack/react-native-pager-view/issues/219 + // Required so ViewPager actually displays first dynamically added child + // (otherwise a white screen is shown until the next user interaction). + // https://github.com/facebook/react-native/issues/17968#issuecomment-697136929 + refreshViewChildrenLayout(parent) + } + + if (!host.didSetInitialIndex && host.initialIndex == index) { + host.didSetInitialIndex = true + setCurrentItem(parent, index, false) + } + } + + fun getChildCount(parent: NestedScrollableHost) = getViewPager(parent).adapter?.itemCount ?: 0 + + fun getChildAt(parent: NestedScrollableHost, index: Int): View { + val view = getViewPager(parent) + return (view.adapter as ViewPagerAdapter?)!!.getChildAt(index) + } + + fun removeView(parent: NestedScrollableHost, view: View) { + val pager = getViewPager(parent) + (pager.adapter as ViewPagerAdapter?)?.removeChild(view) + + // Required so ViewPager actually animates the removed view right away (otherwise + // a white screen is shown until the next user interaction). + // https://github.com/facebook/react-native/issues/17968#issuecomment-697136929 + refreshViewChildrenLayout(pager) + } + + fun removeAllViews(parent: NestedScrollableHost) { + val pager = getViewPager(parent) + pager.isUserInputEnabled = false + val adapter = pager.adapter as ViewPagerAdapter? + adapter?.removeAll() + } + + fun removeViewAt(parent: NestedScrollableHost, index: Int) { + val pager = getViewPager(parent) + val adapter = pager.adapter as ViewPagerAdapter? + adapter?.removeChildAt(index) + + // Required so ViewPager actually animates the removed view right away (otherwise + // a white screen is shown until the next user interaction). + // https://github.com/facebook/react-native/issues/17968#issuecomment-697136929 + refreshViewChildrenLayout(pager) + } + + fun needsCustomLayoutForChildren(): Boolean { + return true + } + + fun setScrollEnabled(host: NestedScrollableHost, value: Boolean) { + getViewPager(host).isUserInputEnabled = value + } + + fun setLayoutDirection(host: NestedScrollableHost, value: String) { + val view = getViewPager(host) + when (value) { + "rtl" -> { + view.layoutDirection = View.LAYOUT_DIRECTION_RTL + } + else -> { + view.layoutDirection = View.LAYOUT_DIRECTION_LTR + } + } + } + + fun setInitialPage(host: NestedScrollableHost, value: Int) { + val view = getViewPager(host) + //https://github.com/callstack/react-native-pager-view/issues/456 + //Initial index should be set only once. + if (host.initialIndex === null) { + host.initialIndex = value + view.post { + host.didSetInitialIndex = true + } + } + } + + fun setOrientation(host: NestedScrollableHost, value: String) { + getViewPager(host).orientation = if (value == "vertical") ViewPager2.ORIENTATION_VERTICAL else ViewPager2.ORIENTATION_HORIZONTAL + } + + fun setOffscreenPageLimit(host: NestedScrollableHost, value: Int) { + getViewPager(host).offscreenPageLimit = value + } + + fun setOverScrollMode(host: NestedScrollableHost, value: String) { + val child = getViewPager(host).getChildAt(0) + when (value) { + "never" -> { + child.overScrollMode = ViewPager2.OVER_SCROLL_NEVER + } + "always" -> { + child.overScrollMode = ViewPager2.OVER_SCROLL_ALWAYS + } + else -> { + child.overScrollMode = ViewPager2.OVER_SCROLL_IF_CONTENT_SCROLLS + } + } + } + + fun setPageMargin(host: NestedScrollableHost, margin: Int) { + val pager = getViewPager(host) + val pageMargin = PixelUtil.toPixelFromDIP(margin.toDouble()).toInt() + /** + * Don't use MarginPageTransformer to be able to support negative margins + */ + pager.setPageTransformer { page, position -> + val offset = pageMargin * position + if (pager.orientation == ViewPager2.ORIENTATION_HORIZONTAL) { + val isRTL = pager.layoutDirection == View.LAYOUT_DIRECTION_RTL + page.translationX = if (isRTL) -offset else offset + } else { + page.translationY = offset + } + } + } + + private fun refreshViewChildrenLayout(view: View) { + view.post { + view.measure( + View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY)) + view.layout(view.left, view.top, view.right, view.bottom) + } + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/PagerViewViewPackage.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/PagerViewViewPackage.kt new file mode 100644 index 00000000000000..8798167ddad0b7 --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/PagerViewViewPackage.kt @@ -0,0 +1,17 @@ +package abi49_0_0.com.reactnativepagerview + +import abi49_0_0.com.facebook.react.ReactPackage +import abi49_0_0.com.facebook.react.bridge.NativeModule +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.uimanager.ViewManager + + +class PagerViewPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return emptyList() + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf(PagerViewViewManager()) + } +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/ViewPagerAdapter.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/ViewPagerAdapter.kt new file mode 100644 index 00000000000000..043e9edde08ba6 --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/ViewPagerAdapter.kt @@ -0,0 +1,69 @@ +package abi49_0_0.com.reactnativepagerview + +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.recyclerview.widget.RecyclerView.Adapter +import java.util.* + + +class ViewPagerAdapter() : Adapter() { + private val childrenViews: ArrayList = ArrayList() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerViewHolder { + return ViewPagerViewHolder.create(parent) + } + + override fun onBindViewHolder(holder: ViewPagerViewHolder, index: Int) { + val container: FrameLayout = holder.container + val child = getChildAt(index) + + if (container.childCount > 0) { + container.removeAllViews() + } + + if (child.parent != null) { + (child.parent as FrameLayout).removeView(child) + } + + container.addView(child) + } + + override fun getItemCount(): Int { + return childrenViews.size + } + + fun addChild(child: View, index: Int) { + childrenViews.add(index, child) + notifyItemInserted(index) + } + + fun getChildAt(index: Int): View { + return childrenViews[index] + } + + fun removeChild(child: View) { + val index = childrenViews.indexOf(child) + + if(index > -1) { + removeChildAt(index) + } + } + + fun removeAll() { + for (index in 1..childrenViews.size) { + val child = childrenViews[index-1] + if (child.parent?.parent != null) { + (child.parent.parent as ViewGroup).removeView(child.parent as View) + } + } + val removedChildrenCount = childrenViews.size + childrenViews.clear() + notifyItemRangeRemoved(0, removedChildrenCount) + } + + fun removeChildAt(index: Int) { + childrenViews.removeAt(index) + notifyItemRemoved(index) + } +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/ViewPagerViewHolder.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/ViewPagerViewHolder.kt new file mode 100644 index 00000000000000..25a2847695a92e --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/ViewPagerViewHolder.kt @@ -0,0 +1,21 @@ +package abi49_0_0.com.reactnativepagerview + +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.widget.FrameLayout +import androidx.recyclerview.widget.RecyclerView.ViewHolder + + +class ViewPagerViewHolder private constructor(container: FrameLayout) : ViewHolder(container) { + val container: FrameLayout + get() = itemView as FrameLayout + + companion object { + fun create(parent: ViewGroup): ViewPagerViewHolder { + val container = FrameLayout(parent.context) + container.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) + container.isSaveEnabled = false + return ViewPagerViewHolder(container) + } + } +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageScrollEvent.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageScrollEvent.kt new file mode 100644 index 00000000000000..d31f2163467f0c --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageScrollEvent.kt @@ -0,0 +1,47 @@ +package abi49_0_0.com.reactnativepagerview.event + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter +import java.lang.Float.isInfinite +import java.lang.Float.isNaN + + +/** + * Event emitted by [ReactViewPager] when user scrolls between pages (or when animating + * between pages). + * + * Additional data provided by this event: + * - position - index of first page from the left that is currently visible + * - offset - value from range [0,1) describing stage between page transitions. Value x means that + * (1 - x) fraction of the page at "position" index is visible, and x fraction of the next page + * is visible. + */ +class PageScrollEvent(viewTag: Int, private val mPosition: Int, offset: Float) : Event(viewTag) { + private val mOffset: Float = if (isInfinite(offset) || isNaN(offset)) 0.0f else offset + override fun getEventName(): String { + return EVENT_NAME + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, serializeEventData()) + } + + private fun serializeEventData(): WritableMap { + val eventData = Arguments.createMap() + eventData.putInt("position", mPosition) + eventData.putDouble("offset", mOffset.toDouble()) + return eventData + } + + companion object { + const val EVENT_NAME = "topPageScroll" + } + + init { + + // folly::toJson default options don't support serialize NaN or Infinite value + } +} + diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageScrollStateChangedEvent.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageScrollStateChangedEvent.kt new file mode 100644 index 00000000000000..260af806e27311 --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageScrollStateChangedEvent.kt @@ -0,0 +1,34 @@ +package abi49_0_0.com.reactnativepagerview.event + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + + +/** + * Event emitted by [ReactViewPager] when user scrolling state changed. + * + * Additional data provided by this event: + * - pageScrollState - {Idle,Dragging,Settling} + */ +class PageScrollStateChangedEvent(viewTag: Int, private val mPageScrollState: String) : Event(viewTag) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, serializeEventData()) + } + + private fun serializeEventData(): WritableMap { + val eventData = Arguments.createMap() + eventData.putString("pageScrollState", mPageScrollState) + return eventData + } + + companion object { + const val EVENT_NAME = "topPageScrollStateChanged" + } + +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageSelectedEvent.kt b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageSelectedEvent.kt new file mode 100644 index 00000000000000..6b1f58a0115d3e --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/main/java/abi49_0_0/com/reactnativepagerview/event/PageSelectedEvent.kt @@ -0,0 +1,34 @@ +package abi49_0_0.com.reactnativepagerview.event + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + + +/** + * Event emitted by [ReactViewPager] when selected page changes. + * + * Additional data provided by this event: + * - position - index of page that has been selected + */ +class PageSelectedEvent(viewTag: Int, private val mPosition: Int) : Event(viewTag) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, serializeEventData()) + } + + private fun serializeEventData(): WritableMap { + val eventData = Arguments.createMap() + eventData.putInt("position", mPosition) + return eventData + } + + companion object { + const val EVENT_NAME = "topPageSelected" + } + +} diff --git a/android/vendored/sdk49/react-native-pager-view/android/src/paper/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManager.kt b/android/vendored/sdk49/react-native-pager-view/android/src/paper/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManager.kt new file mode 100644 index 00000000000000..25869be75c8cbd --- /dev/null +++ b/android/vendored/sdk49/react-native-pager-view/android/src/paper/java/abi49_0_0/com/reactnativepagerview/PagerViewViewManager.kt @@ -0,0 +1,173 @@ +package abi49_0_0.com.reactnativepagerview + +import android.view.View +import android.view.ViewGroup +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.facebook.infer.annotation.Assertions +import abi49_0_0.com.facebook.react.bridge.ReadableArray +import abi49_0_0.com.facebook.react.common.MapBuilder +import abi49_0_0.com.facebook.react.uimanager.PixelUtil +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher +import abi49_0_0.com.reactnativepagerview.event.PageScrollEvent +import abi49_0_0.com.reactnativepagerview.event.PageScrollStateChangedEvent +import abi49_0_0.com.reactnativepagerview.event.PageSelectedEvent + + +class PagerViewViewManager : ViewGroupManager() { + private lateinit var eventDispatcher: EventDispatcher + + override fun getName(): String { + return PagerViewViewManagerImpl.NAME + } + + override fun createViewInstance(reactContext: ThemedReactContext): NestedScrollableHost { + val host = NestedScrollableHost(reactContext) + host.id = View.generateViewId() + host.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + host.isSaveEnabled = false + val vp = ViewPager2(reactContext) + vp.adapter = ViewPagerAdapter() + //https://github.com/callstack/react-native-viewpager/issues/183 + vp.isSaveEnabled = false + eventDispatcher = reactContext.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher + + vp.post { + vp.registerOnPageChangeCallback(object : OnPageChangeCallback() { + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + super.onPageScrolled(position, positionOffset, positionOffsetPixels) + eventDispatcher.dispatchEvent( + PageScrollEvent(host.id, position, positionOffset)) + } + + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + eventDispatcher.dispatchEvent( + PageSelectedEvent(host.id, position)) + } + + override fun onPageScrollStateChanged(state: Int) { + super.onPageScrollStateChanged(state) + val pageScrollState: String = when (state) { + ViewPager2.SCROLL_STATE_IDLE -> "idle" + ViewPager2.SCROLL_STATE_DRAGGING -> "dragging" + ViewPager2.SCROLL_STATE_SETTLING -> "settling" + else -> throw IllegalStateException("Unsupported pageScrollState") + } + eventDispatcher.dispatchEvent( + PageScrollStateChangedEvent(host.id, pageScrollState)) + } + }) + + eventDispatcher.dispatchEvent(PageSelectedEvent(host.id, vp.currentItem)) + } + host.addView(vp) + return host + } + + override fun addView(host: NestedScrollableHost, child: View?, index: Int) { + PagerViewViewManagerImpl.addView(host, child, index) + } + + override fun getChildCount(parent: NestedScrollableHost) = PagerViewViewManagerImpl.getChildCount(parent) + + override fun getChildAt(parent: NestedScrollableHost, index: Int): View { + return PagerViewViewManagerImpl.getChildAt(parent, index) + } + + override fun removeView(parent: NestedScrollableHost, view: View) { + PagerViewViewManagerImpl.removeView(parent, view) + } + + override fun removeAllViews(parent: NestedScrollableHost) { + PagerViewViewManagerImpl.removeAllViews(parent) + } + + override fun removeViewAt(parent: NestedScrollableHost, index: Int) { + PagerViewViewManagerImpl.removeViewAt(parent, index) + } + + override fun needsCustomLayoutForChildren(): Boolean { + return PagerViewViewManagerImpl.needsCustomLayoutForChildren() + } + + @ReactProp(name = "scrollEnabled", defaultBoolean = true) + fun setScrollEnabled(host: NestedScrollableHost, value: Boolean) { + PagerViewViewManagerImpl.setScrollEnabled(host, value) + } + + @ReactProp(name = "initialPage", defaultInt = 0) + fun setInitialPage(host: NestedScrollableHost, value: Int) { + PagerViewViewManagerImpl.setInitialPage(host, value) + } + + @ReactProp(name = "orientation") + fun setOrientation(host: NestedScrollableHost, value: String) { + PagerViewViewManagerImpl.setOrientation(host, value) + } + + @ReactProp(name = "offscreenPageLimit", defaultInt = ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT) + operator fun set(host: NestedScrollableHost, value: Int) { + PagerViewViewManagerImpl.setOffscreenPageLimit(host, value) + } + + @ReactProp(name = "overScrollMode") + fun setOverScrollMode(host: NestedScrollableHost, value: String) { + PagerViewViewManagerImpl.setOverScrollMode(host, value) + } + + @ReactProp(name = "layoutDirection") + fun setLayoutDirection(host: NestedScrollableHost, value: String) { + PagerViewViewManagerImpl.setLayoutDirection(host, value) + } + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap> { + return MapBuilder.of( + PageScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScroll"), + PageScrollStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScrollStateChanged"), + PageSelectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageSelected")) + } + + override fun receiveCommand(root: NestedScrollableHost, commandId: String?, args: ReadableArray?) { + super.receiveCommand(root, commandId, args) + val view = PagerViewViewManagerImpl.getViewPager(root) + Assertions.assertNotNull(view) + Assertions.assertNotNull(args) + val childCount = view.adapter?.itemCount + + when (commandId) { + COMMAND_SET_PAGE, COMMAND_SET_PAGE_WITHOUT_ANIMATION -> { + val pageIndex = args!!.getInt(0) + val canScroll = childCount != null && childCount > 0 && pageIndex >= 0 && pageIndex < childCount + if (canScroll) { + val scrollWithAnimation = commandId == COMMAND_SET_PAGE + PagerViewViewManagerImpl.setCurrentItem(view, pageIndex, scrollWithAnimation) + eventDispatcher.dispatchEvent(PageSelectedEvent(root.id, pageIndex)) + } + } + COMMAND_SET_SCROLL_ENABLED -> { + view.isUserInputEnabled = args!!.getBoolean(0) + } + else -> throw IllegalArgumentException(String.format( + "Unsupported command %d received by %s.", + commandId, + javaClass.simpleName)) + } + } + + @ReactProp(name = "pageMargin", defaultInt = 0) + fun setPageMargin(host: NestedScrollableHost, margin: Int) { + PagerViewViewManagerImpl.setPageMargin(host, margin) + } + + companion object { + private const val COMMAND_SET_PAGE = "setPage" + private const val COMMAND_SET_PAGE_WITHOUT_ANIMATION = "setPageWithoutAnimation" + private const val COMMAND_SET_SCROLL_ENABLED = "setScrollEnabledImperatively" + } +} + diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/AnimatedSensor/AnimatedSensorModule.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/AnimatedSensor/AnimatedSensorModule.cpp new file mode 100644 index 00000000000000..f2600661517509 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/AnimatedSensor/AnimatedSensorModule.cpp @@ -0,0 +1,88 @@ +#include "AnimatedSensorModule.h" + +#include +#include + +#include "Shareables.h" + +namespace reanimated { + +AnimatedSensorModule::AnimatedSensorModule( + const PlatformDepMethodsHolder &platformDepMethodsHolder) + : platformRegisterSensorFunction_(platformDepMethodsHolder.registerSensor), + platformUnregisterSensorFunction_( + platformDepMethodsHolder.unregisterSensor) {} + +AnimatedSensorModule::~AnimatedSensorModule() { + assert(sensorsIds_.empty()); +} + +jsi::Value AnimatedSensorModule::registerSensor( + jsi::Runtime &rt, + const std::shared_ptr &runtimeHelper, + const jsi::Value &sensorTypeValue, + const jsi::Value &interval, + const jsi::Value &iosReferenceFrame, + const jsi::Value &sensorDataHandler) { + SensorType sensorType = static_cast(sensorTypeValue.asNumber()); + + auto shareableHandler = extractShareableOrThrow(rt, sensorDataHandler); + + int sensorId = platformRegisterSensorFunction_( + sensorType, + interval.asNumber(), + iosReferenceFrame.asNumber(), + [sensorType, + shareableHandler, + weakRuntimeHelper = std::weak_ptr(runtimeHelper)]( + double newValues[], int orientationDegrees) { + auto runtimeHelper = weakRuntimeHelper.lock(); + if (runtimeHelper == nullptr || runtimeHelper->uiRuntimeDestroyed) { + return; + } + + auto &rt = *runtimeHelper->uiRuntime(); + auto handler = shareableHandler->getJSValue(rt); + if (sensorType == SensorType::ROTATION_VECTOR) { + jsi::Object value(rt); + // TODO: timestamp should be provided by the platform implementation + // such that the native side has a chance of providing a true event + // timestamp + value.setProperty(rt, "qx", newValues[0]); + value.setProperty(rt, "qy", newValues[1]); + value.setProperty(rt, "qz", newValues[2]); + value.setProperty(rt, "qw", newValues[3]); + value.setProperty(rt, "yaw", newValues[4]); + value.setProperty(rt, "pitch", newValues[5]); + value.setProperty(rt, "roll", newValues[6]); + value.setProperty(rt, "interfaceOrientation", orientationDegrees); + runtimeHelper->runOnUIGuarded(handler, value); + } else { + jsi::Object value(rt); + value.setProperty(rt, "x", newValues[0]); + value.setProperty(rt, "y", newValues[1]); + value.setProperty(rt, "z", newValues[2]); + value.setProperty(rt, "interfaceOrientation", orientationDegrees); + runtimeHelper->runOnUIGuarded(handler, value); + } + }); + if (sensorId != -1) { + sensorsIds_.insert(sensorId); + } + return jsi::Value(sensorId); +} + +void AnimatedSensorModule::unregisterSensor(const jsi::Value &sensorId) { + // It is called during sensor hook unmounting + sensorsIds_.erase(sensorId.getNumber()); + platformUnregisterSensorFunction_(sensorId.asNumber()); +} + +void AnimatedSensorModule::unregisterAllSensors() { + for (auto sensorId : sensorsIds_) { + platformUnregisterSensorFunction_(sensorId); + } + sensorsIds_.clear(); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/AnimatedSensor/AnimatedSensorModule.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/AnimatedSensor/AnimatedSensorModule.h new file mode 100644 index 00000000000000..69c4878a4dab4e --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/AnimatedSensor/AnimatedSensorModule.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +#include "PlatformDepMethodsHolder.h" +#include "RuntimeManager.h" +#include "Shareables.h" + +namespace reanimated { + +using namespace facebook; + +enum SensorType { + ACCELEROMETER = 1, + GYROSCOPE = 2, + GRAVITY = 3, + MAGNETIC_FIELD = 4, + ROTATION_VECTOR = 5, +}; + +class AnimatedSensorModule { + std::unordered_set sensorsIds_; + RegisterSensorFunction platformRegisterSensorFunction_; + UnregisterSensorFunction platformUnregisterSensorFunction_; + + public: + AnimatedSensorModule( + const PlatformDepMethodsHolder &platformDepMethodsHolder); + ~AnimatedSensorModule(); + + jsi::Value registerSensor( + jsi::Runtime &rt, + const std::shared_ptr &runtimeHelper, + const jsi::Value &sensorType, + const jsi::Value &interval, + const jsi::Value &iosReferenceFrame, + const jsi::Value &sensorDataContainer); + void unregisterSensor(const jsi::Value &sensorId); + void unregisterAllSensors(); +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/FabricUtils.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/FabricUtils.cpp new file mode 100644 index 00000000000000..f8d868a4e0ee0d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/FabricUtils.cpp @@ -0,0 +1,29 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#include "FabricUtils.h" + +#include +#include + +using namespace facebook::react; + +namespace reanimated { + +#ifdef ANDROID +RuntimeExecutor getRuntimeExecutorFromBinding(Binding *binding) { + BindingPublic *bindingPublic = reinterpret_cast(binding); + SchedulerPublic *schedulerPublic = + reinterpret_cast((bindingPublic->scheduler_).get()); + return schedulerPublic->runtimeExecutor_; +} +#endif + +std::shared_ptr getContextContainerFromUIManager( + const UIManager *uiManager) { + return reinterpret_cast(uiManager) + ->contextContainer_; +} + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/FabricUtils.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/FabricUtils.h new file mode 100644 index 00000000000000..923b327045c7c9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/FabricUtils.h @@ -0,0 +1,58 @@ +#pragma once +#ifdef RCT_NEW_ARCH_ENABLED + +#ifdef ANDROID +#include +#include +#endif +#include + +#include +#include + +using namespace facebook; +using namespace react; + +namespace reanimated { + +struct UIManagerBindingPublic { + void *vtable; + std::shared_ptr uiManager_; + std::unique_ptr eventHandler_; +}; + +struct UIManagerPublic { + void *vtable; + SharedComponentDescriptorRegistry componentDescriptorRegistry_; + UIManagerDelegate *delegate_; + UIManagerAnimationDelegate *animationDelegate_{nullptr}; + RuntimeExecutor const runtimeExecutor_{}; + ShadowTreeRegistry shadowTreeRegistry_{}; + BackgroundExecutor const backgroundExecutor_{}; + ContextContainer::Shared contextContainer_; +}; + +#ifdef ANDROID +struct BindingPublic : public jni::HybridClass, + public SchedulerDelegate, + public LayoutAnimationStatusDelegate { + std::shared_mutex installMutex_; + std::shared_ptr mountingManager_; + std::shared_ptr scheduler_; +}; + +struct SchedulerPublic : public UIManagerDelegate { + SchedulerDelegate *delegate_; + SharedComponentDescriptorRegistry componentDescriptorRegistry_; + RuntimeExecutor runtimeExecutor_; +}; + +RuntimeExecutor getRuntimeExecutorFromBinding(Binding *binding); +#endif + +std::shared_ptr getContextContainerFromUIManager( + const UIManager *uiManager); + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ReanimatedUIManagerBinding.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ReanimatedUIManagerBinding.cpp new file mode 100644 index 00000000000000..a847614cae78c6 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ReanimatedUIManagerBinding.cpp @@ -0,0 +1,239 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#include "ReanimatedUIManagerBinding.h" +#include "FabricUtils.h" +#include "NewestShadowNodesRegistry.h" + +#include + +#include + +using namespace facebook; +using namespace react; + +namespace reanimated { + +void ReanimatedUIManagerBinding::createAndInstallIfNeeded( + jsi::Runtime &runtime, + RuntimeExecutor const &runtimeExecutor, + std::shared_ptr const &uiManager, + std::shared_ptr const + &newestShadowNodesRegistry) { + // adapted from UIManagerBinding.cpp + auto uiManagerModuleName = "nativeFabricUIManager"; + + auto eventHandler = [&]() -> std::unique_ptr { + auto uiManagerValue = + runtime.global().getProperty(runtime, uiManagerModuleName); + if (uiManagerValue.isUndefined()) { + return nullptr; + } + + auto uiManagerBinding = + uiManagerValue.asObject(runtime).asHostObject( + runtime); + auto uiManagerBindingPublic = + reinterpret_cast(&*uiManagerBinding); + return std::move(uiManagerBindingPublic->eventHandler_); + }(); + + auto reanimatedUiManagerBinding = + std::make_shared( + uiManager, + runtimeExecutor, + std::move(eventHandler), + newestShadowNodesRegistry); + auto object = + jsi::Object::createFromHostObject(runtime, reanimatedUiManagerBinding); + runtime.global().setProperty(runtime, uiManagerModuleName, std::move(object)); +} + +ReanimatedUIManagerBinding::ReanimatedUIManagerBinding( + std::shared_ptr uiManager, + RuntimeExecutor runtimeExecutor, + std::unique_ptr eventHandler, + std::shared_ptr newestShadowNodesRegistry) + : UIManagerBinding(uiManager), + uiManager_(std::move(uiManager)), + newestShadowNodesRegistry_(newestShadowNodesRegistry) { + if (eventHandler != nullptr) { + reinterpret_cast(this)->eventHandler_ = + std::move(eventHandler); + } +} + +ReanimatedUIManagerBinding::~ReanimatedUIManagerBinding() {} + +static inline ShadowNode::Shared cloneNodeUsingNewest( + UIManager *uiManager, + NewestShadowNodesRegistry *newestShadowNodesRegistry, + ShadowNode const &shadowNode, + ShadowNode::SharedListOfShared const &children = nullptr, + RawProps const *rawProps = nullptr) { + { + auto lock = newestShadowNodesRegistry->createLock(); + auto newest = newestShadowNodesRegistry->get(shadowNode.getTag()); + if (newest != nullptr) { + // ShadowNode managed by Reanimated, use newest ShadowNode from registry + auto clone = uiManager->cloneNode(*newest, children, rawProps); + newestShadowNodesRegistry->update(clone); + return clone; + } + } // release lock since we don't need registry anymore + + // ShadowNode not managed by Reanimated (yet?) + return uiManager->cloneNode(shadowNode, children, rawProps); +} + +static inline void appendChildUsingNewest( + UIManager *uiManager, + NewestShadowNodesRegistry *newestShadowNodesRegistry, + const ShadowNode::Shared &parentShadowNode, + const ShadowNode::Shared &childShadowNode) { + { + auto lock = newestShadowNodesRegistry->createLock(); + auto newestChildShadowNode = + newestShadowNodesRegistry->get(childShadowNode->getTag()); + if (newestChildShadowNode != nullptr) { + uiManager->appendChild(parentShadowNode, newestChildShadowNode); + return; + } + } // release lock since we don't need registry anymore + + // child ShadowNode not managed by Reanimated (yet?) + uiManager->appendChild(parentShadowNode, childShadowNode); +} + +jsi::Value ReanimatedUIManagerBinding::get( + jsi::Runtime &runtime, + jsi::PropNameID const &name) { + // Currently, we need to overwrite all variants of `cloneNode` as well as + // `appendChild` to prevent React from overwriting layout props animated using + // Reanimated. However, this may degrade performance due to using locks. + // We already have an idea how this can be done better without locks + // (i.e. by overwriting `completeRoot` and using UIManagerCommitHooks). + + // based on implementation from UIManagerBinding.cpp + auto methodName = name.utf8(runtime); + SystraceSection s("ReanimatedUIManagerBinding::get", "name", methodName); + UIManager *uiManager = uiManager_.get(); + NewestShadowNodesRegistry *newestShadowNodesRegistry = + newestShadowNodesRegistry_.get(); + + // Semantic: Clones the node with *same* props and *same* children. + if (methodName == "cloneNode") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 1, + [uiManager, newestShadowNodesRegistry]( + jsi::Runtime &runtime, + jsi::Value const & /*thisValue*/, + jsi::Value const *arguments, + size_t /*count*/) noexcept -> jsi::Value { + return valueFromShadowNode( + runtime, + cloneNodeUsingNewest( + uiManager, + newestShadowNodesRegistry, + *shadowNodeFromValue(runtime, arguments[0]))); + }); + } + + // Semantic: Clones the node with *same* props and *empty* children. + if (methodName == "cloneNodeWithNewChildren") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 1, + [uiManager, newestShadowNodesRegistry]( + jsi::Runtime &runtime, + jsi::Value const & /*thisValue*/, + jsi::Value const *arguments, + size_t /*count*/) noexcept -> jsi::Value { + return valueFromShadowNode( + runtime, + cloneNodeUsingNewest( + uiManager, + newestShadowNodesRegistry, + *shadowNodeFromValue(runtime, arguments[0]), + ShadowNode::emptySharedShadowNodeSharedList())); + }); + } + + // Semantic: Clones the node with *given* props and *same* children. + if (methodName == "cloneNodeWithNewProps") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 2, + [uiManager, newestShadowNodesRegistry]( + jsi::Runtime &runtime, + jsi::Value const & /*thisValue*/, + jsi::Value const *arguments, + size_t /*count*/) noexcept -> jsi::Value { + auto const &rawProps = RawProps(runtime, arguments[1]); + return valueFromShadowNode( + runtime, + cloneNodeUsingNewest( + uiManager, + newestShadowNodesRegistry, + *shadowNodeFromValue(runtime, arguments[0]), + nullptr, + &rawProps)); + }); + } + + // Semantic: Clones the node with *given* props and *empty* children. + if (methodName == "cloneNodeWithNewChildrenAndProps") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 2, + [uiManager, newestShadowNodesRegistry]( + jsi::Runtime &runtime, + jsi::Value const & /*thisValue*/, + jsi::Value const *arguments, + size_t /*count*/) noexcept -> jsi::Value { + auto const &rawProps = RawProps(runtime, arguments[1]); + return valueFromShadowNode( + runtime, + cloneNodeUsingNewest( + uiManager, + newestShadowNodesRegistry, + *shadowNodeFromValue(runtime, arguments[0]), + ShadowNode::emptySharedShadowNodeSharedList(), + &rawProps)); + }); + } + + if (methodName == "appendChild") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 2, + [uiManager, newestShadowNodesRegistry]( + jsi::Runtime &runtime, + jsi::Value const & /*thisValue*/, + jsi::Value const *arguments, + size_t /*count*/) noexcept -> jsi::Value { + appendChildUsingNewest( + uiManager, + newestShadowNodesRegistry, + shadowNodeFromValue(runtime, arguments[0]), + shadowNodeFromValue(runtime, arguments[1])); + return jsi::Value::undefined(); + }); + } + + // Methods like "findNodeAtPoint", "getRelativeLayoutMetrics", "measure" etc. + // use `UIManager::getNewestCloneOfShadowNode` or + // `ShadowTree::getCurrentRevision` under the hood, + // so there's no need to overwrite them. + + return UIManagerBinding::get(runtime, name); +} + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ReanimatedUIManagerBinding.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ReanimatedUIManagerBinding.h new file mode 100644 index 00000000000000..70fe2a2e74f99e --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ReanimatedUIManagerBinding.h @@ -0,0 +1,47 @@ +#pragma once +#ifdef RCT_NEW_ARCH_ENABLED + +#include +#include +#include +#include +#include + +#include + +#include "NewestShadowNodesRegistry.h" + +using namespace facebook; +using namespace react; + +namespace reanimated { + +class ReanimatedUIManagerBinding : public UIManagerBinding { + public: + static void createAndInstallIfNeeded( + jsi::Runtime &runtime, + RuntimeExecutor const &runtimeExecutor, + std::shared_ptr const &uiManager, + std::shared_ptr const + &newestShadowNodesRegistry); + + ReanimatedUIManagerBinding( + std::shared_ptr uiManager, + RuntimeExecutor runtimeExecutor, + std::unique_ptr eventHandler, + std::shared_ptr newestShadowNodesRegistry); + + ~ReanimatedUIManagerBinding(); + + void invalidate() const; + + jsi::Value get(jsi::Runtime &runtime, jsi::PropNameID const &name) override; + + private: + std::shared_ptr uiManager_; + std::shared_ptr newestShadowNodesRegistry_; +}; + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ShadowTreeCloner.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ShadowTreeCloner.cpp new file mode 100644 index 00000000000000..4ff212fdc7f806 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ShadowTreeCloner.cpp @@ -0,0 +1,92 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#include "ShadowTreeCloner.h" +#include "FabricUtils.h" + +namespace reanimated { + +ShadowTreeCloner::ShadowTreeCloner( + std::shared_ptr newestShadowNodesRegistry, + std::shared_ptr uiManager, + SurfaceId surfaceId) + : newestShadowNodesRegistry_{newestShadowNodesRegistry}, + propsParserContext_{ + surfaceId, + *getContextContainerFromUIManager(&*uiManager)} {} + +ShadowTreeCloner::~ShadowTreeCloner() { +#ifdef DEBUG + react_native_assert( + yogaChildrenUpdates_.empty() && + "Deallocating `ShadowTreeCloner` without calling `updateYogaChildren`."); +#endif +} + +ShadowNode::Unshared ShadowTreeCloner::cloneWithNewProps( + const ShadowNode::Shared &oldRootNode, + const ShadowNodeFamily &family, + RawProps &&rawProps) { + // adapted from ShadowNode::cloneTree + + auto ancestors = family.getAncestors(*oldRootNode); + + if (ancestors.empty()) { + return ShadowNode::Unshared{nullptr}; + } + + auto &parent = ancestors.back(); + auto &oldShadowNode = parent.first.get().getChildren().at(parent.second); + + const auto newest = newestShadowNodesRegistry_->get(oldShadowNode->getTag()); + + const auto &source = newest == nullptr ? oldShadowNode : newest; + + const auto props = source->getComponentDescriptor().cloneProps( + propsParserContext_, source->getProps(), rawProps); + + auto newChildNode = source->clone({/* .props = */ props}); + + for (auto it = ancestors.rbegin(); it != ancestors.rend(); ++it) { + auto &parentNode = it->first.get(); + auto childIndex = it->second; + + auto children = parentNode.getChildren(); + const auto &oldChildNode = *children.at(childIndex); + react_native_assert(ShadowNode::sameFamily(oldChildNode, *newChildNode)); + + newestShadowNodesRegistry_->set(newChildNode, parentNode.getTag()); + + if (!parentNode.getSealed()) { + // Optimization: if a ShadowNode is unsealed, we can directly update its + // children instead of cloning the whole path to the root node. + auto &parentNodeNonConst = const_cast(parentNode); + parentNodeNonConst.replaceChild(oldChildNode, newChildNode, childIndex); + yogaChildrenUpdates_.insert(&parentNodeNonConst); + return std::const_pointer_cast(oldRootNode); + } + + children[childIndex] = newChildNode; + + newChildNode = parentNode.clone({ + ShadowNodeFragment::propsPlaceholder(), + std::make_shared(children), + }); + } + + return std::const_pointer_cast(newChildNode); +} + +void ShadowTreeCloner::updateYogaChildren() { + // Unfortunately, `replaceChild` does not update Yoga nodes, so we need to + // update them manually here. + for (ShadowNode *shadowNode : yogaChildrenUpdates_) { + static_cast(shadowNode)->updateYogaChildren(); + } +#ifdef DEBUG + yogaChildrenUpdates_.clear(); +#endif +} + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ShadowTreeCloner.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ShadowTreeCloner.h new file mode 100644 index 00000000000000..12cbebcd139b87 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Fabric/ShadowTreeCloner.h @@ -0,0 +1,41 @@ +#pragma once +#ifdef RCT_NEW_ARCH_ENABLED + +#include +#include + +#include +#include + +#include "NewestShadowNodesRegistry.h" + +using namespace facebook; +using namespace react; + +namespace reanimated { + +class ShadowTreeCloner { + public: + ShadowTreeCloner( + std::shared_ptr newestShadowNodesRegistry, + std::shared_ptr uiManager, + SurfaceId surfaceId); + + ~ShadowTreeCloner(); + + ShadowNode::Unshared cloneWithNewProps( + const ShadowNode::Shared &oldRootNode, + const ShadowNodeFamily &family, + RawProps &&rawProps); + + void updateYogaChildren(); + + private: + std::shared_ptr newestShadowNodesRegistry_; + PropsParserContext propsParserContext_; + std::set yogaChildrenUpdates_; +}; + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationType.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationType.h new file mode 100644 index 00000000000000..2579c385c03cdd --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationType.h @@ -0,0 +1,8 @@ +#pragma once + +typedef enum LayoutAnimationType { + ENTERING = 1, + EXITING = 2, + LAYOUT = 3, + SHARED_ELEMENT_TRANSITION = 4 +} LayoutAnimationType; diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationsManager.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationsManager.cpp new file mode 100644 index 00000000000000..57d86adc2e104b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationsManager.cpp @@ -0,0 +1,131 @@ +#include "LayoutAnimationsManager.h" +#include "CollectionUtils.h" +#include "Shareables.h" + +#include + +namespace reanimated { + +void LayoutAnimationsManager::configureAnimation( + int tag, + LayoutAnimationType type, + const std::string &sharedTransitionTag, + std::shared_ptr config) { + auto lock = std::unique_lock(animationsMutex_); + getConfigsForType(type)[tag] = config; + if (type == SHARED_ELEMENT_TRANSITION) { + sharedTransitionGroups_[sharedTransitionTag].push_back(tag); + viewTagToSharedTag_[tag] = sharedTransitionTag; + } +} + +bool LayoutAnimationsManager::hasLayoutAnimation( + int tag, + LayoutAnimationType type) { + auto lock = std::unique_lock(animationsMutex_); + return collection::contains(getConfigsForType(type), tag); +} + +void LayoutAnimationsManager::clearLayoutAnimationConfig(int tag) { + auto lock = std::unique_lock(animationsMutex_); + enteringAnimations_.erase(tag); + exitingAnimations_.erase(tag); + layoutAnimations_.erase(tag); + + sharedTransitionAnimations_.erase(tag); + auto const &groupName = viewTagToSharedTag_[tag]; + auto &group = sharedTransitionGroups_[groupName]; + auto position = std::find(group.begin(), group.end(), tag); + if (position != group.end()) { + group.erase(position); + } + if (group.size() == 0) { + sharedTransitionGroups_.erase(groupName); + } + viewTagToSharedTag_.erase(tag); +} + +void LayoutAnimationsManager::startLayoutAnimation( + jsi::Runtime &rt, + int tag, + LayoutAnimationType type, + const jsi::Object &values) { + std::shared_ptr config, viewShareable; + { + auto lock = std::unique_lock(animationsMutex_); + config = getConfigsForType(type)[tag]; + } + // TODO: cache the following!! + jsi::Value layoutAnimationRepositoryAsValue = + rt.global() + .getPropertyAsObject(rt, "global") + .getProperty(rt, "LayoutAnimationsManager"); + jsi::Function startAnimationForTag = + layoutAnimationRepositoryAsValue.getObject(rt).getPropertyAsFunction( + rt, "start"); + startAnimationForTag.call( + rt, + jsi::Value(tag), + jsi::Value(static_cast(type)), + values, + config->getJSValue(rt)); +} + +void LayoutAnimationsManager::cancelLayoutAnimation( + jsi::Runtime &rt, + int tag, + LayoutAnimationType type, + bool cancelled = true, + bool removeView = true) { + jsi::Value layoutAnimationRepositoryAsValue = + rt.global() + .getPropertyAsObject(rt, "global") + .getProperty(rt, "LayoutAnimationsManager"); + jsi::Function cancelLayoutAnimation = + layoutAnimationRepositoryAsValue.getObject(rt).getPropertyAsFunction( + rt, "stop"); + std::shared_ptr config; + { + auto lock = std::unique_lock(animationsMutex_); + config = sharedTransitionAnimations_[tag]; + } + if (config != nullptr) { + cancelLayoutAnimation.call( + rt, jsi::Value(tag), config->getJSValue(rt), cancelled, removeView); + } +} + +/* + The top screen on the stack triggers the animation, so we need to find + the sibling view registered in the past. This method finds view + registered in the same transition group (with the same transition tag) + which has been added to that group directly before the one that we + provide as an argument. +*/ +int LayoutAnimationsManager::findPrecedingViewTagForTransition(int tag) { + auto const &groupName = viewTagToSharedTag_[tag]; + auto const &group = sharedTransitionGroups_[groupName]; + auto position = std::find(group.begin(), group.end(), tag); + if (position != group.end() && position != group.begin()) { + return *std::prev(position); + } + return -1; +} + +std::unordered_map> + &LayoutAnimationsManager::getConfigsForType(LayoutAnimationType type) { + switch (type) { + case ENTERING: + return enteringAnimations_; + case EXITING: + return exitingAnimations_; + case LAYOUT: + return layoutAnimations_; + case SHARED_ELEMENT_TRANSITION: + return sharedTransitionAnimations_; + default: + assert(false); + } +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationsManager.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationsManager.h new file mode 100644 index 00000000000000..f7cadca6c7dd63 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/LayoutAnimations/LayoutAnimationsManager.h @@ -0,0 +1,58 @@ +#pragma once + +#include "ErrorHandler.h" +#include "LayoutAnimationType.h" +#include "Shareables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace reanimated { + +using namespace facebook; + +class LayoutAnimationsManager { + public: + void configureAnimation( + int tag, + LayoutAnimationType type, + const std::string &sharedTransitionTag, + std::shared_ptr config); + bool hasLayoutAnimation(int tag, LayoutAnimationType type); + void startLayoutAnimation( + jsi::Runtime &rt, + int tag, + LayoutAnimationType type, + const jsi::Object &values); + void clearLayoutAnimationConfig(int tag); + void cancelLayoutAnimation( + jsi::Runtime &rt, + int tag, + LayoutAnimationType type, + bool cancelled /* = true */, + bool removeView /* = true */); + int findPrecedingViewTagForTransition(int tag); + + private: + std::unordered_map> &getConfigsForType( + LayoutAnimationType type); + + std::unordered_map> enteringAnimations_; + std::unordered_map> exitingAnimations_; + std::unordered_map> layoutAnimations_; + std::unordered_map> + sharedTransitionAnimations_; + std::unordered_map> sharedTransitionGroups_; + std::unordered_map viewTagToSharedTag_; + mutable std::mutex + animationsMutex_; // Protects `enteringAnimations_`, `exitingAnimations_`, + // `layoutAnimations_` and `viewSharedValues_`. +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModule.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModule.cpp new file mode 100644 index 00000000000000..5e4c7b6c409581 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModule.cpp @@ -0,0 +1,688 @@ +#include "NativeReanimatedModule.h" + +#ifdef RCT_NEW_ARCH_ENABLED +#include +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef RCT_NEW_ARCH_ENABLED +#include "FabricUtils.h" +#include "NewestShadowNodesRegistry.h" +#include "ReanimatedUIManagerBinding.h" +#include "ShadowTreeCloner.h" +#endif + +#include "EventHandlerRegistry.h" +#include "FeaturesConfig.h" +#include "ReanimatedHiddenHeaders.h" +#include "RuntimeDecorator.h" +#include "Shareables.h" +#include "WorkletEventHandler.h" + +using namespace facebook; + +namespace reanimated { + +NativeReanimatedModule::NativeReanimatedModule( + const std::shared_ptr &jsInvoker, + const std::shared_ptr &scheduler, + const std::shared_ptr &rt, + const std::shared_ptr &errorHandler, +#ifdef RCT_NEW_ARCH_ENABLED +// nothing +#else + std::function + propObtainer, +#endif + PlatformDepMethodsHolder platformDepMethodsHolder) + : NativeReanimatedModuleSpec(jsInvoker), + RuntimeManager(rt, errorHandler, scheduler, RuntimeType::UI), + eventHandlerRegistry(std::make_unique()), + requestRender(platformDepMethodsHolder.requestRender), +#ifdef RCT_NEW_ARCH_ENABLED +// nothing +#else + propObtainer(propObtainer), +#endif + animatedSensorModule(platformDepMethodsHolder), +#ifdef RCT_NEW_ARCH_ENABLED + synchronouslyUpdateUIPropsFunction( + platformDepMethodsHolder.synchronouslyUpdateUIPropsFunction) +#else + configurePropsPlatformFunction( + platformDepMethodsHolder.configurePropsFunction) +#endif +{ + auto requestAnimationFrame = [=](jsi::Runtime &rt, const jsi::Value &fn) { + auto jsFunction = std::make_shared(rt, fn); + frameCallbacks.push_back([=](double timestamp) { + runtimeHelper->runOnUIGuarded(*jsFunction, jsi::Value(timestamp)); + }); + maybeRequestRender(); + }; + + auto scheduleOnJS = [this]( + jsi::Runtime &rt, + const jsi::Value &remoteFun, + const jsi::Value &argsValue) { + auto shareableRemoteFun = extractShareableOrThrow( + rt, + remoteFun, + "Incompatible object passed to scheduleOnJS. It is only allowed to schedule functions defined on the React Native JS runtime this way."); + auto shareableArgs = argsValue.isUndefined() + ? nullptr + : extractShareableOrThrow(rt, argsValue); + auto jsRuntime = this->runtimeHelper->rnRuntime(); + this->scheduler->scheduleOnJS([=] { + jsi::Runtime &rt = *jsRuntime; + auto remoteFun = shareableRemoteFun->getJSValue(rt); + if (shareableArgs == nullptr) { + // fast path for remote function w/o arguments + remoteFun.asObject(rt).asFunction(rt).call(rt); + } else { + auto argsArray = shareableArgs->getJSValue(rt).asObject(rt).asArray(rt); + auto argsSize = argsArray.size(rt); + // number of arguments is typically relatively small so it is ok to + // to use VLAs here, hence disabling the lint rule + jsi::Value args[argsSize]; // NOLINT(runtime/arrays) + for (size_t i = 0; i < argsSize; i++) { + args[i] = argsArray.getValueAtIndex(rt, i); + } + remoteFun.asObject(rt).asFunction(rt).call(rt, args, argsSize); + } + }); + }; + + auto makeShareableClone = [this](jsi::Runtime &rt, const jsi::Value &value) { + return this->makeShareableClone(rt, value, jsi::Value::undefined()); + }; + + auto updateDataSynchronously = + [this]( + jsi::Runtime &rt, + const jsi::Value &synchronizedDataHolderRef, + const jsi::Value &newData) { + return this->updateDataSynchronously( + rt, synchronizedDataHolderRef, newData); + }; + +#ifdef RCT_NEW_ARCH_ENABLED + auto updateProps = [this]( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue, + const jsi::Value &props) { + this->updateProps(rt, shadowNodeValue, props); + }; + + auto removeShadowNodeFromRegistry = + [this](jsi::Runtime &rt, const jsi::Value &tag) { + this->removeShadowNodeFromRegistry(rt, tag); + }; + + auto measure = [this](jsi::Runtime &rt, const jsi::Value &shadowNodeValue) { + return this->measure(rt, shadowNodeValue); + }; + + auto dispatchCommand = [this]( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue, + const jsi::Value &commandNameValue, + const jsi::Value &argsValue) { + this->dispatchCommand(rt, shadowNodeValue, commandNameValue, argsValue); + }; +#endif + + RuntimeDecorator::decorateUIRuntime( + *runtime, +#ifdef RCT_NEW_ARCH_ENABLED + updateProps, + measure, + removeShadowNodeFromRegistry, + dispatchCommand, +#else + platformDepMethodsHolder.updatePropsFunction, + platformDepMethodsHolder.measureFunction, + platformDepMethodsHolder.scrollToFunction, +#endif + requestAnimationFrame, + scheduleOnJS, + makeShareableClone, + updateDataSynchronously, + platformDepMethodsHolder.getCurrentTime, + platformDepMethodsHolder.setGestureStateFunction, + platformDepMethodsHolder.progressLayoutAnimation, + platformDepMethodsHolder.endLayoutAnimation, + platformDepMethodsHolder.maybeFlushUIUpdatesQueueFunction); + onRenderCallback = [this](double timestampMs) { + this->renderRequested = false; + this->onRender(timestampMs); + }; + +#ifdef RCT_NEW_ARCH_ENABLED + // nothing +#else + updatePropsFunction = platformDepMethodsHolder.updatePropsFunction; +#endif + subscribeForKeyboardEventsFunction = + platformDepMethodsHolder.subscribeForKeyboardEvents; + unsubscribeFromKeyboardEventsFunction = + platformDepMethodsHolder.unsubscribeFromKeyboardEvents; +} + +void NativeReanimatedModule::installCoreFunctions( + jsi::Runtime &rt, + const jsi::Value &callGuard, + const jsi::Value &valueUnpacker) { + if (!runtimeHelper) { + // initialize runtimeHelper here if not already present. We expect only one + // instace of the helper to exists. + runtimeHelper = + std::make_shared(&rt, this->runtime.get(), scheduler); + } + runtimeHelper->callGuard = + std::make_unique(runtimeHelper.get(), callGuard); + runtimeHelper->valueUnpacker = + std::make_unique(runtimeHelper.get(), valueUnpacker); +} + +NativeReanimatedModule::~NativeReanimatedModule() { + if (runtimeHelper) { + runtimeHelper->callGuard = nullptr; + runtimeHelper->valueUnpacker = nullptr; + // event handler registry and frame callbacks store some JSI values from UI + // runtime, so they have to go away before we tear down the runtime + eventHandlerRegistry.reset(); + frameCallbacks.clear(); + runtime.reset(); + // make sure uiRuntimeDestroyed is set after the runtime is deallocated + runtimeHelper->uiRuntimeDestroyed = true; + } +} + +void NativeReanimatedModule::scheduleOnUI( + jsi::Runtime &rt, + const jsi::Value &worklet) { + auto shareableWorklet = extractShareableOrThrow(rt, worklet); + assert( + shareableWorklet->valueType() == Shareable::WorkletType && + "only worklets can be scheduled to run on UI"); + scheduler->scheduleOnUI([=] { + jsi::Runtime &rt = *runtimeHelper->uiRuntime(); + auto workletValue = shareableWorklet->getJSValue(rt); + runtimeHelper->runOnUIGuarded(workletValue); + }); +} + +jsi::Value NativeReanimatedModule::makeSynchronizedDataHolder( + jsi::Runtime &rt, + const jsi::Value &initialShareable) { + auto dataHolder = std::make_shared( + runtimeHelper, rt, initialShareable); + return dataHolder->getJSValue(rt); +} + +void NativeReanimatedModule::updateDataSynchronously( + jsi::Runtime &rt, + const jsi::Value &synchronizedDataHolderRef, + const jsi::Value &newData) { + auto dataHolder = extractShareableOrThrow( + rt, synchronizedDataHolderRef); + dataHolder->set(rt, newData); +} + +jsi::Value NativeReanimatedModule::getDataSynchronously( + jsi::Runtime &rt, + const jsi::Value &synchronizedDataHolderRef) { + auto dataHolder = extractShareableOrThrow( + rt, synchronizedDataHolderRef); + return dataHolder->get(rt); +} + +jsi::Value NativeReanimatedModule::makeShareableClone( + jsi::Runtime &rt, + const jsi::Value &value, + const jsi::Value &shouldRetainRemote) { + std::shared_ptr shareable; + if (value.isObject()) { + auto object = value.asObject(rt); + if (!object.getProperty(rt, "__workletHash").isUndefined()) { + shareable = std::make_shared(runtimeHelper, rt, object); + } else if (!object.getProperty(rt, "__init").isUndefined()) { + shareable = std::make_shared(runtimeHelper, rt, object); + } else if (object.isFunction(rt)) { + auto function = object.asFunction(rt); + if (function.isHostFunction(rt)) { + shareable = + std::make_shared(rt, std::move(function)); + } else { + shareable = std::make_shared( + runtimeHelper, rt, std::move(function)); + } + } else if (object.isArray(rt)) { + if (shouldRetainRemote.isBool() && shouldRetainRemote.getBool()) { + shareable = std::make_shared>( + runtimeHelper, rt, object.asArray(rt)); + } else { + shareable = std::make_shared(rt, object.asArray(rt)); + } + } else if (object.isHostObject(rt)) { + shareable = std::make_shared( + runtimeHelper, rt, object.getHostObject(rt)); + } else { + if (shouldRetainRemote.isBool() && shouldRetainRemote.getBool()) { + shareable = std::make_shared>( + runtimeHelper, rt, object); + } else { + shareable = std::make_shared(rt, object); + } + } + } else if (value.isString()) { + shareable = std::make_shared(value.asString(rt).utf8(rt)); + } else if (value.isUndefined()) { + shareable = std::make_shared(); + } else if (value.isNull()) { + shareable = std::make_shared(nullptr); + } else if (value.isBool()) { + shareable = std::make_shared(value.getBool()); + } else if (value.isNumber()) { + shareable = std::make_shared(value.getNumber()); + } else if (value.isSymbol()) { + // TODO: this is only a placeholder implementation, here we replace symbols + // with strings in order to make certain objects to be captured. There isn't + // yet any usecase for using symbols on the UI runtime so it is fine to keep + // it like this for now. + shareable = + std::make_shared(value.getSymbol(rt).toString(rt)); + } else { + throw std::runtime_error("attempted to convert an unsupported value type"); + } + return ShareableJSRef::newHostObject(rt, shareable); +} + +jsi::Value NativeReanimatedModule::registerEventHandler( + jsi::Runtime &rt, + const jsi::Value &eventHash, + const jsi::Value &worklet) { + static uint64_t EVENT_HANDLER_ID = 1; + + uint64_t newRegistrationId = EVENT_HANDLER_ID++; + auto eventName = eventHash.asString(rt).utf8(rt); + auto handlerShareable = extractShareableOrThrow(rt, worklet); + + scheduler->scheduleOnUI([=] { + jsi::Runtime &rt = *runtimeHelper->uiRuntime(); + auto handlerFunction = handlerShareable->getJSValue(rt); + auto handler = std::make_shared( + runtimeHelper, + newRegistrationId, + eventName, + std::move(handlerFunction)); + eventHandlerRegistry->registerEventHandler(std::move(handler)); + }); + + return jsi::Value(static_cast(newRegistrationId)); +} + +void NativeReanimatedModule::unregisterEventHandler( + jsi::Runtime &rt, + const jsi::Value ®istrationId) { + uint64_t id = registrationId.asNumber(); + scheduler->scheduleOnUI( + [=] { eventHandlerRegistry->unregisterEventHandler(id); }); +} + +jsi::Value NativeReanimatedModule::getViewProp( + jsi::Runtime &rt, + const jsi::Value &viewTag, + const jsi::Value &propName, + const jsi::Value &callback) { + const int viewTagInt = static_cast(viewTag.asNumber()); + std::string propNameStr = propName.asString(rt).utf8(rt); + jsi::Function fun = callback.getObject(rt).asFunction(rt); + std::shared_ptr funPtr = + std::make_shared(std::move(fun)); + + scheduler->scheduleOnUI([&rt, viewTagInt, funPtr, this, propNameStr]() { + const jsi::String propNameValue = + jsi::String::createFromUtf8(rt, propNameStr); + jsi::Value result = propObtainer(rt, viewTagInt, propNameValue); + std::string resultStr = result.asString(rt).utf8(rt); + + scheduler->scheduleOnJS([&rt, resultStr, funPtr]() { + const jsi::String resultValue = + jsi::String::createFromUtf8(rt, resultStr); + funPtr->call(rt, resultValue); + }); + }); + + return jsi::Value::undefined(); +} + +jsi::Value NativeReanimatedModule::enableLayoutAnimations( + jsi::Runtime &rt, + const jsi::Value &config) { + FeaturesConfig::setLayoutAnimationEnabled(config.getBool()); + return jsi::Value::undefined(); +} + +jsi::Value NativeReanimatedModule::configureProps( + jsi::Runtime &rt, + const jsi::Value &uiProps, + const jsi::Value &nativeProps) { +#ifdef RCT_NEW_ARCH_ENABLED + jsi::Array array = nativeProps.asObject(rt).asArray(rt); + for (int i = 0; i < array.size(rt); ++i) { + std::string name = array.getValueAtIndex(rt, i).asString(rt).utf8(rt); + nativePropNames_.insert(name); + } +#else + configurePropsPlatformFunction(rt, uiProps, nativeProps); +#endif // RCT_NEW_ARCH_ENABLED + + return jsi::Value::undefined(); +} + +jsi::Value NativeReanimatedModule::configureLayoutAnimation( + jsi::Runtime &rt, + const jsi::Value &viewTag, + const jsi::Value &type, + const jsi::Value &sharedTransitionTag, + const jsi::Value &config) { + layoutAnimationsManager_.configureAnimation( + viewTag.asNumber(), + static_cast(type.asNumber()), + sharedTransitionTag.asString(rt).utf8(rt), + extractShareableOrThrow(rt, config)); + return jsi::Value::undefined(); +} + +void NativeReanimatedModule::onEvent( + double eventTimestamp, + const std::string &eventName, + const jsi::Value &payload) { + eventHandlerRegistry->processEvent( + *runtime, eventTimestamp, eventName, payload); +} + +bool NativeReanimatedModule::isAnyHandlerWaitingForEvent( + std::string eventName) { + return eventHandlerRegistry->isAnyHandlerWaitingForEvent(eventName); +} + +void NativeReanimatedModule::maybeRequestRender() { + if (!renderRequested) { + renderRequested = true; + requestRender(onRenderCallback, *this->runtime); + } +} + +void NativeReanimatedModule::onRender(double timestampMs) { + std::vector callbacks = frameCallbacks; + frameCallbacks.clear(); + for (auto &callback : callbacks) { + callback(timestampMs); + } +} + +jsi::Value NativeReanimatedModule::registerSensor( + jsi::Runtime &rt, + const jsi::Value &sensorType, + const jsi::Value &interval, + const jsi::Value &iosReferenceFrame, + const jsi::Value &sensorDataHandler) { + return animatedSensorModule.registerSensor( + rt, + runtimeHelper, + sensorType, + interval, + iosReferenceFrame, + sensorDataHandler); +} + +void NativeReanimatedModule::unregisterSensor( + jsi::Runtime &rt, + const jsi::Value &sensorId) { + animatedSensorModule.unregisterSensor(sensorId); +} + +void NativeReanimatedModule::cleanupSensors() { + animatedSensorModule.unregisterAllSensors(); +} + +#ifdef RCT_NEW_ARCH_ENABLED +bool NativeReanimatedModule::isThereAnyLayoutProp( + jsi::Runtime &rt, + const jsi::Value &props) { + const jsi::Array propNames = props.asObject(rt).getPropertyNames(rt); + for (size_t i = 0; i < propNames.size(rt); ++i) { + const std::string propName = + propNames.getValueAtIndex(rt, i).asString(rt).utf8(rt); + bool isLayoutProp = + nativePropNames_.find(propName) != nativePropNames_.end(); + if (isLayoutProp) { + return true; + } + } + return false; +} +#endif // RCT_NEW_ARCH_ENABLED + +bool NativeReanimatedModule::handleEvent( + const std::string &eventName, + const jsi::Value &payload, + double currentTime) { + onEvent(currentTime, eventName, payload); + + // TODO: return true if Reanimated successfully handled the event + // to avoid sending it to JavaScript + return false; +} + +#ifdef RCT_NEW_ARCH_ENABLED +bool NativeReanimatedModule::handleRawEvent( + const RawEvent &rawEvent, + double currentTime) { + const EventTarget *eventTarget = rawEvent.eventTarget.get(); + if (eventTarget == nullptr) { + // after app reload scrollview is unmounted and its content offset is set to + // 0 and view is thrown into recycle pool setting content offset triggers + // scroll event eventTarget is null though, because it's unmounting we can + // just ignore this event, because it's an event on unmounted component + return false; + } + const std::string &type = rawEvent.type; + const ValueFactory &payloadFactory = rawEvent.payloadFactory; + + int tag = eventTarget->getTag(); + std::string eventType = type; + if (eventType.rfind("top", 0) == 0) { + eventType = "on" + eventType.substr(3); + } + std::string eventName = std::to_string(tag) + eventType; + jsi::Runtime &rt = *runtime.get(); + jsi::Value payload = payloadFactory(rt); + + auto res = handleEvent(eventName, std::move(payload), currentTime); + // TODO: we should call performOperations conditionally if event is handled + // (res == true), but for now handleEvent always returns false. Thankfully, + // performOperations does not trigger a lot of code if there is nothing to be + // done so this is fine for now. + performOperations(); + return res; +} + +void NativeReanimatedModule::updateProps( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue, + const jsi::Value &props) { + ShadowNode::Shared shadowNode = shadowNodeFromValue(rt, shadowNodeValue); + + // TODO: support multiple surfaces + surfaceId_ = shadowNode->getSurfaceId(); + + if (isThereAnyLayoutProp(rt, props)) { + operationsInBatch_.emplace_back( + shadowNode, std::make_unique(rt, props)); + } else { + // TODO: batch with layout props changes? + Tag tag = shadowNode->getTag(); + synchronouslyUpdateUIPropsFunction(rt, tag, props); + } +} + +void NativeReanimatedModule::performOperations() { + if (operationsInBatch_.empty()) { + return; + } + + auto copiedOperationsQueue = std::move(operationsInBatch_); + operationsInBatch_ = + std::vector>>(); + + auto copiedTagsToRemove = std::move(tagsToRemove_); + tagsToRemove_ = std::vector(); + + react_native_assert(uiManager_ != nullptr); + const auto &shadowTreeRegistry = uiManager_->getShadowTreeRegistry(); + jsi::Runtime &rt = *runtime.get(); + + shadowTreeRegistry.visit(surfaceId_, [&](ShadowTree const &shadowTree) { + auto lock = newestShadowNodesRegistry_->createLock(); + + shadowTree.commit( + [&](RootShadowNode const &oldRootShadowNode) { + auto rootNode = + oldRootShadowNode.ShadowNode::clone(ShadowNodeFragment{}); + + ShadowTreeCloner shadowTreeCloner{ + newestShadowNodesRegistry_, uiManager_, surfaceId_}; + + for (const auto &pair : copiedOperationsQueue) { + const ShadowNodeFamily &family = pair.first->getFamily(); + react_native_assert(family.getSurfaceId() == surfaceId_); + + auto newRootNode = shadowTreeCloner.cloneWithNewProps( + rootNode, family, RawProps(rt, *pair.second)); + + if (newRootNode == nullptr) { + // this happens when React removed the component but Reanimated + // still tries to animate it, let's skip update for this specific + // component + continue; + } + rootNode = newRootNode; + } + + // remove ShadowNodes and its ancestors from NewestShadowNodesRegistry + for (auto tag : copiedTagsToRemove) { + newestShadowNodesRegistry_->remove(tag); + } + + shadowTreeCloner.updateYogaChildren(); + + return std::static_pointer_cast(rootNode); + }, + {/* default commit options */}); + }); +} + +void NativeReanimatedModule::removeShadowNodeFromRegistry( + jsi::Runtime &rt, + const jsi::Value &tag) { + tagsToRemove_.push_back(tag.asNumber()); +} + +void NativeReanimatedModule::dispatchCommand( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue, + const jsi::Value &commandNameValue, + const jsi::Value &argsValue) { + ShadowNode::Shared shadowNode = shadowNodeFromValue(rt, shadowNodeValue); + std::string commandName = stringFromValue(rt, commandNameValue); + folly::dynamic args = commandArgsFromValue(rt, argsValue); + uiManager_->dispatchCommand(shadowNode, commandName, args); +} + +jsi::Value NativeReanimatedModule::measure( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue) { + // based on implementation from UIManagerBinding.cpp + + auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue); + auto layoutMetrics = uiManager_->getRelativeLayoutMetrics( + *shadowNode, nullptr, {/* .includeTransform = */ true}); + + if (layoutMetrics == EmptyLayoutMetrics) { + // Originally, in this case React Native returns `{0, 0, 0, 0, 0, 0}`, most + // likely due to the type of measure callback function which accepts just an + // array of numbers (not null). In Reanimated, `measure` returns + // `MeasuredDimensions | null`. + return jsi::Value::null(); + } + auto newestCloneOfShadowNode = + uiManager_->getNewestCloneOfShadowNode(*shadowNode); + + auto layoutableShadowNode = + traitCast(newestCloneOfShadowNode.get()); + facebook::react::Point originRelativeToParent = + layoutableShadowNode != nullptr + ? layoutableShadowNode->getLayoutMetrics().frame.origin + : facebook::react::Point(); + + auto frame = layoutMetrics.frame; + + jsi::Object result(rt); + result.setProperty( + rt, "x", jsi::Value(static_cast(originRelativeToParent.x))); + result.setProperty( + rt, "y", jsi::Value(static_cast(originRelativeToParent.y))); + result.setProperty( + rt, "width", jsi::Value(static_cast(frame.size.width))); + result.setProperty( + rt, "height", jsi::Value(static_cast(frame.size.height))); + result.setProperty( + rt, "pageX", jsi::Value(static_cast(frame.origin.x))); + result.setProperty( + rt, "pageY", jsi::Value(static_cast(frame.origin.y))); + return result; +} + +void NativeReanimatedModule::setUIManager( + std::shared_ptr uiManager) { + uiManager_ = uiManager; +} + +void NativeReanimatedModule::setNewestShadowNodesRegistry( + std::shared_ptr newestShadowNodesRegistry) { + newestShadowNodesRegistry_ = newestShadowNodesRegistry; +} +#endif // RCT_NEW_ARCH_ENABLED + +jsi::Value NativeReanimatedModule::subscribeForKeyboardEvents( + jsi::Runtime &rt, + const jsi::Value &handlerWorklet, + const jsi::Value &isStatusBarTranslucent) { + auto shareableHandler = extractShareableOrThrow(rt, handlerWorklet); + return subscribeForKeyboardEventsFunction( + [=](int keyboardState, int height) { + jsi::Runtime &rt = *runtimeHelper->uiRuntime(); + auto handler = shareableHandler->getJSValue(rt); + runtimeHelper->runOnUIGuarded( + handler, jsi::Value(keyboardState), jsi::Value(height)); + }, + isStatusBarTranslucent.getBool()); +} + +void NativeReanimatedModule::unsubscribeFromKeyboardEvents( + jsi::Runtime &rt, + const jsi::Value &listenerId) { + unsubscribeFromKeyboardEventsFunction(listenerId.asNumber()); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModule.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModule.h new file mode 100644 index 00000000000000..d51a6c771e9508 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModule.h @@ -0,0 +1,208 @@ +#pragma once + +#ifdef RCT_NEW_ARCH_ENABLED +#include +#include "NewestShadowNodesRegistry.h" +#endif + +#include +#include +#include +#include +#include + +#include "AnimatedSensorModule.h" +#include "ErrorHandler.h" +#include "LayoutAnimationsManager.h" +#include "NativeReanimatedModuleSpec.h" +#include "PlatformDepMethodsHolder.h" +#include "RuntimeDecorator.h" +#include "RuntimeManager.h" +#include "Scheduler.h" +#include "SingleInstanceChecker.h" + +namespace reanimated { + +using FrameCallback = std::function; + +class EventHandlerRegistry; + +class NativeReanimatedModule : public NativeReanimatedModuleSpec, + public RuntimeManager { + public: + NativeReanimatedModule( + const std::shared_ptr &jsInvoker, + const std::shared_ptr &scheduler, + const std::shared_ptr &rt, + const std::shared_ptr &errorHandler, +#ifdef RCT_NEW_ARCH_ENABLED + // nothing +#else + std::function + propObtainer, +#endif + PlatformDepMethodsHolder platformDepMethodsHolder); + + ~NativeReanimatedModule(); + + std::shared_ptr runtimeHelper; + + void installCoreFunctions( + jsi::Runtime &rt, + const jsi::Value &callGuard, + const jsi::Value &valueUnpacker) override; + + jsi::Value makeShareableClone( + jsi::Runtime &rt, + const jsi::Value &value, + const jsi::Value &shouldRetainRemote) override; + + jsi::Value makeSynchronizedDataHolder( + jsi::Runtime &rt, + const jsi::Value &initialShareable) override; + jsi::Value getDataSynchronously( + jsi::Runtime &rt, + const jsi::Value &synchronizedDataHolderRef) override; + void updateDataSynchronously( + jsi::Runtime &rt, + const jsi::Value &synchronizedDataHolderRef, + const jsi::Value &newData); + + void scheduleOnUI(jsi::Runtime &rt, const jsi::Value &worklet) override; + + jsi::Value registerEventHandler( + jsi::Runtime &rt, + const jsi::Value &eventHash, + const jsi::Value &worklet) override; + void unregisterEventHandler( + jsi::Runtime &rt, + const jsi::Value ®istrationId) override; + + jsi::Value getViewProp( + jsi::Runtime &rt, + const jsi::Value &viewTag, + const jsi::Value &propName, + const jsi::Value &callback) override; + + jsi::Value enableLayoutAnimations(jsi::Runtime &rt, const jsi::Value &config) + override; + jsi::Value configureProps( + jsi::Runtime &rt, + const jsi::Value &uiProps, + const jsi::Value &nativeProps) override; + jsi::Value configureLayoutAnimation( + jsi::Runtime &rt, + const jsi::Value &viewTag, + const jsi::Value &type, + const jsi::Value &sharedTransitionTag, + const jsi::Value &config) override; + + void onRender(double timestampMs); + + void onEvent( + double eventTimestamp, + const std::string &eventName, + const jsi::Value &payload); + + bool isAnyHandlerWaitingForEvent(std::string eventName); + + void maybeRequestRender(); + UpdatePropsFunction updatePropsFunction; + + bool handleEvent( + const std::string &eventName, + const jsi::Value &payload, + double currentTime); + +#ifdef RCT_NEW_ARCH_ENABLED + bool handleRawEvent(const RawEvent &rawEvent, double currentTime); + + void updateProps( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue, + const jsi::Value &props); + + void removeShadowNodeFromRegistry(jsi::Runtime &rt, const jsi::Value &tag); + + void performOperations(); + + void dispatchCommand( + jsi::Runtime &rt, + const jsi::Value &shadowNodeValue, + const jsi::Value &commandNameValue, + const jsi::Value &argsValue); + + jsi::Value measure(jsi::Runtime &rt, const jsi::Value &shadowNodeValue); + + void setUIManager(std::shared_ptr uiManager); + + void setNewestShadowNodesRegistry( + std::shared_ptr newestShadowNodesRegistry); +#endif + + jsi::Value registerSensor( + jsi::Runtime &rt, + const jsi::Value &sensorType, + const jsi::Value &interval, + const jsi::Value &iosReferenceFrame, + const jsi::Value &sensorDataContainer) override; + void unregisterSensor(jsi::Runtime &rt, const jsi::Value &sensorId) override; + + void cleanupSensors(); + + jsi::Value subscribeForKeyboardEvents( + jsi::Runtime &rt, + const jsi::Value &keyboardEventContainer, + const jsi::Value &isStatusBarTranslucent) override; + void unsubscribeFromKeyboardEvents( + jsi::Runtime &rt, + const jsi::Value &listenerId) override; + + inline LayoutAnimationsManager &layoutAnimationsManager() { + return layoutAnimationsManager_; + } + + private: +#ifdef RCT_NEW_ARCH_ENABLED + bool isThereAnyLayoutProp(jsi::Runtime &rt, const jsi::Value &props); +#endif // RCT_NEW_ARCH_ENABLED + + std::unique_ptr eventHandlerRegistry; + std::function requestRender; + std::vector frameCallbacks; + bool renderRequested = false; + std::function + propObtainer; + std::function onRenderCallback; + AnimatedSensorModule animatedSensorModule; + ConfigurePropsFunction configurePropsPlatformFunction; + +#ifdef RCT_NEW_ARCH_ENABLED + SynchronouslyUpdateUIPropsFunction synchronouslyUpdateUIPropsFunction; + + std::shared_ptr uiManager_; + + // After app reload, surfaceId on iOS is still 1 but on Android it's 11. + // We can store surfaceId of the most recent ShadowNode as a workaround. + SurfaceId surfaceId_ = -1; + + std::vector>> + operationsInBatch_; // TODO: refactor std::pair to custom struct + + std::shared_ptr newestShadowNodesRegistry_; + + std::vector tagsToRemove_; // from newestShadowNodesRegistry_ +#endif + + std::unordered_set nativePropNames_; // filled by configureProps + LayoutAnimationsManager layoutAnimationsManager_; + + KeyboardEventSubscribeFunction subscribeForKeyboardEventsFunction; + KeyboardEventUnsubscribeFunction unsubscribeFromKeyboardEventsFunction; + +#ifdef DEBUG + SingleInstanceChecker singleInstanceChecker_; +#endif +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp new file mode 100644 index 00000000000000..e8bde590d3aaad --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp @@ -0,0 +1,205 @@ +#include "NativeReanimatedModuleSpec.h" + +#include + +#define SPEC_PREFIX(FN_NAME) __hostFunction_NativeReanimatedModuleSpec_##FN_NAME + +namespace reanimated { + +static jsi::Value SPEC_PREFIX(installCoreFunctions)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->installCoreFunctions(rt, std::move(args[0]), std::move(args[1])); + return jsi::Value::undefined(); +} + +// SharedValue + +static jsi::Value SPEC_PREFIX(makeShareableClone)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->makeShareableClone(rt, std::move(args[0]), std::move(args[1])); +} + +// Sync methods + +static jsi::Value SPEC_PREFIX(makeSynchronizedDataHolder)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->makeSynchronizedDataHolder(rt, std::move(args[0])); +} + +static jsi::Value SPEC_PREFIX(getDataSynchronously)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->getDataSynchronously(rt, std::move(args[0])); +} + +// scheduler + +static jsi::Value SPEC_PREFIX(scheduleOnUI)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->scheduleOnUI(rt, std::move(args[0])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(registerEventHandler)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->registerEventHandler(rt, std::move(args[0]), std::move(args[1])); +} + +static jsi::Value SPEC_PREFIX(unregisterEventHandler)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->unregisterEventHandler(rt, std::move(args[0])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(getViewProp)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->getViewProp( + rt, std::move(args[0]), std::move(args[1]), std::move(args[2])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(enableLayoutAnimations)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->enableLayoutAnimations(rt, std::move(args[0])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(registerSensor)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->registerSensor( + rt, + std::move(args[0]), + std::move(args[1]), + std::move(args[2]), + std::move(args[3])); +} + +static jsi::Value SPEC_PREFIX(unregisterSensor)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->unregisterSensor(rt, std::move(args[0])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(configureProps)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->configureProps(rt, std::move(args[0]), std::move(args[1])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(subscribeForKeyboardEvents)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->subscribeForKeyboardEvents(rt, std::move(args[0]), std::move(args[1])); +} + +static jsi::Value SPEC_PREFIX(unsubscribeFromKeyboardEvents)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->unsubscribeFromKeyboardEvents(rt, std::move(args[0])); + return jsi::Value::undefined(); +} + +static jsi::Value SPEC_PREFIX(configureLayoutAnimation)( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + return static_cast(&turboModule) + ->configureLayoutAnimation( + rt, + std::move(args[0]), + std::move(args[1]), + std::move(args[2]), + std::move(args[3])); +} + +NativeReanimatedModuleSpec::NativeReanimatedModuleSpec( + std::shared_ptr jsInvoker) + : TurboModule("NativeReanimated", jsInvoker) { + methodMap_["installCoreFunctions"] = + MethodMetadata{2, SPEC_PREFIX(installCoreFunctions)}; + + methodMap_["makeShareableClone"] = + MethodMetadata{2, SPEC_PREFIX(makeShareableClone)}; + + methodMap_["makeSynchronizedDataHolder"] = + MethodMetadata{1, SPEC_PREFIX(makeSynchronizedDataHolder)}; + methodMap_["getDataSynchronously"] = + MethodMetadata{1, SPEC_PREFIX(getDataSynchronously)}; + + methodMap_["scheduleOnUI"] = MethodMetadata{1, SPEC_PREFIX(scheduleOnUI)}; + + methodMap_["registerEventHandler"] = + MethodMetadata{2, SPEC_PREFIX(registerEventHandler)}; + methodMap_["unregisterEventHandler"] = + MethodMetadata{1, SPEC_PREFIX(unregisterEventHandler)}; + + methodMap_["getViewProp"] = MethodMetadata{3, SPEC_PREFIX(getViewProp)}; + methodMap_["enableLayoutAnimations"] = + MethodMetadata{2, SPEC_PREFIX(enableLayoutAnimations)}; + methodMap_["registerSensor"] = MethodMetadata{4, SPEC_PREFIX(registerSensor)}; + methodMap_["unregisterSensor"] = + MethodMetadata{1, SPEC_PREFIX(unregisterSensor)}; + methodMap_["configureProps"] = MethodMetadata{2, SPEC_PREFIX(configureProps)}; + methodMap_["subscribeForKeyboardEvents"] = + MethodMetadata{2, SPEC_PREFIX(subscribeForKeyboardEvents)}; + methodMap_["unsubscribeFromKeyboardEvents"] = + MethodMetadata{1, SPEC_PREFIX(unsubscribeFromKeyboardEvents)}; + + methodMap_["configureLayoutAnimation"] = + MethodMetadata{4, SPEC_PREFIX(configureLayoutAnimation)}; +} +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModuleSpec.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModuleSpec.h new file mode 100644 index 00000000000000..438437963a0d32 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/NativeModules/NativeReanimatedModuleSpec.h @@ -0,0 +1,101 @@ +#pragma once + +#include +#include +#include + +#ifdef ANDROID +#include "TurboModule.h" +#else +#include +#endif + +#include + +using namespace facebook; +using namespace react; + +namespace reanimated { + +class JSI_EXPORT NativeReanimatedModuleSpec : public TurboModule { + protected: + explicit NativeReanimatedModuleSpec(std::shared_ptr jsInvoker); + + public: + virtual void installCoreFunctions( + jsi::Runtime &rt, + const jsi::Value &callGuard, + const jsi::Value &valueUnpacker) = 0; + + // SharedValue + virtual jsi::Value makeShareableClone( + jsi::Runtime &rt, + const jsi::Value &value, + const jsi::Value &shouldRetainRemote) = 0; + + // Synchronized data objects + virtual jsi::Value makeSynchronizedDataHolder( + jsi::Runtime &rt, + const jsi::Value &initialShareable) = 0; + virtual jsi::Value getDataSynchronously( + jsi::Runtime &rt, + const jsi::Value &synchronizedDataHolderRef) = 0; + + // Scheduling + virtual void scheduleOnUI(jsi::Runtime &rt, const jsi::Value &worklet) = 0; + + // events + virtual jsi::Value registerEventHandler( + jsi::Runtime &rt, + const jsi::Value &eventHash, + const jsi::Value &worklet) = 0; + virtual void unregisterEventHandler( + jsi::Runtime &rt, + const jsi::Value ®istrationId) = 0; + + // views + virtual jsi::Value getViewProp( + jsi::Runtime &rt, + const jsi::Value &viewTag, + const jsi::Value &propName, + const jsi::Value &callback) = 0; + + // sensors + virtual jsi::Value registerSensor( + jsi::Runtime &rt, + const jsi::Value &sensorType, + const jsi::Value &interval, + const jsi::Value &iosReferenceFrame, + const jsi::Value &sensorDataContainer) = 0; + virtual void unregisterSensor( + jsi::Runtime &rt, + const jsi::Value &sensorId) = 0; + + // keyboard + virtual jsi::Value subscribeForKeyboardEvents( + jsi::Runtime &rt, + const jsi::Value &keyboardEventContainer, + const jsi::Value &isStatusBarTranslucent) = 0; + virtual void unsubscribeFromKeyboardEvents( + jsi::Runtime &rt, + const jsi::Value &listenerId) = 0; + + // other + virtual jsi::Value enableLayoutAnimations( + jsi::Runtime &rt, + const jsi::Value &config) = 0; + virtual jsi::Value configureProps( + jsi::Runtime &rt, + const jsi::Value &uiProps, + const jsi::Value &nativeProps) = 0; + + // layout animations + virtual jsi::Value configureLayoutAnimation( + jsi::Runtime &rt, + const jsi::Value &viewTag, + const jsi::Value &type, + const jsi::Value &sharedTransitionTag, + const jsi::Value &config) = 0; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.cpp new file mode 100644 index 00000000000000..45dd987d80892a --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.cpp @@ -0,0 +1,142 @@ +#include "ReanimatedHermesRuntime.h" + +// Only include this file in Hermes-enabled builds as some platforms (like tvOS) +// don't support hermes and it causes the compilation to fail. +#if JS_RUNTIME_HERMES + +#include +#include +#include + +#include +#include +#include + +#if __has_include() +#include +#else // __has_include() || ANDROID +#include +#endif + +#include +#include + +namespace reanimated { + +using namespace facebook; +using namespace react; + +#if HERMES_ENABLE_DEBUGGER + +class HermesExecutorRuntimeAdapter + : public facebook::hermes::inspector::RuntimeAdapter { + public: + HermesExecutorRuntimeAdapter( + facebook::hermes::HermesRuntime &hermesRuntime, + std::shared_ptr thread) + : hermesRuntime_(hermesRuntime), thread_(std::move(thread)) {} + + virtual ~HermesExecutorRuntimeAdapter() { + // This is required by iOS, because there is an assertion in the destructor + // that the thread was indeed `quit` before + thread_->quitSynchronous(); + } + +#if REACT_NATIVE_MINOR_VERSION >= 71 + facebook::hermes::HermesRuntime &getRuntime() override { + return hermesRuntime_; + } +#else + facebook::jsi::Runtime &getRuntime() override { + return hermesRuntime_; + } + + facebook::hermes::debugger::Debugger &getDebugger() override { + return hermesRuntime_.getDebugger(); + } +#endif // REACT_NATIVE_MINOR_VERSION + + // This is not empty in the original implementation, but we decided to tickle + // the runtime by running a small piece of code on every frame as using this + // required us to hold a refernce to the runtime inside this adapter which + // caused issues while reloading the app. + void tickleJs() override {} + + public: + facebook::hermes::HermesRuntime &hermesRuntime_; + std::shared_ptr thread_; +}; + +#endif // HERMES_ENABLE_DEBUGGER + +ReanimatedHermesRuntime::ReanimatedHermesRuntime( + std::unique_ptr runtime, + std::shared_ptr jsQueue) + : jsi::WithRuntimeDecorator( + *runtime, + reentrancyCheck_), + runtime_(std::move(runtime)) { +#if HERMES_ENABLE_DEBUGGER + auto adapter = + std::make_unique(*runtime_, jsQueue); +#if REACT_NATIVE_MINOR_VERSION >= 71 + debugToken_ = facebook::hermes::inspector::chrome::enableDebugging( + std::move(adapter), "Reanimated Runtime"); +#else + facebook::hermes::inspector::chrome::enableDebugging( + std::move(adapter), "Reanimated Runtime"); +#endif // REACT_NATIVE_MINOR_VERSION +#else + // This is required by iOS, because there is an assertion in the destructor + // that the thread was indeed `quit` before + jsQueue->quitSynchronous(); +#endif + +#ifdef DEBUG + facebook::hermes::HermesRuntime *wrappedRuntime = runtime_.get(); + jsi::Value evalWithSourceMap = jsi::Function::createFromHostFunction( + *runtime_, + jsi::PropNameID::forAscii(*runtime_, "evalWithSourceMap"), + 3, + [wrappedRuntime]( + jsi::Runtime &rt, + const jsi::Value &thisValue, + const jsi::Value *args, + size_t count) -> jsi::Value { + auto code = std::make_shared( + args[0].asString(rt).utf8(rt)); + std::string sourceURL; + if (count > 1 && args[1].isString()) { + sourceURL = args[1].asString(rt).utf8(rt); + } + std::shared_ptr sourceMap; + if (count > 2 && args[2].isString()) { + sourceMap = std::make_shared( + args[2].asString(rt).utf8(rt)); + } +#if REACT_NATIVE_MINOR_VERSION >= 65 + return wrappedRuntime->evaluateJavaScriptWithSourceMap( + code, sourceMap, sourceURL); +#else + return wrappedRuntime->evaluateJavaScript(code, sourceURL); +#endif + }); + runtime_->global().setProperty( + *runtime_, "evalWithSourceMap", evalWithSourceMap); +#endif // DEBUG +} + +ReanimatedHermesRuntime::~ReanimatedHermesRuntime() { +#if HERMES_ENABLE_DEBUGGER + // We have to disable debugging before the runtime is destroyed. +#if REACT_NATIVE_MINOR_VERSION >= 71 + facebook::hermes::inspector::chrome::disableDebugging(debugToken_); +#else + facebook::hermes::inspector::chrome::disableDebugging(*runtime_); +#endif // REACT_NATIVE_MINOR_VERSION +#endif // HERMES_ENABLE_DEBUGGER +} + +} // namespace reanimated + +#endif // JS_RUNTIME_HERMES diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.h new file mode 100644 index 00000000000000..e4d807d36a7c1e --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.h @@ -0,0 +1,134 @@ +#pragma once + +// JS_RUNTIME_HERMES is only set on Android so we have to check __has_include +// on iOS. +#if __APPLE__ && \ + (__has_include( \ + ) || __has_include()) +#define JS_RUNTIME_HERMES 1 +#endif + +// Only include this file in Hermes-enabled builds as some platforms (like tvOS) +// don't support hermes and it causes the compilation to fail. +#if JS_RUNTIME_HERMES + +#include +#include +#include + +#include +#include + +#if __has_include() +#include +#else // __has_include() || ANDROID +#include +#endif + +#if REACT_NATIVE_MINOR_VERSION >= 71 +#include +#endif + +namespace reanimated { + +using namespace facebook; +using namespace react; + +// ReentrancyCheck is copied from React Native +// from ReactCommon/hermes/executor/HermesExecutorFactory.cpp +// https://github.com/facebook/react-native/blob/main/ReactCommon/hermes/executor/HermesExecutorFactory.cpp +struct ReanimatedReentrancyCheck { +// This is effectively a very subtle and complex assert, so only +// include it in builds which would include asserts. +#ifndef NDEBUG + ReanimatedReentrancyCheck() : tid(std::thread::id()), depth(0) {} + + void before() { + std::thread::id this_id = std::this_thread::get_id(); + std::thread::id expected = std::thread::id(); + + // A note on memory ordering: the main purpose of these checks is + // to observe a before/before race, without an intervening after. + // This will be detected by the compare_exchange_strong atomicity + // properties, regardless of memory order. + // + // For everything else, it is easiest to think of 'depth' as a + // proxy for any access made inside the VM. If access to depth + // are reordered incorrectly, the same could be true of any other + // operation made by the VM. In fact, using acquire/release + // memory ordering could create barriers which mask a programmer + // error. So, we use relaxed memory order, to avoid masking + // actual ordering errors. Although, in practice, ordering errors + // of this sort would be surprising, because the decorator would + // need to call after() without before(). + + if (tid.compare_exchange_strong( + expected, this_id, std::memory_order_relaxed)) { + // Returns true if tid and expected were the same. If they + // were, then the stored tid referred to no thread, and we + // atomically saved this thread's tid. Now increment depth. + assert(depth == 0 && "No thread id, but depth != 0"); + ++depth; + } else if (expected == this_id) { + // If the stored tid referred to a thread, expected was set to + // that value. If that value is this thread's tid, that's ok, + // just increment depth again. + assert(depth != 0 && "Thread id was set, but depth == 0"); + ++depth; + } else { + // The stored tid was some other thread. This indicates a bad + // programmer error, where VM methods were called on two + // different threads unsafely. Fail fast (and hard) so the + // crash can be analyzed. + __builtin_trap(); + } + } + + void after() { + assert( + tid.load(std::memory_order_relaxed) == std::this_thread::get_id() && + "No thread id in after()"); + if (--depth == 0) { + // If we decremented depth to zero, store no-thread into tid. + std::thread::id expected = std::this_thread::get_id(); + bool didWrite = tid.compare_exchange_strong( + expected, std::thread::id(), std::memory_order_relaxed); + assert(didWrite && "Decremented to zero, but no tid write"); + } + } + + std::atomic tid; + // This is not atomic, as it is only written or read from the owning + // thread. + unsigned int depth; +#endif // NDEBUG +}; + +// This is in fact a subclass of jsi::Runtime! WithRuntimeDecorator is a +// template class that is a subclass of DecoratedRuntime which is also a +// template class that then inherits its template, which in this case is +// jsi::Runtime. So the inheritance is: ReanimatedHermesRuntime -> +// WithRuntimeDecorator -> DecoratedRuntime -> jsi::Runtime You can find out +// more about this in ReactCommon/jsi/jsi/Decorator.h or by following this link: +// https://github.com/facebook/react-native/blob/main/ReactCommon/jsi/jsi/decorator.h +class ReanimatedHermesRuntime + : public jsi::WithRuntimeDecorator { + public: + ReanimatedHermesRuntime( + std::unique_ptr runtime, + std::shared_ptr jsQueue); + ~ReanimatedHermesRuntime(); + + private: + std::unique_ptr runtime_; + ReanimatedReentrancyCheck reentrancyCheck_; +#if HERMES_ENABLE_DEBUGGER +#if REACT_NATIVE_MINOR_VERSION >= 71 + facebook::hermes::inspector::chrome::DebugSessionToken debugToken_; +#endif // REACT_NATIVE_MINOR_VERSION >= 71 +#endif // HERMES_ENABLE_DEBUGGER +}; + +} // namespace reanimated + +#endif // JS_RUNTIME_HERMES diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.cpp new file mode 100644 index 00000000000000..5a3c0293623e3b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.cpp @@ -0,0 +1,55 @@ +#include "ReanimatedRuntime.h" + +#include +#include + +#include +#include + +#if JS_RUNTIME_HERMES +#include "ReanimatedHermesRuntime.h" +#elif JS_RUNTIME_V8 +#include +#else +#if REACT_NATIVE_MINOR_VERSION >= 71 +#include +#else +#include +#endif // REACT_NATIVE_MINOR_VERSION +#endif // JS_RUNTIME + +namespace reanimated { + +using namespace facebook; +using namespace react; + +std::shared_ptr ReanimatedRuntime::make( + jsi::Runtime *rnRuntime, + std::shared_ptr jsQueue) { +#if JS_RUNTIME_HERMES + std::unique_ptr runtime = + facebook::hermes::makeHermesRuntime(); + + // We don't call `jsQueue->quitSynchronous()` here, since it will be done + // later in ReanimatedHermesRuntime + + return std::make_shared(std::move(runtime), jsQueue); +#elif JS_RUNTIME_V8 + // This is required by iOS, because there is an assertion in the destructor + // that the thread was indeed `quit` before. + jsQueue->quitSynchronous(); + + auto config = std::make_unique(); + config->enableInspector = false; + config->appName = "reanimated"; + return rnv8::createSharedV8Runtime(rnRuntime, std::move(config)); +#else + // This is required by iOS, because there is an assertion in the destructor + // that the thread was indeed `quit` before + jsQueue->quitSynchronous(); + + return facebook::jsc::makeJSCRuntime(); +#endif +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.h new file mode 100644 index 00000000000000..09469ca85fc03c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.h @@ -0,0 +1,28 @@ +#pragma once + +// JS_RUNTIME_HERMES is only set on Android so we have to check __has_include +// on iOS. +#if __APPLE__ && \ + (__has_include( \ + ) || __has_include()) +#define JS_RUNTIME_HERMES 1 +#endif + +#include +#include + +#include + +namespace reanimated { + +using namespace facebook; +using namespace react; + +class ReanimatedRuntime { + public: + static std::shared_ptr make( + jsi::Runtime *rnRuntime, + std::shared_ptr jsQueue); +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/EventHandlerRegistry.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/EventHandlerRegistry.cpp new file mode 100644 index 00000000000000..26d316777f70e4 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/EventHandlerRegistry.cpp @@ -0,0 +1,55 @@ +#include "EventHandlerRegistry.h" +#include "WorkletEventHandler.h" + +namespace reanimated { + +void EventHandlerRegistry::registerEventHandler( + std::shared_ptr eventHandler) { + const std::lock_guard lock(instanceMutex); + eventMappings[eventHandler->eventName][eventHandler->id] = eventHandler; + eventHandlers[eventHandler->id] = eventHandler; +} + +void EventHandlerRegistry::unregisterEventHandler(uint64_t id) { + const std::lock_guard lock(instanceMutex); + auto handlerIt = eventHandlers.find(id); + if (handlerIt != eventHandlers.end()) { + eventMappings[handlerIt->second->eventName].erase(id); + if (eventMappings[handlerIt->second->eventName].empty()) { + eventMappings.erase(handlerIt->second->eventName); + } + eventHandlers.erase(handlerIt); + } +} + +void EventHandlerRegistry::processEvent( + jsi::Runtime &rt, + double eventTimestamp, + const std::string &eventName, + const jsi::Value &eventPayload) { + std::vector> handlersForEvent; + { + const std::lock_guard lock(instanceMutex); + auto handlersIt = eventMappings.find(eventName); + if (handlersIt != eventMappings.end()) { + for (auto handler : handlersIt->second) { + handlersForEvent.push_back(handler.second); + } + } + } + + eventPayload.asObject(rt).setProperty( + rt, "eventName", jsi::String::createFromUtf8(rt, eventName)); + for (auto handler : handlersForEvent) { + handler->process(eventTimestamp, eventPayload); + } +} + +bool EventHandlerRegistry::isAnyHandlerWaitingForEvent( + const std::string &eventName) { + const std::lock_guard lock(instanceMutex); + auto it = eventMappings.find(eventName); + return (it != eventMappings.end()) && (!(it->second).empty()); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/EventHandlerRegistry.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/EventHandlerRegistry.h new file mode 100644 index 00000000000000..d58a07b47d805b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/EventHandlerRegistry.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace facebook; + +namespace reanimated { + +class WorkletEventHandler; + +class EventHandlerRegistry { + std::map< + std::string, + std::unordered_map>> + eventMappings; + std::map> eventHandlers; + std::mutex instanceMutex; + + public: + void registerEventHandler(std::shared_ptr eventHandler); + void unregisterEventHandler(uint64_t id); + + void processEvent( + jsi::Runtime &rt, + double eventTimestamp, + const std::string &eventName, + const jsi::Value &eventPayload); + + bool isAnyHandlerWaitingForEvent(const std::string &eventName); +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/NewestShadowNodesRegistry.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/NewestShadowNodesRegistry.cpp new file mode 100644 index 00000000000000..ab5c0ecda7fc2d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/NewestShadowNodesRegistry.cpp @@ -0,0 +1,68 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#include "NewestShadowNodesRegistry.h" + +#include +#include + +using namespace facebook::react; + +namespace reanimated { + +void NewestShadowNodesRegistry::set( + ShadowNode::Shared shadowNode, + Tag parentTag) { + map_[shadowNode->getTag()] = std::make_pair(shadowNode, parentTag); +} + +bool NewestShadowNodesRegistry::has( + const ShadowNode::Shared &shadowNode) const { + return map_.find(shadowNode->getTag()) != map_.cend(); +} + +ShadowNode::Shared NewestShadowNodesRegistry::get(Tag tag) const { + const auto it = map_.find(tag); + return it != map_.cend() ? it->second.first : nullptr; +} + +void NewestShadowNodesRegistry::update(ShadowNode::Shared shadowNode) { + const auto it = map_.find(shadowNode->getTag()); + react_native_assert(it != map_.cend()); + it->second.first = shadowNode; +} + +void NewestShadowNodesRegistry::remove(Tag tag) { + if (map_.find(tag) == map_.cend()) { + return; + } + + auto shadowNode = map_[tag].first; + + while (shadowNode != nullptr) { + bool hasAnyChildInMap = false; + for (const auto &child : shadowNode->getChildren()) { + if (has(child)) { + hasAnyChildInMap = true; + break; + } + } + + if (hasAnyChildInMap) { + break; + } + + auto it = map_.find(shadowNode->getTag()); + Tag parentTag = it->second.second; + map_.erase(it); + + shadowNode = map_[parentTag].first; + } +} + +std::lock_guard NewestShadowNodesRegistry::createLock() const { + return std::lock_guard(mutex_); +} + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/NewestShadowNodesRegistry.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/NewestShadowNodesRegistry.h new file mode 100644 index 00000000000000..c8cdf137fcff1d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Registries/NewestShadowNodesRegistry.h @@ -0,0 +1,41 @@ +#pragma once +#ifdef RCT_NEW_ARCH_ENABLED + +#include +#include +#include +#include + +using namespace facebook::react; + +namespace reanimated { + +class NewestShadowNodesRegistry { + public: + std::lock_guard createLock() const; + // returns a lock you need to hold when calling any of the methods below + + void set(ShadowNode::Shared shadowNode, Tag parentTag); + // updates ShadowNode and sets parent tag, to be called from Reanimated + + bool has(const ShadowNode::Shared &shadowNode) const; + // checks if ShadowNode exists in the registry + + ShadowNode::Shared get(Tag tag) const; + // returns the most recent version of ShadowNode or nullptr if not found + + void update(ShadowNode::Shared shadowNode); + // updates ShadowNode that already exists in registry, to be called from RN + + void remove(Tag tag); + // removes ShadowNode from map along with its ancestors + + private: + std::unordered_map> map_; + // tag -> (most recent clone of shadow node, parent tag) + mutable std::mutex mutex_; // Protects `map_`. +}; + +} // namespace reanimated + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/RuntimeManager.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/RuntimeManager.h new file mode 100644 index 00000000000000..7a0e546fec029e --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/RuntimeManager.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include "ErrorHandler.h" +#include "RuntimeDecorator.h" +#include "Scheduler.h" + +namespace reanimated { + +using namespace facebook; + +/** + A class that manages a jsi::Runtime apart from the React-JS runtime. + */ +class RuntimeManager { + public: + RuntimeManager( + std::shared_ptr runtime, + std::shared_ptr errorHandler, + std::shared_ptr scheduler, + RuntimeType runtimeType = RuntimeType::Worklet) + : runtime(runtime), errorHandler(errorHandler), scheduler(scheduler) { + RuntimeDecorator::registerRuntime(this->runtime.get(), runtimeType); + } + + /** + Holds the jsi::Runtime this RuntimeManager is managing. + */ + std::shared_ptr runtime; + /** + Holds the error handler that will be invoked when any kind of error occurs. + */ + std::shared_ptr errorHandler; + /** + Holds the Scheduler that is responsible for scheduling work on the UI- or + React-JS Thread. + */ + std::shared_ptr scheduler; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/Shareables.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/Shareables.cpp new file mode 100644 index 00000000000000..38ca82deef4558 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/Shareables.cpp @@ -0,0 +1,90 @@ +#include "Shareables.h" + +using namespace facebook; + +namespace reanimated { + +CoreFunction::CoreFunction( + JSRuntimeHelper *runtimeHelper, + const jsi::Value &workletValue) + : runtimeHelper_(runtimeHelper) { + jsi::Runtime &rt = *runtimeHelper->rnRuntime(); + auto workletObject = workletValue.asObject(rt); + rnFunction_ = std::make_unique(workletObject.asFunction(rt)); + functionBody_ = workletObject.getPropertyAsObject(rt, "__initData") + .getProperty(rt, "code") + .asString(rt) + .utf8(rt); + location_ = "worklet_" + + std::to_string(static_cast( + workletObject.getProperty(rt, "__workletHash").getNumber())); +} + +std::unique_ptr &CoreFunction::getFunction(jsi::Runtime &rt) { + if (runtimeHelper_->isUIRuntime(rt)) { + if (uiFunction_ == nullptr) { + // maybe need to initialize UI Function + // the newline before closing paren is needed because the last line can be + // an inline comment (specifically this happens when we attach source maps + // at the end) in which case the paren won't be parsed + auto codeBuffer = std::make_shared( + "(" + functionBody_ + "\n)"); + uiFunction_ = std::make_unique( + rt.evaluateJavaScript(codeBuffer, location_) + .asObject(rt) + .asFunction(rt)); + } + return uiFunction_; + } else { + // running on the main RN runtime + return rnFunction_; + } +} + +std::shared_ptr extractShareableOrThrow( + jsi::Runtime &rt, + const jsi::Value &maybeShareableValue, + const char *errorMessage) { + if (maybeShareableValue.isObject()) { + auto object = maybeShareableValue.asObject(rt); + if (object.isHostObject(rt)) { + return object.getHostObject(rt)->value(); + } + } else if (maybeShareableValue.isUndefined()) { + return Shareable::undefined(); + } + throw std::runtime_error( + errorMessage != nullptr + ? errorMessage + : "expecting the object to be of type ShareableJSRef"); +} + +Shareable::~Shareable() {} + +ShareableArray::ShareableArray(jsi::Runtime &rt, const jsi::Array &array) + : Shareable(ArrayType) { + auto size = array.size(rt); + data_.reserve(size); + for (size_t i = 0; i < size; i++) { + data_.push_back(extractShareableOrThrow(rt, array.getValueAtIndex(rt, i))); + } +} + +ShareableObject::ShareableObject(jsi::Runtime &rt, const jsi::Object &object) + : Shareable(ObjectType) { + auto propertyNames = object.getPropertyNames(rt); + auto size = propertyNames.size(rt); + data_.reserve(size); + for (size_t i = 0; i < size; i++) { + auto key = propertyNames.getValueAtIndex(rt, i).asString(rt); + auto value = extractShareableOrThrow(rt, object.getProperty(rt, key)); + data_.emplace_back(key.utf8(rt), value); + } +} + +std::shared_ptr Shareable::undefined() { + static auto undefined = std::make_shared(); + return undefined; +} + +} /* namespace reanimated */ diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/Shareables.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/Shareables.h new file mode 100644 index 00000000000000..d927f824b766d4 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/Shareables.h @@ -0,0 +1,497 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "ReanimatedRuntime.h" +#include "RuntimeManager.h" +#include "Scheduler.h" + +using namespace facebook; + +namespace reanimated { + +class JSRuntimeHelper; + +// Core functions are not allowed to capture outside variables, otherwise they'd +// try to access _closure variable which is something we want to avoid for +// simplicity reasons. +class CoreFunction { + private: + std::unique_ptr rnFunction_; + std::unique_ptr uiFunction_; + std::string functionBody_; + std::string location_; + JSRuntimeHelper + *runtimeHelper_; // runtime helper holds core function references, so we + // use normal pointer here to avoid ref cycles. + std::unique_ptr &getFunction(jsi::Runtime &rt); + + public: + CoreFunction(JSRuntimeHelper *runtimeHelper, const jsi::Value &workletObject); + template + jsi::Value call(jsi::Runtime &rt, Args &&...args) { + return getFunction(rt)->call(rt, args...); + } +}; + +class JSRuntimeHelper { + private: + jsi::Runtime *rnRuntime_; // React-Native's main JS runtime + jsi::Runtime *uiRuntime_; // UI runtime created by Reanimated + std::shared_ptr scheduler_; + + public: + JSRuntimeHelper( + jsi::Runtime *rnRuntime, + jsi::Runtime *uiRuntime, + const std::shared_ptr &scheduler) + : rnRuntime_(rnRuntime), uiRuntime_(uiRuntime), scheduler_(scheduler) {} + + volatile bool uiRuntimeDestroyed = false; + std::unique_ptr callGuard; + std::unique_ptr valueUnpacker; + + inline jsi::Runtime *uiRuntime() const { + return uiRuntime_; + } + + inline jsi::Runtime *rnRuntime() const { + return rnRuntime_; + } + + inline bool isUIRuntime(const jsi::Runtime &rt) const { + return &rt == uiRuntime_; + } + + inline bool isRNRuntime(const jsi::Runtime &rt) const { + return &rt == rnRuntime_; + } + + void scheduleOnUI(std::function job) { + scheduler_->scheduleOnUI(job); + } + + void scheduleOnJS(std::function job) { + scheduler_->scheduleOnJS(job); + } + + template + inline void runOnUIGuarded(const jsi::Value &function, Args &&...args) { + // We only use callGuard in debug mode, otherwise we call the provided + // function directly. CallGuard provides a way of capturing exceptions in + // JavaScript and propagating them to the main React Native thread such that + // they can be presented using RN's LogBox. + jsi::Runtime &rt = *uiRuntime_; +#ifdef DEBUG + callGuard->call(rt, function, args...); +#else + function.asObject(rt).asFunction(rt).call(rt, args...); +#endif + } +}; + +class Shareable { + protected: + virtual jsi::Value toJSValue(jsi::Runtime &rt) = 0; + + public: + virtual ~Shareable(); + + enum ValueType { + UndefinedType, + NullType, + BooleanType, + NumberType, + // SymbolType, TODO + // BigIntType, TODO + StringType, + ObjectType, + ArrayType, + WorkletType, + RemoteFunctionType, + HandleType, + SynchronizedDataHolder, + HostObjectType, + HostFunctionType, + }; + + explicit Shareable(ValueType valueType) : valueType_(valueType) {} + virtual jsi::Value getJSValue(jsi::Runtime &rt) { + return toJSValue(rt); + } + + inline ValueType valueType() const { + return valueType_; + } + + static std::shared_ptr undefined(); + + protected: + ValueType valueType_; +}; + +template +class RetainingShareable : virtual public BaseClass { + private: + std::shared_ptr runtimeHelper_; + std::unique_ptr remoteValue_; + + public: + template + RetainingShareable( + const std::shared_ptr &runtimeHelper, + Args &&...args) + : BaseClass(std::forward(args)...), runtimeHelper_(runtimeHelper) {} + jsi::Value getJSValue(jsi::Runtime &rt) { + if (runtimeHelper_->isRNRuntime(rt)) { + // TODO: it is suboptimal to generate new object every time getJS is + // called on host runtime – the objects we are generating already exists + // and we should possibly just grab a hold of such object and use it here + // instead of creating a new JS representation. As far as I understand the + // only case where it can be realistically called this way is when a + // shared value is created and then accessed on the same runtime + return BaseClass::toJSValue(rt); + } else if (remoteValue_ == nullptr) { + auto value = BaseClass::toJSValue(rt); + remoteValue_ = std::make_unique(rt, value); + return value; + } + return jsi::Value(rt, *remoteValue_); + } + ~RetainingShareable() { + if (runtimeHelper_->uiRuntimeDestroyed) { + // The below use of unique_ptr.release prevents the smart pointer from + // calling the destructor of the kept object. This effectively results in + // leaking some memory. We do this on purpose, as sometimes we would keep + // references to JSI objects past the lifetime of its runtime (e.g., + // shared values references from the RN VM holds reference to JSI objects + // on the UI runtime). When the UI runtime is terminated, the orphaned JSI + // objects would crash the app when their destructors are called, because + // they call into a memory that's managed by the terminated runtime. We + // accept the tradeoff of leaking memory here, as it has a limited impact. + // This scenario can only occur when the React instance is torn down which + // happens in development mode during app reloads, or in production when + // the app is being shut down gracefully by the system. An alternative + // solution would require us to keep track of all JSI values that are in + // use which would require additional data structure and compute spent on + // bookkeeping that only for the sake of destroying the values in time + // before the runtime is terminated. Note that the underlying memory that + // jsi::Value refers to is managed by the VM and gets freed along with the + // runtime. + remoteValue_.release(); + } + } +}; + +class ShareableJSRef : public jsi::HostObject { + private: + std::shared_ptr value_; + + public: + explicit ShareableJSRef(std::shared_ptr value) : value_(value) {} + std::shared_ptr value() const { + return value_; + } + + static jsi::Object newHostObject( + jsi::Runtime &rt, + const std::shared_ptr &value) { + return jsi::Object::createFromHostObject( + rt, std::make_shared(value)); + } +}; + +std::shared_ptr extractShareableOrThrow( + jsi::Runtime &rt, + const jsi::Value &maybeShareableValue, + const char *errorMessage = nullptr); + +template +std::shared_ptr extractShareableOrThrow( + jsi::Runtime &rt, + const jsi::Value &shareableRef, + const char *errorMessage = nullptr) { + auto res = std::dynamic_pointer_cast( + extractShareableOrThrow(rt, shareableRef, errorMessage)); + if (!res) { + throw new std::runtime_error( + errorMessage != nullptr + ? errorMessage + : "provided shareable object is of an incompatible type"); + } + return res; +} + +class ShareableArray : public Shareable { + public: + ShareableArray(jsi::Runtime &rt, const jsi::Array &array); + + jsi::Value toJSValue(jsi::Runtime &rt) override { + auto size = data_.size(); + auto ary = jsi::Array(rt, size); + for (size_t i = 0; i < size; i++) { + ary.setValueAtIndex(rt, i, data_[i]->getJSValue(rt)); + } + return ary; + } + + protected: + std::vector> data_; +}; + +class ShareableObject : public Shareable { + public: + ShareableObject(jsi::Runtime &rt, const jsi::Object &object); + jsi::Value toJSValue(jsi::Runtime &rt) override { + auto obj = jsi::Object(rt); + for (size_t i = 0, size = data_.size(); i < size; i++) { + obj.setProperty( + rt, data_[i].first.c_str(), data_[i].second->getJSValue(rt)); + } + return obj; + } + + protected: + std::vector>> data_; +}; + +class ShareableHostObject : public Shareable { + public: + ShareableHostObject( + const std::shared_ptr &runtimeHelper, + jsi::Runtime &rt, + const std::shared_ptr &hostObject) + : Shareable(HostObjectType), hostObject_(hostObject) {} + jsi::Value toJSValue(jsi::Runtime &rt) override { + return jsi::Object::createFromHostObject(rt, hostObject_); + } + + protected: + std::shared_ptr hostObject_; +}; + +class ShareableHostFunction : public Shareable { + public: + ShareableHostFunction(jsi::Runtime &rt, jsi::Function function) + : Shareable(HostFunctionType), + hostFunction_( + (assert(function.isHostFunction(rt)), + function.getHostFunction(rt))), + name_(function.getProperty(rt, "name").asString(rt).utf8(rt)), + paramCount_(function.getProperty(rt, "length").asNumber()) {} + + jsi::Value toJSValue(jsi::Runtime &rt) override { + return jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forUtf8(rt, name_), paramCount_, hostFunction_); + } + + protected: + jsi::HostFunctionType hostFunction_; + std::string name_; + unsigned int paramCount_; +}; + +class ShareableWorklet : public ShareableObject { + private: + std::shared_ptr runtimeHelper_; + + public: + ShareableWorklet( + const std::shared_ptr &runtimeHelper, + jsi::Runtime &rt, + const jsi::Object &worklet) + : ShareableObject(rt, worklet), runtimeHelper_(runtimeHelper) { + valueType_ = WorkletType; + } + jsi::Value toJSValue(jsi::Runtime &rt) override { + jsi::Value obj = ShareableObject::toJSValue(rt); + return runtimeHelper_->valueUnpacker->call(rt, obj); + } +}; + +class ShareableRemoteFunction + : public Shareable, + public std::enable_shared_from_this { + private: + jsi::Function function_; + std::shared_ptr runtimeHelper_; + + public: + ShareableRemoteFunction( + const std::shared_ptr &runtimeHelper, + jsi::Runtime &rt, + jsi::Function &&function) + : Shareable(RemoteFunctionType), + function_(std::move(function)), + runtimeHelper_(runtimeHelper) {} + jsi::Value toJSValue(jsi::Runtime &rt) override { + if (runtimeHelper_->isUIRuntime(rt)) { +#ifdef DEBUG + return runtimeHelper_->valueUnpacker->call( + rt, + ShareableJSRef::newHostObject(rt, shared_from_this()), + jsi::String::createFromAscii(rt, "RemoteFunction")); +#else + return ShareableJSRef::newHostObject(rt, shared_from_this()); +#endif + } else { + return jsi::Value(rt, function_); + } + } +}; + +class ShareableHandle : public Shareable { + private: + std::shared_ptr runtimeHelper_; + std::unique_ptr initializer_; + std::unique_ptr remoteValue_; + + public: + ShareableHandle( + const std::shared_ptr runtimeHelper, + jsi::Runtime &rt, + const jsi::Object &initializerObject) + : Shareable(HandleType), runtimeHelper_(runtimeHelper) { + initializer_ = std::make_unique(rt, initializerObject); + } + ~ShareableHandle() { + if (runtimeHelper_->uiRuntimeDestroyed) { + // The below use of unique_ptr.release prevents the smart pointer from + // calling the destructor of the kept object. This effectively results in + // leaking some memory. We do this on purpose, as sometimes we would keep + // references to JSI objects past the lifetime of its runtime (e.g., + // shared values references from the RN VM holds reference to JSI objects + // on the UI runtime). When the UI runtime is terminated, the orphaned JSI + // objects would crash the app when their destructors are called, because + // they call into a memory that's managed by the terminated runtime. We + // accept the tradeoff of leaking memory here, as it has a limited impact. + // This scenario can only occur when the React instance is torn down which + // happens in development mode during app reloads, or in production when + // the app is being shut down gracefully by the system. An alternative + // solution would require us to keep track of all JSI values that are in + // use which would require additional data structure and compute spent on + // bookkeeping that only for the sake of destroying the values in time + // before the runtime is terminated. Note that the underlying memory that + // jsi::Value refers to is managed by the VM and gets freed along with the + // runtime. + remoteValue_.release(); + } + } + jsi::Value toJSValue(jsi::Runtime &rt) override { + if (initializer_ != nullptr) { + auto initObj = initializer_->getJSValue(rt); + remoteValue_ = std::make_unique( + runtimeHelper_->valueUnpacker->call(rt, initObj)); + initializer_ = nullptr; // we can release ref to initializer as this + // method should be called at most once + } + return jsi::Value(rt, *remoteValue_); + } +}; + +class ShareableSynchronizedDataHolder + : public Shareable, + public std::enable_shared_from_this { + private: + std::shared_ptr runtimeHelper_; + std::shared_ptr data_; + std::shared_ptr uiValue_; + std::shared_ptr rnValue_; + std::mutex dataAccessMutex_; // Protects `data_`. + + public: + ShareableSynchronizedDataHolder( + std::shared_ptr runtimeHelper, + jsi::Runtime &rt, + const jsi::Value &initialValue) + : Shareable(SynchronizedDataHolder), + runtimeHelper_(runtimeHelper), + data_(extractShareableOrThrow(rt, initialValue)) {} + + jsi::Value get(jsi::Runtime &rt) { + std::unique_lock read_lock(dataAccessMutex_); + if (runtimeHelper_->isUIRuntime(rt)) { + if (uiValue_ == nullptr) { + auto value = data_->getJSValue(rt); + uiValue_ = std::make_shared(rt, value); + return value; + } else { + return jsi::Value(rt, *uiValue_); + } + } else { + if (rnValue_ == nullptr) { + auto value = data_->getJSValue(rt); + rnValue_ = std::make_shared(rt, value); + return value; + } else { + return jsi::Value(rt, *rnValue_); + } + } + } + + void set(jsi::Runtime &rt, const jsi::Value &data) { + std::unique_lock write_lock(dataAccessMutex_); + data_ = extractShareableOrThrow(rt, data); + uiValue_.reset(); + rnValue_.reset(); + } + + jsi::Value toJSValue(jsi::Runtime &rt) override { + return ShareableJSRef::newHostObject(rt, shared_from_this()); + }; +}; + +class ShareableString : public Shareable { + public: + explicit ShareableString(const std::string &string) + : Shareable(StringType), data_(string) {} + jsi::Value toJSValue(jsi::Runtime &rt) override { + return jsi::String::createFromUtf8(rt, data_); + } + + protected: + std::string data_; +}; + +class ShareableScalar : public Shareable { + public: + explicit ShareableScalar(double number) : Shareable(NumberType) { + data_.number = number; + } + explicit ShareableScalar(bool boolean) : Shareable(BooleanType) { + data_.boolean = boolean; + } + ShareableScalar() : Shareable(UndefinedType) {} + explicit ShareableScalar(std::nullptr_t) : Shareable(NullType) {} + + jsi::Value toJSValue(jsi::Runtime &rt) override { + switch (valueType_) { + case Shareable::UndefinedType: + return jsi::Value(); + case Shareable::NullType: + return jsi::Value(nullptr); + case Shareable::BooleanType: + return jsi::Value(data_.boolean); + case Shareable::NumberType: + return jsi::Value(data_.number); + default: + throw std::runtime_error( + "attempted to convert object that's not of a scalar type"); + } + } + + protected: + union Data { + bool boolean; + double number; + }; + + private: + Data data_; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/SharedParent.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/SharedParent.h new file mode 100644 index 00000000000000..8f3085066e1d10 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SharedItems/SharedParent.h @@ -0,0 +1,30 @@ +#pragma once + +namespace reanimated { + +enum class ValueType { + UndefinedType, + NullType, + BoolType, + NumberType, + StringType, + RemoteObjectType, // object that can be instantiated on host side and modified + // on the remote (worklet) side + MutableValueType, // object with 'value' property that can be updated and read + // from any thread + HostFunctionType, // function that will be executed asynchronously on the host + // runtime + WorkletFunctionType, // function that gets run on the UI thread + FrozenObjectType, // frozen object, can only be set and never modified + FrozenArrayType, // frozen array, can only be set and never modified +#ifdef RCT_NEW_ARCH_ENABLED + ShadowNodeType, // ShadowNode::Shared +#endif // RCT_NEW_ARCH_ENABLED +}; + +class ShareableValue; +class MutableValue; +class RemoteObject; +class NativeReanimatedModule; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/SpecTools/ErrorHandler.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SpecTools/ErrorHandler.h new file mode 100644 index 00000000000000..b19b8f00e83469 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/SpecTools/ErrorHandler.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#ifdef __APPLE__ +#include "RNReanimated/Scheduler.h" +#else +#include "Scheduler.h" +#endif + +namespace reanimated { + +struct ErrorWrapper { + std::string message = ""; + bool handled = true; +}; + +class ErrorHandler { + public: + bool raise() { + if (getError()->handled) { + return false; + } + this->getScheduler()->scheduleOnUI([this]() mutable { this->raiseSpec(); }); + return true; + } + virtual std::shared_ptr getScheduler() = 0; + virtual std::shared_ptr getError() = 0; + virtual void setError(std::string message) = 0; + virtual ~ErrorHandler() {} + + protected: + virtual void raiseSpec() = 0; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/CollectionUtils.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/CollectionUtils.h new file mode 100644 index 00000000000000..451b8bf927e8cf --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/CollectionUtils.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace reanimated { +namespace collection { + +template +inline bool contains(CollectionType &collection, const ValueType &value) { + return collection.find(value) != collection.end(); +} + +} // namespace collection +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/FeaturesConfig.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/FeaturesConfig.cpp new file mode 100644 index 00000000000000..ed4867d933c901 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/FeaturesConfig.cpp @@ -0,0 +1,5 @@ +#include "FeaturesConfig.h" + +namespace reanimated { +bool FeaturesConfig::_isLayoutAnimationEnabled = false; +} diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/FeaturesConfig.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/FeaturesConfig.h new file mode 100644 index 00000000000000..c07e82449a17e4 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/FeaturesConfig.h @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace reanimated { + +class FeaturesConfig { + public: + static inline bool isLayoutAnimationEnabled() { + return _isLayoutAnimationEnabled; + } + static inline void setLayoutAnimationEnabled(bool isLayoutAnimationEnabled) { + _isLayoutAnimationEnabled = isLayoutAnimationEnabled; + } + + private: + static bool _isLayoutAnimationEnabled; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/JsiUtils.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/JsiUtils.cpp new file mode 100644 index 00000000000000..71c942b9bf3480 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/JsiUtils.cpp @@ -0,0 +1,26 @@ +#include "JsiUtils.h" +#include + +using namespace facebook; + +namespace reanimated::jsi_utils { + +jsi::Array convertStringToArray( + jsi::Runtime &rt, + const std::string &value, + const unsigned int expectedSize) { + std::vector transformMatrixList; + std::istringstream stringStream(value); + std::copy( + std::istream_iterator(stringStream), + std::istream_iterator(), + std::back_inserter(transformMatrixList)); + assert(transformMatrixList.size() == expectedSize); + jsi::Array matrix(rt, expectedSize); + for (int i = 0; i < expectedSize; i++) { + matrix.setValueAtIndex(rt, i, transformMatrixList[i]); + } + return matrix; +} + +} // namespace reanimated::jsi_utils diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/JsiUtils.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/JsiUtils.h new file mode 100644 index 00000000000000..8f3ccb3f2c7678 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/JsiUtils.h @@ -0,0 +1,176 @@ +#pragma once + +#include +#include +#include +#include +#include + +using namespace facebook; + +namespace reanimated { +namespace jsi_utils { + +// `get` functions take a pointer to `jsi::Value` and +// call an appropriate method to cast to the native type +template +inline T get(jsi::Runtime &rt, const jsi::Value *value); + +template <> +inline double get(jsi::Runtime &rt, const jsi::Value *value) { + return value->asNumber(); +} + +template <> +inline int get(jsi::Runtime &rt, const jsi::Value *value) { + return value->asNumber(); +} + +template <> +inline bool get(jsi::Runtime &rt, const jsi::Value *value) { + if (!value->isBool()) { + throw jsi::JSINativeException("Expected a boolean"); + } + return value->getBool(); +} + +template <> +inline jsi::Object get(jsi::Runtime &rt, const jsi::Value *value) { + return value->asObject(rt); +} + +template <> +inline jsi::Value const &get( + jsi::Runtime &rt, + const jsi::Value *value) { + return *value; +} + +// `convertArgs` functions take a variadic template parameter of target (C++) +// argument types `Targs` and a `jsi::Value` array `args`, and converts `args` +// to a tuple of typed C++ arguments to be passed to the native implementation. +// This is accomplished by dispatching (at compile time) to the correct +// implementation based on the first type of `Targs`, using SFINAE to select the +// correct specialization, and concatenating with the result of recursion on the +// rest of `Targs` + +// BEGIN implementations for `convertArgs` specializations. +// specialization for empty `Targs` - returns an empty tuple +template +inline std::enable_if_t<(sizeof...(Args) == 0), std::tuple<>> convertArgs( + jsi::Runtime &rt, + const jsi::Value *args) { + return std::make_tuple(); +} + +// calls `get` on the first argument to retrieve the native type, +// then calls recursively on the rest of `args` +// and returns the concatenation of results +template +inline std::tuple convertArgs( + jsi::Runtime &rt, + const jsi::Value *args) { + auto arg = std::tuple(get(rt, args)); + auto rest = convertArgs(rt, std::next(args)); + return std::tuple_cat(std::move(arg), std::move(rest)); +} +// END implementations for `convertArgs` specializations. + +// returns a tuple with the result of casting `args` to appropriate +// native C++ types needed to call `function` +template +std::tuple getArgsForFunction( + std::function function, + jsi::Runtime &rt, + const jsi::Value *args, + const size_t count) { + assert(sizeof...(Args) == count); + return convertArgs(rt, args); +} + +// returns a tuple with the result of casting `args` to appropriate +// native C++ types needed to call `function`, +// passing `rt` as the first argument +template +std::tuple getArgsForFunction( + std::function function, + jsi::Runtime &rt, + const jsi::Value *args, + const size_t count) { + assert(sizeof...(Args) == count); + return std::tuple_cat(std::tie(rt), convertArgs(rt, args)); +} + +// calls `function` with `args` +template +inline jsi::Value apply( + std::function function, + std::tuple args) { + return std::apply(function, std::move(args)); +} + +// calls void-returning `function` with `args`, +// and returns `undefined` +template +inline jsi::Value apply( + std::function function, + std::tuple args) { + std::apply(function, std::move(args)); + return jsi::Value::undefined(); +} + +// returns a function with JSI calling convention +// from a native function `function` +template +jsi::HostFunctionType createHostFunction(Fun function) { + return [function]( + jsi::Runtime &rt, + const jsi::Value &thisValue, + const jsi::Value *args, + const size_t count) { + auto argz = getArgsForFunction(function, rt, args, count); + return apply(function, std::move(argz)); + }; +} + +// used to determine if `function` +// takes `Runtime &` as its first argument +template +struct takes_runtime { + static constexpr size_t value = 0; +}; + +// specialization for `function +struct takes_runtime { + static constexpr size_t value = 1; +}; + +// creates a JSI compatible function from `function` +// and installs it as a global function named `name` +// in the `rt` JS runtime +template +void installJsiFunction( + jsi::Runtime &rt, + std::string_view name, + std::function function) { + auto clb = createHostFunction(function); + auto argsCount = sizeof...(Args) - takes_runtime::value; + jsi::Value jsiFunction = jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, name.data()), argsCount, clb); + rt.global().setProperty(rt, name.data(), jsiFunction); +} + +// this should take care of passing types convertible to `function` +template +void installJsiFunction(jsi::Runtime &rt, std::string_view name, Fun function) { + installJsiFunction(rt, name, std::function(std::forward(function))); +} + +jsi::Array convertStringToArray( + jsi::Runtime &rt, + const std::string &value, + const unsigned int expectedSize); + +} // namespace jsi_utils +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/PlatformDepMethodsHolder.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/PlatformDepMethodsHolder.h new file mode 100644 index 00000000000000..db0315f8630852 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/PlatformDepMethodsHolder.h @@ -0,0 +1,94 @@ +#pragma once + +#include + +#ifdef RCT_NEW_ARCH_ENABLED +#include +#endif + +#include +#include +#include + +using namespace facebook; + +#ifdef RCT_NEW_ARCH_ENABLED +using namespace react; +#endif + +namespace reanimated { + +#ifdef RCT_NEW_ARCH_ENABLED + +using SynchronouslyUpdateUIPropsFunction = + std::function; +using UpdatePropsFunction = std::function; +using RemoveShadowNodeFromRegistryFunction = + std::function; +using DispatchCommandFunction = std::function; +using MeasureFunction = std::function< + jsi::Value(jsi::Runtime &rt, const jsi::Value &shadowNodeValue)>; + +#else + +using UpdatePropsFunction = std::function; +using ScrollToFunction = std::function; +using MeasureFunction = + std::function>(int)>; + +#endif // RCT_NEW_ARCH_ENABLED + +using RequestRender = + std::function, jsi::Runtime &rt)>; +using TimeProviderFunction = std::function; + +using ProgressLayoutAnimationFunction = + std::function; +using EndLayoutAnimationFunction = std::function; + +using RegisterSensorFunction = + std::function)>; +using UnregisterSensorFunction = std::function; +using SetGestureStateFunction = std::function; +using ConfigurePropsFunction = std::function; +using KeyboardEventSubscribeFunction = + std::function, bool)>; +using KeyboardEventUnsubscribeFunction = std::function; +using MaybeFlushUIUpdatesQueueFunction = std::function; + +struct PlatformDepMethodsHolder { + RequestRender requestRender; +#ifdef RCT_NEW_ARCH_ENABLED + SynchronouslyUpdateUIPropsFunction synchronouslyUpdateUIPropsFunction; +#else + UpdatePropsFunction updatePropsFunction; + ScrollToFunction scrollToFunction; + MeasureFunction measureFunction; + ConfigurePropsFunction configurePropsFunction; +#endif + TimeProviderFunction getCurrentTime; + ProgressLayoutAnimationFunction progressLayoutAnimation; + EndLayoutAnimationFunction endLayoutAnimation; + RegisterSensorFunction registerSensor; + UnregisterSensorFunction unregisterSensor; + SetGestureStateFunction setGestureStateFunction; + KeyboardEventSubscribeFunction subscribeForKeyboardEvents; + KeyboardEventUnsubscribeFunction unsubscribeFromKeyboardEvents; + MaybeFlushUIUpdatesQueueFunction maybeFlushUIUpdatesQueueFunction; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedHiddenHeaders.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedHiddenHeaders.h new file mode 100644 index 00000000000000..c1a05456d8c782 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedHiddenHeaders.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef ANDROID +#include "Logger.h" +#include "LoggerInterface.h" +#include "SpeedChecker.h" +#else +#include "Common/cpp/hidden_headers/Logger.h" +#include "Common/cpp/hidden_headers/LoggerInterface.h" +#include "Common/cpp/hidden_headers/SpeedChecker.h" +#endif diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedVersion.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedVersion.cpp new file mode 100644 index 00000000000000..d374943e2a716b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedVersion.cpp @@ -0,0 +1,17 @@ +#include "ReanimatedVersion.h" + +#ifdef REANIMATED_VERSION +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define REANIMATED_VERSION_STRING STRINGIZE2(REANIMATED_VERSION) +#endif // REANIMATED_VERSION + +using namespace facebook; + +namespace reanimated { + +jsi::String getReanimatedVersionString(jsi::Runtime &rt) { + return jsi::String::createFromUtf8(rt, REANIMATED_VERSION_STRING); +} + +}; // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedVersion.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedVersion.h new file mode 100644 index 00000000000000..895669dceaad3c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/ReanimatedVersion.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +using namespace facebook; + +namespace reanimated { + +jsi::String getReanimatedVersionString(jsi::Runtime &rt); + +}; diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/RuntimeDecorator.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/RuntimeDecorator.cpp new file mode 100644 index 00000000000000..e7f1a26695bde6 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/RuntimeDecorator.cpp @@ -0,0 +1,154 @@ +#include "RuntimeDecorator.h" +#include +#include +#include +#include +#include +#include "JsiUtils.h" +#include "ReanimatedHiddenHeaders.h" + +namespace reanimated { + +static const std::function logValue = + [](jsi::Runtime &rt, jsi::Value const &value) { + if (value.isString()) { + Logger::log(value.getString(rt).utf8(rt).c_str()); + } else if (value.isNumber()) { + Logger::log(value.getNumber()); + } else if (value.isUndefined()) { + Logger::log("undefined"); + } else { + Logger::log("unsupported value type"); + } + }; + +std::unordered_map + &RuntimeDecorator::runtimeRegistry() { + static std::unordered_map runtimeRegistry; + return runtimeRegistry; +} + +void RuntimeDecorator::registerRuntime( + jsi::Runtime *runtime, + RuntimeType runtimeType) { + runtimeRegistry().insert({runtime, runtimeType}); +} + +void RuntimeDecorator::decorateRuntime( + jsi::Runtime &rt, + const std::string &label) { + // This property will be used to find out if a runtime is a custom worklet + // runtime (e.g. UI, VisionCamera frame processor, ...) + rt.global().setProperty(rt, "_WORKLET", jsi::Value(true)); + // This property will be used for debugging + rt.global().setProperty( + rt, "_LABEL", jsi::String::createFromAscii(rt, label)); + + rt.global().setProperty(rt, "global", rt.global()); + +#ifdef DEBUG + auto evalWithSourceUrl = [](jsi::Runtime &rt, + const jsi::Value &thisValue, + const jsi::Value *args, + size_t count) -> jsi::Value { + auto code = std::make_shared( + args[0].asString(rt).utf8(rt)); + std::string url; + if (count > 1 && args[1].isString()) { + url = args[1].asString(rt).utf8(rt); + } + + return rt.evaluateJavaScript(code, url); + }; + + rt.global().setProperty( + rt, + "evalWithSourceUrl", + jsi::Function::createFromHostFunction( + rt, + jsi::PropNameID::forAscii(rt, "evalWithSourceUrl"), + 1, + evalWithSourceUrl)); +#endif // DEBUG + + jsi_utils::installJsiFunction(rt, "_log", logValue); +} + +void RuntimeDecorator::decorateUIRuntime( + jsi::Runtime &rt, + const UpdatePropsFunction updateProps, + const MeasureFunction measure, +#ifdef RCT_NEW_ARCH_ENABLED + const RemoveShadowNodeFromRegistryFunction removeShadowNodeFromRegistry, + const DispatchCommandFunction dispatchCommand, +#else + const ScrollToFunction scrollTo, +#endif + const RequestFrameFunction requestFrame, + const ScheduleOnJSFunction scheduleOnJS, + const MakeShareableCloneFunction makeShareableClone, + const UpdateDataSynchronouslyFunction updateDataSynchronously, + const TimeProviderFunction getCurrentTime, + const SetGestureStateFunction setGestureState, + const ProgressLayoutAnimationFunction progressLayoutAnimationFunction, + const EndLayoutAnimationFunction endLayoutAnimationFunction, + const MaybeFlushUIUpdatesQueueFunction maybeFlushUIUpdatesQueueFunction) { + RuntimeDecorator::decorateRuntime(rt, "UI"); + rt.global().setProperty(rt, "_UI", jsi::Value(true)); + +#ifdef RCT_NEW_ARCH_ENABLED + jsi_utils::installJsiFunction(rt, "_updatePropsFabric", updateProps); + jsi_utils::installJsiFunction( + rt, "_removeShadowNodeFromRegistry", removeShadowNodeFromRegistry); + jsi_utils::installJsiFunction(rt, "_dispatchCommand", dispatchCommand); + jsi_utils::installJsiFunction(rt, "_measure", measure); +#else + jsi_utils::installJsiFunction(rt, "_updatePropsPaper", updateProps); + jsi_utils::installJsiFunction(rt, "_scrollTo", scrollTo); + + std::function _measure = + [measure](jsi::Runtime &rt, int viewTag) -> jsi::Value { + auto result = measure(viewTag); + jsi::Object resultObject(rt); + for (auto &i : result) { + resultObject.setProperty(rt, i.first.c_str(), i.second); + } + return resultObject; + }; + + jsi_utils::installJsiFunction(rt, "_measure", _measure); +#endif // RCT_NEW_ARCH_ENABLED + + jsi_utils::installJsiFunction(rt, "requestAnimationFrame", requestFrame); + jsi_utils::installJsiFunction(rt, "_scheduleOnJS", scheduleOnJS); + jsi_utils::installJsiFunction(rt, "_makeShareableClone", makeShareableClone); + jsi_utils::installJsiFunction( + rt, "_updateDataSynchronously", updateDataSynchronously); + + auto performanceNow = [getCurrentTime]( + jsi::Runtime &rt, + const jsi::Value &thisValue, + const jsi::Value *args, + size_t count) -> jsi::Value { + return jsi::Value(getCurrentTime()); + }; + jsi::Object performance(rt); + performance.setProperty( + rt, + "now", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "now"), 0, performanceNow)); + rt.global().setProperty(rt, "performance", performance); + + // layout animation + jsi_utils::installJsiFunction( + rt, "_notifyAboutProgress", progressLayoutAnimationFunction); + jsi_utils::installJsiFunction( + rt, "_notifyAboutEnd", endLayoutAnimationFunction); + + jsi_utils::installJsiFunction(rt, "_setGestureState", setGestureState); + jsi_utils::installJsiFunction( + rt, "_maybeFlushUIUpdatesQueue", maybeFlushUIUpdatesQueueFunction); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/RuntimeDecorator.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/RuntimeDecorator.h new file mode 100644 index 00000000000000..8f81c8b9a30d49 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/RuntimeDecorator.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "PlatformDepMethodsHolder.h" + +using namespace facebook; + +namespace reanimated { + +using RequestFrameFunction = + std::function; +using ScheduleOnJSFunction = + std::function; +using MakeShareableCloneFunction = + std::function; +using UpdateDataSynchronouslyFunction = + std::function; + +enum RuntimeType { + /** + Represents any runtime that supports the concept of workletization + */ + Worklet, + /** + Represents the Reanimated UI worklet runtime specifically + */ + UI +}; +typedef jsi::Runtime *RuntimePointer; + +class RuntimeDecorator { + public: + static void decorateRuntime(jsi::Runtime &rt, const std::string &label); + static void decorateUIRuntime( + jsi::Runtime &rt, + const UpdatePropsFunction updateProps, + const MeasureFunction measure, +#ifdef RCT_NEW_ARCH_ENABLED + const RemoveShadowNodeFromRegistryFunction removeShadowNodeFromRegistry, + const DispatchCommandFunction dispatchCommand, +#else + const ScrollToFunction scrollTo, +#endif + const RequestFrameFunction requestFrame, + const ScheduleOnJSFunction scheduleOnJS, + const MakeShareableCloneFunction makeShareableClone, + const UpdateDataSynchronouslyFunction updateDataSynchronously, + const TimeProviderFunction getCurrentTime, + const SetGestureStateFunction setGestureState, + const ProgressLayoutAnimationFunction progressLayoutAnimationFunction, + const EndLayoutAnimationFunction endLayoutAnimationFunction, + const MaybeFlushUIUpdatesQueueFunction maybeFlushUIUpdatesQueueFunction); + + /** + Returns true if the given Runtime is the Reanimated UI-Thread Runtime. + */ + inline static bool isUIRuntime(jsi::Runtime &rt); + /** + Returns true if the given Runtime is a Runtime that supports the concept of + Workletization. (REA, Vision, ...) + */ + inline static bool isWorkletRuntime(jsi::Runtime &rt); + /** + Returns true if the given Runtime is the default React-JS Runtime. + */ + inline static bool isReactRuntime(jsi::Runtime &rt); + /** + Register the given Runtime. This function is required for every + RuntimeManager, otherwise future runtime checks will fail. + */ + static void registerRuntime(jsi::Runtime *runtime, RuntimeType runtimeType); + + private: + static std::unordered_map &runtimeRegistry(); +}; + +inline bool RuntimeDecorator::isUIRuntime(jsi::Runtime &rt) { + auto iterator = runtimeRegistry().find(&rt); + if (iterator == runtimeRegistry().end()) + return false; + return iterator->second == RuntimeType::UI; +} + +inline bool RuntimeDecorator::isWorkletRuntime(jsi::Runtime &rt) { + auto iterator = runtimeRegistry().find(&rt); + if (iterator == runtimeRegistry().end()) + return false; + auto type = iterator->second; + return type == RuntimeType::UI || type == RuntimeType::Worklet; +} + +inline bool RuntimeDecorator::isReactRuntime(jsi::Runtime &rt) { + auto iterator = runtimeRegistry().find(&rt); + if (iterator == runtimeRegistry().end()) + return true; + return false; +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/Scheduler.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/Scheduler.cpp new file mode 100644 index 00000000000000..fc429ba4a12270 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/Scheduler.cpp @@ -0,0 +1,51 @@ +#ifdef __APPLE__ +#include +#else +#include "Scheduler.h" +#endif +#include "ReanimatedRuntime.h" +#include "RuntimeManager.h" + +namespace reanimated { + +void Scheduler::scheduleOnUI(std::function job) { + uiJobs.push(std::move(job)); +} + +void Scheduler::scheduleOnJS(std::function job) { + jsCallInvoker_->invokeAsync(std::move(job)); +} + +void Scheduler::triggerUI() { + scheduledOnUI = false; +#if JS_RUNTIME_HERMES + // JSI's scope defined here allows for JSI-objects to be cleared up after + // each runtime loop. Within these loops we typically create some temporary + // JSI objects and hence it allows for such objects to be garbage collected + // much sooner. + // Apparently the scope API is only supported on Hermes at the moment. + auto scope = jsi::Scope(*runtimeManager.lock()->runtime); +#endif + while (uiJobs.getSize()) { + auto job = uiJobs.pop(); + job(); + } +} + +void Scheduler::setJSCallInvoker( + std::shared_ptr jsCallInvoker) { + jsCallInvoker_ = jsCallInvoker; +} + +void Scheduler::setRuntimeManager( + std::shared_ptr runtimeManager) { + this->runtimeManager = runtimeManager; +} + +Scheduler::~Scheduler() {} + +Scheduler::Scheduler() { + this->scheduledOnUI = false; +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/Scheduler.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/Scheduler.h new file mode 100644 index 00000000000000..295dbeb5a859ea --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/Scheduler.h @@ -0,0 +1,89 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace reanimated { + +// +// Copyright (c) 2013 Juan Palacios juan.palacios.puyana@gmail.com +// Subject to the BSD 2-Clause License +// - see < http://opensource.org/licenses/BSD-2-Clause> +// +template +class Queue { + public: + T pop() { + std::unique_lock mlock(mutex_); + while (queue_.empty()) { + cond_.wait(mlock); + } + auto item = queue_.front(); + queue_.pop(); + return item; + } + + void pop(T &item) { + std::unique_lock mlock(mutex_); + while (queue_.empty()) { + cond_.wait(mlock); + } + item = queue_.front(); + queue_.pop(); + } + + void push(const T &item) { + std::unique_lock mlock(mutex_); + queue_.push(item); + mlock.unlock(); + cond_.notify_one(); + } + + void push(T &&item) { + std::unique_lock mlock(mutex_); + queue_.push(std::move(item)); + mlock.unlock(); + cond_.notify_one(); + } + + size_t getSize() { + std::unique_lock mlock(mutex_); + const size_t res = queue_.size(); + mlock.unlock(); + cond_.notify_one(); + return res; + } + + private: + std::queue queue_; + std::mutex mutex_; + std::condition_variable cond_; +}; + +class RuntimeManager; + +class Scheduler { + public: + Scheduler(); + void scheduleOnJS(std::function job); + void setJSCallInvoker( + std::shared_ptr jsCallInvoker); + void setRuntimeManager(std::shared_ptr runtimeManager); + virtual void scheduleOnUI(std::function job); + virtual void triggerUI(); + virtual ~Scheduler(); + + protected: + std::atomic scheduledOnUI{}; + Queue> uiJobs; + std::shared_ptr jsCallInvoker_; + std::weak_ptr runtimeManager; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/SingleInstanceChecker.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/SingleInstanceChecker.h new file mode 100644 index 00000000000000..3710d72ad6b7e6 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/SingleInstanceChecker.h @@ -0,0 +1,70 @@ +#pragma once + +#ifdef DEBUG + +#include + +#include +#include + +#ifdef ANDROID +#include +#endif + +namespace reanimated { + +// This is a class that counts how many instances of a different class there +// are. It is meant only to be used with classes that should only have one +// instance. + +template +class SingleInstanceChecker { + public: + SingleInstanceChecker(); + ~SingleInstanceChecker(); + + private: + void assertWithMessage(bool condition, std::string message) { + if (!condition) { +#ifdef ANDROID + __android_log_print( + ANDROID_LOG_WARN, "Reanimated", "%s", message.c_str()); +#else + std::cerr << "[Reanimated] " << message << std::endl; +#endif + +#ifdef IS_REANIMATED_EXAMPLE_APP + assert(false); +#endif + } + } + + // A static field will exist separately for every class template. + // This has to be inline for automatic initialization. + inline static volatile int instanceCount_; +}; + +template +SingleInstanceChecker::SingleInstanceChecker() { + int status = 0; + std::string className = + __cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); + + // Only one instance should exist, but it is possible for two instances + // to co-exist during a reload. + assertWithMessage( + instanceCount_ <= 1, + "More than one instance of " + className + + " present. This may indicate a memory leak due to a retain cycle."); + + instanceCount_++; +} + +template +SingleInstanceChecker::~SingleInstanceChecker() { + instanceCount_--; +} + +} // namespace reanimated + +#endif // DEBUG diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/WorkletEventHandler.cpp b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/WorkletEventHandler.cpp new file mode 100644 index 00000000000000..3000342f3ac969 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/WorkletEventHandler.cpp @@ -0,0 +1,12 @@ +#include "WorkletEventHandler.h" + +namespace reanimated { + +void WorkletEventHandler::process( + double eventTimestamp, + const jsi::Value &eventValue) { + _runtimeHelper->runOnUIGuarded( + _handlerFunction, jsi::Value(eventTimestamp), eventValue); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/WorkletEventHandler.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/WorkletEventHandler.h new file mode 100644 index 00000000000000..63c2b1d92032c9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/Tools/WorkletEventHandler.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +#include "Shareables.h" + +using namespace facebook; + +namespace reanimated { + +class EventHandlerRegistry; + +class WorkletEventHandler { + friend EventHandlerRegistry; + + private: + std::shared_ptr _runtimeHelper; + uint64_t id; + std::string eventName; + jsi::Value _handlerFunction; + + public: + WorkletEventHandler( + const std::shared_ptr &runtimeHelper, + uint64_t id, + std::string eventName, + jsi::Value &&handlerFunction) + : _runtimeHelper(runtimeHelper), + id(id), + eventName(eventName), + _handlerFunction(std::move(handlerFunction)) {} + void process(double eventTimestamp, const jsi::Value &eventValue); +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/Logger.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/Logger.h new file mode 100644 index 00000000000000..9c4947e409371d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/Logger.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "./LoggerInterface.h" + +namespace reanimated { + +class Logger { + public: + template + static void log(T value) { + if (instance == nullptr) { + throw std::runtime_error("no logger specified"); + } + instance->log(value); + } + + private: + static std::unique_ptr instance; +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/LoggerInterface.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/LoggerInterface.h new file mode 100644 index 00000000000000..1f6004f0de6151 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/LoggerInterface.h @@ -0,0 +1,14 @@ +#pragma once + +namespace reanimated { + +class LoggerInterface { + public: + virtual void log(const char *str) = 0; + virtual void log(double d) = 0; + virtual void log(int i) = 0; + virtual void log(bool b) = 0; + virtual ~LoggerInterface() {} +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/SpeedChecker.h b/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/SpeedChecker.h new file mode 100644 index 00000000000000..9b0683080d0eaa --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/Common/cpp/hidden_headers/SpeedChecker.h @@ -0,0 +1,29 @@ +#pragma once + +#define CHECK_SPEED 1 + +#include +#include +#include +#include +#include "./Logger.h" + +namespace reanimated { + +class SpeedChecker { + public: + static void checkSpeed(std::string tag, std::function fun) { +#if CHECK_SPEED + auto start = std::chrono::system_clock::now(); +#endif + fun(); +#if CHECK_SPEED + auto end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + tag += " " + std::to_string(elapsed_seconds.count()) + "s"; + Logger::log(tag.c_str()); +#endif + } +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/CMakeLists.txt b/android/vendored/sdk49/react-native-reanimated/android/CMakeLists.txt new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/android/vendored/sdk49/react-native-reanimated/android/build.gradle b/android/vendored/sdk49/react-native-reanimated/android/build.gradle new file mode 100644 index 00000000000000..0140de11f25685 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/build.gradle @@ -0,0 +1,1160 @@ +import com.android.Version +import org.apache.tools.ant.filters.ReplaceTokens +import org.apache.tools.ant.taskdefs.condition.Os +import groovy.json.JsonSlurper + +import javax.inject.Inject +import java.nio.file.Files +import java.nio.file.Paths + +/** + * Finds the path of the installed npm package with the given name using Node's + * module resolution algorithm, which searches "node_modules" directories up to + * the file system root. This handles various cases, including: + * + * - Working in the open-source RN repo: + * Gradle: /path/to/versioned-react-native/packages/react-native/ReactAndroid + * Node module: /path/to/versioned-react-native/packages/react-native/node_modules/[package] + * + * - Installing RN as a dependency of an app and searching for hoisted + * dependencies: + * Gradle: /path/to/app/node_modules/versioned-react-native/packages/react-native/ReactAndroid + * Node module: /path/to/app/node_modules/[package] + * + * - Working in a larger repo (e.g., Facebook) that contains RN: + * Gradle: /path/to/repo/path/to/versioned-react-native/packages/react-native/ReactAndroid + * Node module: /path/to/repo/node_modules/[package] + * + * The search begins at the given base directory (a File object). The returned + * path is a string. + */ +static def findNodeModulePath(baseDir, packageName) { + def basePath = baseDir.toPath().normalize() + // Node's module resolution algorithm searches up to the root directory, + // after which the base path will be null + while (basePath) { + def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName) + if (candidatePath.toFile().exists()) { + return candidatePath.toString() + } + basePath = basePath.getParent() + } + return null +} + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +def safeAppExtGet(prop, fallback) { + def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } + appProject?.ext?.has(prop) ? appProject.ext.get(prop) : fallback +} + +def resolveBuildType() { + Gradle gradle = getGradle() + String tskReqStr = gradle.getStartParameter().getTaskRequests()['args'].toString() + + return tskReqStr.contains('Release') ? 'release' : 'debug' +} + +def resolveClientSideBuild() { + def clientSideBuild = System.getenv("CLIENT_SIDE_BUILD") + if (clientSideBuild != null) { + return clientSideBuild == "True" + } + + if (hasProperty("clientSideBuild")) { + return property("clientSideBuild") == "true" + } + + if (isDeveloperMode()) { + return false + } + + return true +} + +def isReanimatedExampleApp() { + return safeAppExtGet("isReanimatedExampleApp", false) +} + +def isDeveloperMode() { + return isReanimatedExampleApp() || System.getenv("REANIMATED_PACKAGE_BUILD") == "1" +} + +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + +def resolveReactNativeDirectory() { + def reactNativeLocation = safeAppExtGet("REACT_NATIVE_NODE_MODULES_DIR", null) + if (reactNativeLocation != null) { + return file(reactNativeLocation) + } + + if (isDeveloperMode()) { + return file("$projectDir/../${getPlaygroundAppName()}/node_modules/react-native") + } + + // monorepo workaround + // react-native can be hoisted or in project's own node_modules + def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native") + if (reactNativeFromProjectNodeModules.exists()) { + return reactNativeFromProjectNodeModules + } + + def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native") + if (reactNativeFromNodeModulesWithReanimated.exists()) { + return reactNativeFromNodeModulesWithReanimated + } + + throw new GradleException( + "[Reanimated] Unable to resolve react-native location in " + + "node_modules. You should project extension property (in app/build.gradle) " + + "`REACT_NATIVE_NODE_MODULES_DIR` with path to react-native." + ) +} + +def getPlaygroundAppName() { // only for the development + String playgroundAppName = "" + try { + rootProject.getSubprojects().forEach({project -> + if (project.plugins.hasPlugin("com.android.application")) { + var projectCatalogAbsolutePath = project.projectDir.toString().replace("/android/app", "") + var slashPosition = projectCatalogAbsolutePath.lastIndexOf("/") + playgroundAppName = projectCatalogAbsolutePath.substring(slashPosition + 1) + } + }) + } catch(_) { + return "NOT_FOUND" + } + return playgroundAppName +} + +def shouldAssertNoMultipleInstances() { + if (rootProject.hasProperty("disableMultipleInstancesCheck")) { + return rootProject.property("disableMultipleInstancesCheck") != "true" + } else { + return true + } +} + +def getReanimatedVersion() { + def inputFile = file(projectDir.path + '/../package.json') + def json = new JsonSlurper().parseText(inputFile.text) + return json.version +} + +def getReanimatedMajorVersion() { + def (major, minor, patch) = getReanimatedVersion().tokenize('.') + return major.toInteger() +} + +def toPlatformFileString(String path) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + path = path.replace(File.separatorChar, '/' as char) + } + return path +} + +boolean CLIENT_SIDE_BUILD = resolveClientSideBuild() +if (CLIENT_SIDE_BUILD) { + configurations.maybeCreate("default") +} + +def reactNativeRootDir = Paths.get(projectDir.getPath(), '../../../../versioned-react-native/packages/react-native').toFile() + +def reactProperties = new Properties() +file("$rootDir/../react-native-lab/react-native/packages/react-native/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) } + +def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME") +def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger() +def REANIMATED_PACKAGE_BUILD = System.getenv("REANIMATED_PACKAGE_BUILD") +def REANIMATED_VERSION = "3.3.0" +def REANIMATED_MAJOR_VERSION = 3 + +// for React Native <= 0.70 +def BOOST_VERSION = reactProperties.getProperty("BOOST_VERSION") +def DOUBLE_CONVERSION_VERSION = reactProperties.getProperty("DOUBLE_CONVERSION_VERSION") +def FOLLY_VERSION = reactProperties.getProperty("FOLLY_VERSION") +def GLOG_VERSION = reactProperties.getProperty("GLOG_VERSION") +def FBJNI_VERSION = "0.3.0" + +// We download various C++ open-source dependencies into downloads. +// We then copy both the downloaded code and our custom makefiles and headers into third-party-ndk. +// After that we build native code from src/main/jni with module path pointing at third-party-ndk. + +def customDownloadsDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR") +def downloadsDir = customDownloadsDir ? new File(customDownloadsDir) : new File("$buildDir/downloads") +def thirdPartyNdkDir = new File("$buildDir/third-party-ndk") + +def reactNativeThirdParty = new File("$reactNativeRootDir/ReactAndroid/src/main/jni/third-party") +def reactNativeAndroidDownloadDir = new File("$reactNativeRootDir/ReactAndroid/build/downloads") + +def JS_RUNTIME = { + return "hermes" // Expo Go always uses hermes + + // Override JS runtime with environment variable + if (System.getenv("JS_RUNTIME")) { + return System.getenv("JS_RUNTIME") + } + + // Enable V8 runtime if react-native-v8 is installed + def v8Project = rootProject.getSubprojects().find { project -> project.name == "react-native-v8" } + if (v8Project != null) { + return "v8" + } + + // Check if Hermes is enabled in app setup + def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } + if ((REACT_NATIVE_MINOR_VERSION >= 71 && appProject?.hermesEnabled?.toBoolean()) || appProject?.ext?.react?.enableHermes?.toBoolean()) { + return "hermes" + } + + // Use JavaScriptCore (JSC) by default + return "jsc" +}.call() + +def jsRuntimeDir = { + if (JS_RUNTIME == "hermes") { + if (REACT_NATIVE_MINOR_VERSION >= 69) { + return Paths.get(reactNativeRootDir.path, "sdks", "hermes") + } else { + return Paths.get(reactNativeRootDir.path, "..", "hermes-engine") + } + } else if (JS_RUNTIME == "v8") { + return findProject(":react-native-v8").getProjectDir().getParent() + } else { + return Paths.get(reactNativeRootDir.path, "ReactCommon", "jsi") + } +}.call() + +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +def detectAAR(Integer rnMinorVersion, String engine) { // Reanimated2 only + def rnMinorVersionCopy = rnMinorVersion + def aar = file("react-native-reanimated-${rnMinorVersionCopy}-${engine}.aar") + + if (aar.exists()) { + println "AAR for react-native-reanimated has been found\n$aar" + return aar + } else { + while (!aar.exists() && rnMinorVersionCopy >= 63) { + rnMinorVersionCopy -= 1 + aar = file("react-native-reanimated-${rnMinorVersionCopy}-${engine}.aar") + } + + if (rnMinorVersionCopy < 63) { + println "No AAR for react-native-reanimated found. Attempting to build from source." + } else { // aar exists, but was build for lower react-native version + println "\n\n\n" + println "****************************************************************************************" + println "\n\n\n" + println "WARNING reanimated - no version-specific reanimated AAR for react-native version $rnMinorVersion found." + println "Falling back to AAR for react-native version $rnMinorVersionCopy." + println "The react-native JSI interface is not ABI-safe yet, this may result in crashes." + println "Please post a pull request to implement support for react-native version $rnMinorVersion to the reanimated repo." + println "Thanks!" + println "\n\n\n" + println "****************************************************************************************" + + return aar + } + } + return null +} + +def isUserDemandToBuildFromSource() { // Reanimated2 only + def buildFromSourceConf = false + rootProject.getSubprojects().forEach({project -> + if (project.plugins.hasPlugin("com.android.application")) { + if ( + project.ext.has("reanimated") + && project.ext.reanimated.buildFromSource + ) { + buildFromSourceConf = true + } + } + }) + return buildFromSourceConf +} + +def shouldBuildFromSource(aar, jsRuntimeName) { // Reanimated2 only + if (jsRuntimeName == "v8") { + return true + } + else if (isDeveloperMode()) { + // Example app + return true + } + else if (isUserDemandToBuildFromSource()) { + // on user demand + return true + } + else if (aar != null) { + // when binary exist + return false + } + // when binary is not found + return true +} + +def getTaskByPath( + project, + String appName, + String secondPart, + String flavorString, + String lastPart +) { // Reanimated2 only + String pathName = "${appName}:${secondPart}${flavorString}${lastPart}" + Task task = project.getTasks().findByPath(pathName) + if (task != null) { + return task + } + pathName = "${appName}:${secondPart}${flavorString.capitalize()}${lastPart}" + return project.getTasks().findByPath(pathName) +} + +def aar = detectAAR(REACT_NATIVE_MINOR_VERSION, JS_RUNTIME) +boolean BUILD_FROM_SOURCE = shouldBuildFromSource(aar, JS_RUNTIME) + +if (!BUILD_FROM_SOURCE && !isNewArchitectureEnabled()) { // Reanimated2 only + if (REACT_NATIVE_MINOR_VERSION < 65) { + tasks.register("replaceSoTaskDebug", replaceSoTask) + tasks.register("replaceSoTaskRelease", replaceSoTask) + Task replaceSoTaskDebug = project.getTasks().findByPath(":react-native-reanimated:replaceSoTaskDebug") + Task replaceSoTaskRelease = project.getTasks().findByPath(":react-native-reanimated:replaceSoTaskRelease") + + if (replaceSoTaskDebug != null && replaceSoTaskRelease != null) { + rootProject.getSubprojects().forEach({project -> + if (project.plugins.hasPlugin("com.android.application") && project.getProperties().get("android")) { + def projectProperties = project.getProperties() + def flavorString = getCurrentFlavor() + def reanimatedConf = projectProperties.get("reanimated") + + if ( + flavorString != "NOT-FOUND" + && (!reanimatedConf || (reanimatedConf && !reanimatedConf.get("enablePackagingOptions"))) + ) { + replaceSoTask.appName = projectProperties.path + replaceSoTask.buildDir = projectProperties.buildDir + def appName = projectProperties.path + + Task debugNativeLibsTask = getTaskByPath(project, appName, "merge", flavorString, "DebugNativeLibs") + Task debugDebugSymbolsTask = getTaskByPath(project, appName, "strip", flavorString, "DebugDebugSymbols") + Task releaseNativeLibsTask = getTaskByPath(project, appName, "merge", flavorString, "ReleaseNativeLibs") + Task releaseDebugSymbolsTask = getTaskByPath(project, appName, "strip", flavorString, "ReleaseDebugSymbols") + Task debugTask = getTaskByPath(project, appName, "package", flavorString, "Debug") + Task releaseTask = getTaskByPath(project, appName, "package", flavorString, "Release") + + if ( + debugNativeLibsTask != null && debugDebugSymbolsTask != null + && releaseNativeLibsTask != null && releaseDebugSymbolsTask != null + && debugTask != null && releaseTask != null + ) { + replaceSoTaskDebug.dependsOn(debugNativeLibsTask, debugDebugSymbolsTask) + debugTask.dependsOn(replaceSoTaskDebug) + replaceSoTaskRelease.dependsOn(releaseNativeLibsTask, releaseDebugSymbolsTask) + releaseTask.dependsOn(replaceSoTaskRelease) + } + } + } + }) + } + } + + artifacts.add("default", aar) +} + +// end if already loaded aar +if (!BUILD_FROM_SOURCE) { + return +} + +buildscript { + repositories { + google() + mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "com.android.tools.build:gradle:7.3.1" + classpath "de.undercouch:gradle-download-task:5.0.1" + classpath "com.diffplug.spotless:spotless-plugin-gradle:6.11.0" + } +} + +if (project == rootProject) { + apply from: "spotless.gradle" +} + +apply plugin: "com.android.library" +apply plugin: "maven-publish" +apply plugin: "de.undercouch.download" + +android { + compileSdkVersion safeExtGet("compileSdkVersion", 30) + def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION + if (agpVersion.tokenize('.')[0].toInteger() >= 7) { + namespace "abi49_0_0.com.swmansion.reanimated" + } + if (REACT_NATIVE_MINOR_VERSION >= 71) { + buildFeatures { + prefab true + } + } + defaultConfig { + minSdkVersion safeExtGet("minSdkVersion", 16) + targetSdkVersion safeExtGet("targetSdkVersion", 30) + versionCode 1 + versionName "1.0" + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + externalNativeBuild { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}", + "-DANDROID_TOOLCHAIN=clang", + REACT_NATIVE_MINOR_VERSION < 71 ? "-DBOOST_VERSION=${BOOST_VERSION}" : "-DBOOST_VERSION=", + "-DREACT_NATIVE_DIR=${toPlatformFileString(reactNativeRootDir.path)}", + "-DJS_RUNTIME=${JS_RUNTIME}", + "-DJS_RUNTIME_DIR=${jsRuntimeDir}", + "-DCLIENT_SIDE_BUILD=${CLIENT_SIDE_BUILD}", + "-DIS_NEW_ARCHITECTURE_ENABLED=${isNewArchitectureEnabled()}", + "-DIS_REANIMATED_EXAMPLE_APP=${isReanimatedExampleApp()}", + "-DPLAYGROUND_APP_NAME=${getPlaygroundAppName()}", + "-DREANIMATED_PACKAGE_BUILD=${REANIMATED_PACKAGE_BUILD}", + "-DREANIMATED_VERSION=${REANIMATED_VERSION}" + abiFilters (*reactNativeArchitectures()) + } + } + + buildConfigField("boolean", "IS_INTERNAL_BUILD", "false") + buildConfigField("int", "EXOPACKAGE_FLAGS", "0") + buildConfigField("int", "REACT_NATIVE_MINOR_VERSION", REACT_NATIVE_MINOR_VERSION.toString()) + + consumerProguardFiles 'proguard-rules.pro' + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } + buildTypes { + debug { + externalNativeBuild { + cmake { + if (JS_RUNTIME == "hermes" && !REANIMATED_PACKAGE_BUILD) { + arguments "-DHERMES_ENABLE_DEBUGGER=1" + } else { + arguments "-DHERMES_ENABLE_DEBUGGER=0" + } + } + } + } + release { + externalNativeBuild { + cmake { + arguments "-DHERMES_ENABLE_DEBUGGER=0" + } + } + } + } + lintOptions { + abortOnError false + } + packagingOptions { + doNotStrip resolveBuildType() == 'debug' ? "**/**/*.so" : '' + excludes = [ + "META-INF", + "META-INF/**", + "**/libc++_shared.so", + "**/libfbjni.so", + "**/libjsi.so", + "**/libfolly_json.so", + "**/libfolly_runtime.so", + "**/libglog.so", + "**/libhermes.so", + "**/libhermes-executor-debug.so", + "**/libhermes_executor.so", + "**/libreactnativejni.so", + "**/libturbomodulejsijni.so", + "**/libreact_nativemodule_core.so", + "**/libjscexecutor.so", + "**/libv8executor.so", + ] + } + tasks.withType(JavaCompile) { + compileTask -> + compileTask.dependsOn(packageNdkLibs) + } + configurations { + extractHeaders + extractSO + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + packagingOptions { + // For some reason gradle only complains about the duplicated version of librrc_root and libreact_render libraries + // while there are more libraries copied in intermediates folder of the lib build directory, we exclude + // only the ones that make the build fail (ideally we should only include libreanimated but we + // are only allowed to specify exlude patterns) + exclude "**/libreact_render*.so" + exclude "**/librrc_root.so" + } + sourceSets.main { + java { + if (isNewArchitectureEnabled()) { + srcDirs += "src/fabric/java" + } else { + srcDirs += "src/paper/java" + } + + // messageQueueThread + if (REANIMATED_MAJOR_VERSION > 2) { + if (REACT_NATIVE_MINOR_VERSION <= 67) { + srcDirs += "src/reactNativeVersionPatch/messageQueueThread/67" + } else { + srcDirs += "src/reactNativeVersionPatch/messageQueueThread/latest" + } + } + + // UIImplementation + if (REACT_NATIVE_MINOR_VERSION <= 64) { + srcDirs += "src/reactNativeVersionPatch/UIImplementation/64" + } else { + srcDirs += "src/reactNativeVersionPatch/UIImplementation/latest" + } + + // ReanimatedUIManager & ReanimatedUIImplementation + if (REACT_NATIVE_MINOR_VERSION <= 70) { + srcDirs += "src/reactNativeVersionPatch/ReanimatedUIManager/70" + } else { + srcDirs += "src/reactNativeVersionPatch/ReanimatedUIManager/latest" + } + + // nativeHierarchyManager + if (REACT_NATIVE_MINOR_VERSION <= 62) { + srcDirs += "src/reactNativeVersionPatch/nativeHierarchyManager/62" + } else { + srcDirs += "src/reactNativeVersionPatch/nativeHierarchyManager/latest" + } + } + } +} + +abstract class NoMultipleInstancesAssertionTask extends DefaultTask { + @Inject abstract ObjectFactory getObjectFactory() + + @Input abstract Property getProjectDirFile() + @Input abstract Property getRootDirFile() + @Input abstract Property getShouldCheck() + + def findReanimatedInstancesForPath(String path) { + return objectFactory.fileTree().from(path) + .include("**/react-native-reanimated/package.json") + .exclude("**/.yarn/**") + .exclude({ Files.isSymbolicLink(it.getFile().toPath()) }) + .findAll() + } + + @TaskAction + def check() { + if (shouldCheck.get()) { + // Assert there are no multiple installations of Reanimated + Set files + + if (projectDirFile.get().parent.contains(rootDirFile.get().parent)) { + // standard app + files = findReanimatedInstancesForPath(rootDirFile.get().parent + "/node_modules") + } else { + // monorepo + files = findReanimatedInstancesForPath(rootDirFile.get().parent + "/node_modules") + files.addAll( + findReanimatedInstancesForPath(projectDirFile.get().parentFile.parent) + ) + } + + if (files.size() > 1) { + String parsedLocation = files.stream().map({ + File file -> "- " + file.toString().replace("/package.json", "") + }).collect().join("\n") + String exceptionMessage = "\n[react-native-reanimated] Multiple versions of Reanimated " + + "were detected. Only one instance of react-native-reanimated can be installed in a " + + "project. You need to resolve the conflict manually. Check out the documentation: " + + "https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/" + + "troubleshooting#multiple-versions-of-reanimated-were-detected \n\nConflict " + + "between: \n" + parsedLocation + "\n" + throw new GradleException(exceptionMessage) + } + } + } +} + +tasks.register('assertNoMultipleInstances', NoMultipleInstancesAssertionTask) { + shouldCheck = shouldAssertNoMultipleInstances() + rootDirFile = rootDir + projectDirFile = projectDir +} + +def NEW_ARCH_ENABLED = isNewArchitectureEnabled() + +def assertNoReanimated2WithNewArchitecture = task assertNoReanimated2WithNewArchitectureTask { + onlyIf { NEW_ARCH_ENABLED && REANIMATED_MAJOR_VERSION == 2 } + doFirst { + throw new GradleException( + "\n[react-native-reanimated] Reanimated 2.x does not support Fabric. " + + "Please upgrade to 3.x to use Reanimated with the New Architecture. " + + "For details, see https://blog.swmansion.com/announcing-reanimated-3-16167428c5f7" + ) + } +} + +def assertLatestReactNativeWithNewArchitecture = task assertLatestReactNativeWithNewArchitectureTask { + onlyIf { NEW_ARCH_ENABLED && REANIMATED_MAJOR_VERSION == 3 && REACT_NATIVE_MINOR_VERSION < 72 } + doFirst { + throw new GradleException( + "\n[react-native-reanimated] Reanimated " + REANIMATED_VERSION + " supports the New Architecture " + + "only on the latest minor release of React Native. Please upgrade to React Native 0.72.0+ " + + "or downgrade to an older version of Reanimated v3." + ) + } +} + +tasks.preBuild { + dependsOn assertNoMultipleInstances, assertNoReanimated2WithNewArchitecture, assertLatestReactNativeWithNewArchitecture +} + +task cleanCmakeCache() { + tasks.getByName("clean").dependsOn(cleanCmakeCache) + doFirst { + delete "${projectDir}/.cxx" + } +} + +task printVersions { + println "Android gradle plugin: ${Version.ANDROID_GRADLE_PLUGIN_VERSION}" + println "Gradle: ${project.gradle.gradleVersion}" +} + +task createNativeDepsDirectories() { + downloadsDir.mkdirs() + thirdPartyNdkDir.mkdirs() +} + +def resolveTaskFactory(String taskName, String artifactLocalName, File reactNativeAndroidDownloadDir, File reanimatedDownloadDir) { + return tasks.create(name: taskName, dependsOn: createNativeDepsDirectories, type: Copy) { + from reactNativeAndroidDownloadDir + include artifactLocalName + into reanimatedDownloadDir + + onlyIf { + // First we check whether the file is already in our download directory + if (file("$reanimatedDownloadDir/$artifactLocalName").isFile()) { + return false + } + + // If it is not the case we check whether it was downloaded by ReactAndroid project + if (file("$reactNativeAndroidDownloadDir/$artifactLocalName").isFile()) { + return true + } + + return false + } + } +} + +/* +Reanimated includes "hermes/hermes.h" header file in `NativeProxy.cpp`. +Previously, we used header files from `hermes-engine` package in `node_modules`. +In React Native 0.69 and 0.70, Hermes is no longer distributed as package on NPM. +On the new architecture, Hermes is downloaded from GitHub and then compiled from sources. +However, on the old architecture, we need to download Hermes header files on our own +as well as unzip Hermes AAR in order to obtain `libhermes.so` shared library. +For more details, see https://reactnative.dev/architecture/bundled-hermes +or https://github.com/reactwg/react-native-new-architecture/discussions/4 +*/ +if (REACT_NATIVE_MINOR_VERSION in [69, 70] && !isNewArchitectureEnabled()) { + // copied from `react-native/ReactAndroid/hermes-engine/build.gradle` + + def downloadDir = customDownloadsDir ? new File(customDownloadsDir) : new File(reactNativeRootDir, "sdks/download") + + // By default we are going to download and unzip hermes inside the /sdks/hermes folder + // but you can provide an override for where the hermes source code is located. + def hermesDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR") ?: new File(reactNativeRootDir, "sdks/hermes") + + def hermesVersion = "main" + def hermesVersionFile = new File(reactNativeRootDir, "sdks/.hermesversion") + if (hermesVersionFile.exists()) { + hermesVersion = hermesVersionFile.text + } + + task downloadHermes(type: Download) { + src("https://github.com/facebook/hermes/tarball/${hermesVersion}") + onlyIfNewer(true) + overwrite(false) + dest(new File(downloadDir, "hermes.tar.gz")) + } + + task unzipHermes(dependsOn: downloadHermes, type: Copy) { + from(tarTree(downloadHermes.dest)) { + eachFile { file -> + // We flatten the unzip as the tarball contains a `facebook-hermes-` + // folder at the top level. + if (file.relativePath.segments.size() > 1) { + file.relativePath = new RelativePath(!file.isDirectory(), file.relativePath.segments.drop(1)) + } + } + } + into(hermesDir) + } +} + +if (REACT_NATIVE_MINOR_VERSION < 71) { + // You need to have following folders in this directory: + // - boost_1_63_0 + // - double-conversion-1.1.6 + // - folly-deprecate-dynamic-initializer + // - glog-0.3.5 + def dependenciesPath = System.getenv("REACT_NATIVE_DEPENDENCIES") + + // The Boost library is a very large download (>100MB). + // If Boost is already present on your system, define the REACT_NATIVE_BOOST_PATH env variable + // and the build will use that. + def boostPath = dependenciesPath ?: System.getenv("REACT_NATIVE_BOOST_PATH") + + def follyReplaceContent = ''' + ssize_t r; + do { + r = open(name, flags, mode); + } while (r == -1 && errno == EINTR); + return r; + ''' + + Task resolveBoost = resolveTaskFactory("resolveBoost", "boost_${BOOST_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir) + Task resolveDoubleConversion = resolveTaskFactory( + "resolveDoubleConversion", + "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz", + reactNativeAndroidDownloadDir, + downloadsDir + ) + Task resolveFolly = resolveTaskFactory("resolveFolly", "folly-${FOLLY_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir) + Task resolveGlog = resolveTaskFactory("resolveGlog", "glog-${GLOG_VERSION}.tar.gz", reactNativeAndroidDownloadDir, downloadsDir) + + if (isNewArchitectureEnabled()) { + def reactNativeAndroidProject = findProject(":packages:react-native::ReactAndroid") + if (reactNativeAndroidProject != null) { + reactNativeAndroidProject.afterEvaluate { + def resolveTasks = [resolveBoost, resolveGlog, resolveDoubleConversion, resolveFolly] + resolveTasks.forEach({ task -> + String reactAndroidDownloadTaskName = "download" + task.name.replace("resolve", "") + def reactAndroidDownloadTask = reactNativeAndroidProject.getTasks().findByName(reactAndroidDownloadTaskName) + if (reactAndroidDownloadTask != null) { + task.dependsOn(reactAndroidDownloadTask) + } else { + logger.warn("[Reanimated] Failed to find task named `$reactAndroidDownloadTaskName` in `:packages:react-native::ReactAndroid` project." + + " Explicit dependency between it and $task.name task can not be set.") + } + }) + } + } else { + throw new GradleException("[Reanimated] Failed to find `:packages:react-native::ReactAndroid` project. Explicit dependency between download tasks can not be set.") + } + } + + task downloadBoost(dependsOn: resolveBoost, type: Download) { + def transformedVersion = BOOST_VERSION.replace("_", ".") + def artifactLocalName = "boost_${BOOST_VERSION}.tar.gz" + def srcUrl = "https://boostorg.jfrog.io/artifactory/main/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz" + if (REACT_NATIVE_MINOR_VERSION < 69) { + srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/boost_${BOOST_VERSION}.tar.gz" + } + src(srcUrl) + onlyIfNewer(true) + overwrite(false) + dest(new File(downloadsDir, artifactLocalName)) + } + + task prepareBoost(dependsOn: boostPath ? [] : [downloadBoost], type: Copy) { + from(boostPath ?: tarTree(resources.gzip(downloadBoost.dest))) + from("$reactNativeThirdParty/boost/Android.mk") + include("Android.mk", "boost_${BOOST_VERSION}/boost/**/*.hpp", "boost/boost/**/*.hpp") + includeEmptyDirs = false + into("$thirdPartyNdkDir/boost") + doLast { + file("$thirdPartyNdkDir/boost/boost").renameTo("$thirdPartyNdkDir/boost/boost_${BOOST_VERSION}") + } + } + + task downloadDoubleConversion(dependsOn: resolveDoubleConversion, type: Download) { + src("https://github.com/google/double-conversion/archive/v${DOUBLE_CONVERSION_VERSION}.tar.gz") + onlyIfNewer(true) + overwrite(false) + dest(new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz")) + } + + task prepareDoubleConversion(dependsOn: dependenciesPath ? [] : [downloadDoubleConversion], type: Copy) { + from(dependenciesPath ?: tarTree(downloadDoubleConversion.dest)) + from("$reactNativeThirdParty/double-conversion/Android.mk") + include("double-conversion-${DOUBLE_CONVERSION_VERSION}/src/**/*", "Android.mk") + filesMatching("*/src/**/*", { fname -> fname.path = "double-conversion/${fname.name}" }) + includeEmptyDirs = false + into("$thirdPartyNdkDir/double-conversion") + } + + task downloadFolly(dependsOn: resolveFolly, type: Download) { + src("https://github.com/facebook/folly/archive/v${FOLLY_VERSION}.tar.gz") + onlyIfNewer(true) + overwrite(false) + dest(new File(downloadsDir, "folly-${FOLLY_VERSION}.tar.gz")) + } + + task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy) { + from(dependenciesPath ?: tarTree(downloadFolly.dest)) + from("$reactNativeThirdParty/folly/Android.mk") + include("folly-${FOLLY_VERSION}/folly/**/*", "Android.mk") + eachFile { fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/") } + // Fixes problem with Folly failing to build on certain systems. See + // https://github.com/software-mansion/react-native-reanimated/issues/1024 + filter { line -> line.replaceAll("return int\\(wrapNoInt\\(open, name, flags, mode\\)\\);", follyReplaceContent) } + includeEmptyDirs = false + into("$thirdPartyNdkDir/folly") + } + + task downloadGlog(dependsOn: resolveGlog, type: Download) { + src("https://github.com/google/glog/archive/v${GLOG_VERSION}.tar.gz") + onlyIfNewer(true) + overwrite(false) + dest(new File(downloadsDir, "glog-${GLOG_VERSION}.tar.gz")) + } + + // Prepare glog sources to be compiled, this task will perform steps that normally should've been + // executed by automake. This way we can avoid dependencies on make/automake + task prepareGlog(dependsOn: dependenciesPath ? [] : [downloadGlog], type: Copy) { + duplicatesStrategy = "include" + from(dependenciesPath ?: tarTree(downloadGlog.dest)) + from("$reactNativeThirdParty/glog/") + include("glog-${GLOG_VERSION}/src/**/*", "Android.mk", "config.h") + includeEmptyDirs = false + filesMatching("**/*.h.in") { + filter(ReplaceTokens, tokens: [ + ac_cv_have_unistd_h : "1", + ac_cv_have_stdint_h : "1", + ac_cv_have_systypes_h : "1", + ac_cv_have_inttypes_h : "1", + ac_cv_have_libgflags : "0", + ac_google_start_namespace : "namespace google {", + ac_cv_have_uint16_t : "1", + ac_cv_have_u_int16_t : "1", + ac_cv_have___uint16 : "0", + ac_google_end_namespace : "}", + ac_cv_have___builtin_expect : "1", + ac_google_namespace : "google", + ac_cv___attribute___noinline : "__attribute__ ((noinline))", + ac_cv___attribute___noreturn : "__attribute__ ((noreturn))", + ac_cv___attribute___printf_4_5: "__attribute__((__format__ (__printf__, 4, 5)))" + ]) + it.path = (it.name - ".in") + } + into("$thirdPartyNdkDir/glog") + + doLast { + copy { + from(fileTree(dir: "$thirdPartyNdkDir/glog", includes: ["stl_logging.h", "logging.h", "raw_logging.h", "vlog_is_on.h", "**/src/glog/log_severity.h"]).files) + includeEmptyDirs = false + into("$thirdPartyNdkDir/glog/exported/glog") + } + } + } + + task prepareHermes { + return + if (REACT_NATIVE_MINOR_VERSION >= 69) { + if (!isNewArchitectureEnabled()) { + dependsOn(unzipHermes) + } + + doLast { + // e.g. hermes-engine-0.70.0-rc.1-debug.aar + def hermesAAR = file( + "$reactNativeRootDir/android/com/facebook/react/hermes-engine/" + + "${REACT_NATIVE_VERSION}/hermes-engine-${REACT_NATIVE_VERSION}-" + + "${resolveBuildType()}.aar" + ) + if (!hermesAAR.exists()) { + throw new GradleException("Could not find hermes-engine AAR", null) + } + + def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" }) + + copy { + from soFiles + from "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/hermes/Android.mk" + into "$thirdPartyNdkDir/hermes" + } + } + } else { + doLast { + def hermesPackagePath = findNodeModulePath(projectDir, "hermes-engine") + if (!hermesPackagePath) { + throw new GradleException("Could not find the hermes-engine npm package", null) + } + + def hermesAAR = file("$hermesPackagePath/android/hermes-${resolveBuildType()}.aar") // e.g. hermes-debug.aar + if (!hermesAAR.exists()) { + throw new GradleException("The hermes-engine npm package is missing \"android/hermes-${resolveBuildType()}.aar\"", null) + } + + def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" }) + + copy { + from soFiles + from "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/hermes/Android.mk" + into "$thirdPartyNdkDir/hermes" + } + } + } + } + + task prepareJSC { + if (REACT_NATIVE_MINOR_VERSION >= 71) { + // do nothing + } else { + doLast { + def jscPackagePath = findNodeModulePath(projectDir, "jsc-android") + if (!jscPackagePath) { + throw new GradleException("Could not find the jsc-android npm package", null) + } + + def jscDist = file("$jscPackagePath/dist") + if (!jscDist.exists()) { + throw new GradleException("The jsc-android npm package is missing its \"dist\" directory", null) + } + + def jscAAR = fileTree(jscDist).matching({ it.include "**/android-jsc/**/*.aar" }).singleFile + def soFiles = zipTree(jscAAR).matching({ it.include "**/*.so" }) + + def headerFiles = fileTree(jscDist).matching({ it.include "**/include/*.h" }) + + copy { + from(soFiles) + from(headerFiles) + from("$reactNativeRootDir/ReactAndroid/src/main/jni/third-party/jsc/Android.mk") + + filesMatching("**/*.h", { it.path = "JavaScriptCore/${it.name}" }) + + includeEmptyDirs(false) + into("$thirdPartyNdkDir/jsc") + } + } + } + } + + task extractAARHeaders { + doLast { + configurations.extractHeaders.files.each { + def file = it.absoluteFile + def packageName = file.name.tokenize('-')[0] + copy { + from zipTree(file) + into "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/$packageName/headers" + include "**/*.h" + } + } + } + } + + task extractSOFiles { + doLast { + configurations.extractSO.files.each { + def file = it.absoluteFile + def packageName = file.name.tokenize('-')[0] + copy { + from zipTree(file) + into "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/$packageName/" + include "jni/**/*.so" + } + } + } + } + + task unpackReactNativeAAR { + return + def buildType = resolveBuildType() + def rnAarMatcher = "**/versioned-react-native/packages/react-native/**/*${buildType}.aar" + if (REACT_NATIVE_MINOR_VERSION < 69) { + rnAarMatcher = "**/**/*.aar" + } + def rnAAR = fileTree("$reactNativeRootDir/android").matching({ it.include rnAarMatcher }).singleFile + def file = rnAAR.absoluteFile + def packageName = file.name.tokenize('-')[0] + copy { + from zipTree(file) + into "$reactNativeRootDir/ReactAndroid/src/main/jni/first-party/$packageName/" + include "jni/**/*.so" + } + } + + task downloadNdkBuildDependencies { + if (!boostPath) { + dependsOn(downloadBoost) + } + dependsOn(downloadDoubleConversion) + dependsOn(downloadFolly) + dependsOn(downloadGlog) + } + + task prepareThirdPartyNdkHeaders(dependsOn:[ + downloadNdkBuildDependencies, + prepareBoost, + prepareDoubleConversion, + prepareFolly, + prepareGlog, + unpackReactNativeAAR] + ) {} +} + +task packageNdkLibs(type: Copy) { + from("$buildDir/reanimated-ndk/all") + include("**/libreanimated.so") + if(REACT_NATIVE_MINOR_VERSION < 64) { + include("**/libturbomodulejsijni.so") + } + into("$projectDir/src/main/jniLibs") +} + +repositories { + mavenCentral() + mavenLocal() + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "$reactNativeRootDir/android" + } + maven { + // Android JSC is installed from npm + url "$reactNativeRootDir/../jsc-android/dist" + } + google() +} + +dependencies { + // noinspection GradleDynamicVersion + implementation "com.facebook.yoga:proguard-annotations:1.19.0" + implementation "androidx.transition:transition:1.1.0" + implementation "androidx.core:core:1.6.0" + + if (REACT_NATIVE_MINOR_VERSION >= 71) { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + // version substituted by RNGP + if (JS_RUNTIME == "hermes") { + if (file("${reactNativeRootDir}/ReactAndroid/hermes-engine/build/outputs/aar/hermes-engine-release.aar").exists()) { + compileOnly(files("${reactNativeRootDir}/ReactAndroid/hermes-engine/build/outputs/aar/hermes-engine-release.aar")) + } + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + } + } else { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + // From node_modules + if (isDeveloperMode() && !isNewArchitectureEnabled()) { + implementation "com.facebook.fbjni:fbjni:" + FBJNI_VERSION + } + else { + implementation "com.facebook.fbjni:fbjni-java-only:" + FBJNI_VERSION + } + + extractHeaders("com.facebook.fbjni:fbjni:" + FBJNI_VERSION + ":headers") + extractSO("com.facebook.fbjni:fbjni:" + FBJNI_VERSION) + + def jscAAR = fileTree("$reactNativeRootDir/../jsc-android/dist/org/webkit/android-jsc").matching({ it.include "**/**/*.aar" }).singleFile + extractSO(files(jscAAR)) + } +} + +def nativeBuildDependsOn(dependsOnTask) { + def buildTasks = tasks.findAll({ task -> ( + !task.name.contains("Clean") + && (task.name.contains("externalNative") + || task.name.contains("CMake") + || task.name.contains("generateJsonModel") + ) + ) }) + buildTasks.forEach { task -> task.dependsOn(dependsOnTask) } +} + +afterEvaluate { + if (REACT_NATIVE_MINOR_VERSION < 71) { + extractAARHeaders.dependsOn(prepareThirdPartyNdkHeaders) + extractSOFiles.dependsOn(prepareThirdPartyNdkHeaders) + + nativeBuildDependsOn(prepareThirdPartyNdkHeaders) + nativeBuildDependsOn(extractAARHeaders) + nativeBuildDependsOn(extractSOFiles) + } + + tasks.forEach({ task -> + if (task.name.contains("JniLibFolders")) { + task.dependsOn(packageNdkLibs) + } + }) + + if (JS_RUNTIME == "hermes") { + if (REACT_NATIVE_MINOR_VERSION < 71) { + extractAARHeaders.dependsOn(prepareHermes) + extractSOFiles.dependsOn(prepareHermes) + } + } else if (JS_RUNTIME == "v8") { + def buildTasks = tasks.findAll({ task -> + !task.name.contains("Clean") && (task.name.contains("externalNative") || task.name.contains("CMake") || task.name.startsWith("generateJsonModel")) }) + buildTasks.forEach { task -> + def buildType = task.name.endsWith('Debug') ? 'Debug' : 'Release' + task.dependsOn(":react-native-v8:copy${buildType}JniLibsProjectOnly") + } + } else if (JS_RUNTIME == "jsc") { + if (REACT_NATIVE_MINOR_VERSION < 71) { + extractAARHeaders.dependsOn(prepareJSC) + extractSOFiles.dependsOn(prepareJSC) + } + } else { + throw GradleScriptException("Unknown JS runtime ${JS_RUNTIME}.") + } +} + +if (CLIENT_SIDE_BUILD) { + def aarDir = "${buildDir}/outputs" + aar = file("${aarDir}/android-${resolveBuildType()}.aar") // e.g. android-debug.aar + if (aar == null) { + throw GradleScriptException("AAR build failed. No AAR found in ${aarDir}.") + } + artifacts.add("default", aar) +} + +android.packagingOptions.excludes.add("**/libhermes*.so") \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-reanimated/android/empty.cpp b/android/vendored/sdk49/react-native-reanimated/android/empty.cpp new file mode 100644 index 00000000000000..8d50bb2809009d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/empty.cpp @@ -0,0 +1 @@ +// required for compilation purpose diff --git a/android/vendored/sdk49/react-native-reanimated/android/proguard-rules.pro b/android/vendored/sdk49/react-native-reanimated/android/proguard-rules.pro new file mode 100644 index 00000000000000..118a2c3f822142 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/proguard-rules.pro @@ -0,0 +1,2 @@ +-keep class com.swmansion.reanimated.** { *; } +-keep class com.facebook.react.turbomodule.** { *; } diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/fabric/java/abi49_0_0/com/swmansion/reanimated/NativeProxy.java b/android/vendored/sdk49/react-native-reanimated/android/src/fabric/java/abi49_0_0/com/swmansion/reanimated/NativeProxy.java new file mode 100644 index 00000000000000..b416ae88822a23 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/fabric/java/abi49_0_0/com/swmansion/reanimated/NativeProxy.java @@ -0,0 +1,96 @@ +package abi49_0_0.com.swmansion.reanimated; + +import android.util.Log; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.queue.MessageQueueThread; +import abi49_0_0.com.facebook.react.fabric.FabricUIManager; +import abi49_0_0.com.facebook.react.turbomodule.core.CallInvokerHolderImpl; +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper; +import abi49_0_0.com.facebook.react.uimanager.common.UIManagerType; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.AnimationsManager; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.LayoutAnimations; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.NativeMethodsHolder; +import abi49_0_0.com.swmansion.reanimated.nativeProxy.NativeProxyCommon; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +public class NativeProxy extends NativeProxyCommon { + @DoNotStrip + @SuppressWarnings("unused") + private final HybridData mHybridData; + + public NativeProxy(ReactApplicationContext context) { + super(context); + + CallInvokerHolderImpl holder = + (CallInvokerHolderImpl) context.getCatalystInstance().getJSCallInvokerHolder(); + + FabricUIManager fabricUIManager = + (FabricUIManager) UIManagerHelper.getUIManager(context, UIManagerType.FABRIC); + + LayoutAnimations LayoutAnimations = new LayoutAnimations(context); + + mHybridData = + initHybrid( + context.getJavaScriptContextHolder().get(), + holder, + mScheduler, + LayoutAnimations, + fabricUIManager); + prepareLayoutAnimations(LayoutAnimations); + ReanimatedMessageQueueThread messageQueueThread = new ReanimatedMessageQueueThread(); + installJSIBindings(messageQueueThread, fabricUIManager); + } + + private native HybridData initHybrid( + long jsContext, + CallInvokerHolderImpl jsCallInvokerHolder, + Scheduler scheduler, + LayoutAnimations LayoutAnimations, + FabricUIManager fabricUIManager); + + private native void installJSIBindings( + MessageQueueThread messageQueueThread, + FabricUIManager fabricUIManager); + + public native boolean isAnyHandlerWaitingForEvent(String eventName); + + public native void performOperations(); + + @Override + protected HybridData getHybridData() { + return mHybridData; + } + + public static NativeMethodsHolder createNativeMethodsHolder(LayoutAnimations layoutAnimations) { + return new NativeMethodsHolder() { + @Override + public void startAnimation(int tag, int type, HashMap values) {} + + @Override + public boolean isLayoutAnimationEnabled() { + return false; + } + + @Override + public int findPrecedingViewTagForTransition(int tag) { + return -1; + } + + @Override + public boolean hasAnimation(int tag, int type) { + return false; + } + + @Override + public void clearAnimationConfig(int tag) {} + + @Override + public void cancelAnimation(int tag, int type, boolean cancelled, boolean removeView) {} + }; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/fabric/java/abi49_0_0/com/swmansion/reanimated/ReaCompatibility.java b/android/vendored/sdk49/react-native-reanimated/android/src/fabric/java/abi49_0_0/com/swmansion/reanimated/ReaCompatibility.java new file mode 100644 index 00000000000000..e55ca4aaa9de78 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/fabric/java/abi49_0_0/com/swmansion/reanimated/ReaCompatibility.java @@ -0,0 +1,25 @@ +package abi49_0_0.com.swmansion.reanimated; + +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper; +import abi49_0_0.com.facebook.react.uimanager.common.UIManagerType; +import abi49_0_0.com.facebook.react.fabric.FabricUIManager; + +class ReaCompatibility { + private FabricUIManager fabricUIManager; + + public ReaCompatibility(ReactApplicationContext reactApplicationContext) { + fabricUIManager = (FabricUIManager) UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC); + } + + public void registerFabricEventListener(NodesManager nodeManager) { + if (fabricUIManager != null) { + fabricUIManager.getEventDispatcher().addListener(nodeManager); + } + } + + public void synchronouslyUpdateUIProps(int viewTag, ReadableMap uiProps) { + fabricUIManager.synchronouslyUpdateViewOnUIThread(viewTag, uiProps); + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/react-native-reanimated/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5483971cfb570 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidErrorHandler.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidErrorHandler.cpp new file mode 100644 index 00000000000000..fb1386fcadfaf9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidErrorHandler.cpp @@ -0,0 +1,41 @@ +#include "AndroidErrorHandler.h" +#include +#include +#include +#include "Logger.h" + +namespace reanimated { + +using namespace facebook::jni; + +AndroidErrorHandler::AndroidErrorHandler(std::shared_ptr scheduler) { + this->scheduler = scheduler; + this->error = std::make_shared(); +} + +void AndroidErrorHandler::raiseSpec() { + if (error->handled) { + return; + } + + // mark error as handled before this method throws exception + this->error->handled = true; + throw std::runtime_error(this->error->message); +} + +std::shared_ptr AndroidErrorHandler::getScheduler() { + return this->scheduler; +} + +std::shared_ptr AndroidErrorHandler::getError() { + return this->error; +} + +void AndroidErrorHandler::setError(std::string message) { + if (error->handled) { + error->message = message; + error->handled = false; + } +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidErrorHandler.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidErrorHandler.h new file mode 100644 index 00000000000000..5db14393507730 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidErrorHandler.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include +#include "AndroidScheduler.h" +#include "ErrorHandler.h" +#include "Logger.h" +#include "Scheduler.h" + +namespace reanimated { + +class AndroidErrorHandler : public ErrorHandler { + std::shared_ptr error; + std::shared_ptr scheduler; + void raiseSpec() override; + + public: + explicit AndroidErrorHandler(std::shared_ptr scheduler); + std::shared_ptr getScheduler() override; + std::shared_ptr getError() override; + void setError(std::string message) override; + virtual ~AndroidErrorHandler() {} +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidLogger.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidLogger.cpp new file mode 100644 index 00000000000000..767ce6f43f2ab1 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidLogger.cpp @@ -0,0 +1,30 @@ +#include +#include + +#include "AndroidLogger.h" +#include "Logger.h" + +#define APPNAME "NATIVE_REANIMATED" + +namespace reanimated { + +std::unique_ptr Logger::instance = + std::make_unique(); + +void AndroidLogger::log(const char *str) { + __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "%s", str); +} + +void AndroidLogger::log(double d) { + __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "%f", d); +} + +void AndroidLogger::log(int i) { + __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "%d", i); +} + +void AndroidLogger::log(bool b) { + __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "%s", b ? "true" : "false"); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidLogger.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidLogger.h new file mode 100644 index 00000000000000..7e1f3a52fa679a --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidLogger.h @@ -0,0 +1,16 @@ +#pragma once + +#include "LoggerInterface.h" + +namespace reanimated { + +class AndroidLogger : public LoggerInterface { + public: + void log(const char *str) override; + void log(double d) override; + void log(int i) override; + void log(bool b) override; + virtual ~AndroidLogger() {} +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidScheduler.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidScheduler.cpp new file mode 100644 index 00000000000000..1b5b976af1fb10 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidScheduler.cpp @@ -0,0 +1,59 @@ +#include "AndroidScheduler.h" +#include +#include +#include +#include +#include + +namespace reanimated { + +using namespace facebook; +using namespace react; + +class SchedulerWrapper : public Scheduler { + private: + jni::global_ref scheduler_; + + public: + explicit SchedulerWrapper( + jni::global_ref scheduler) + : scheduler_(scheduler) {} + + void scheduleOnUI(std::function job) override { + Scheduler::scheduleOnUI(job); + if (!scheduledOnUI) { + scheduledOnUI = true; + scheduler_->cthis()->scheduleOnUI(); + } + } + + ~SchedulerWrapper() {} +}; + +AndroidScheduler::AndroidScheduler( + jni::alias_ref jThis) + : javaPart_(jni::make_global(jThis)), + scheduler_(new SchedulerWrapper(jni::make_global(jThis))) {} + +jni::local_ref AndroidScheduler::initHybrid( + jni::alias_ref jThis) { + return makeCxxInstance(jThis); +} + +void AndroidScheduler::triggerUI() { + scheduler_->triggerUI(); +} + +void AndroidScheduler::scheduleOnUI() { + static auto method = javaPart_->getClass()->getMethod("scheduleOnUI"); + method(javaPart_.get()); +} + +void AndroidScheduler::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", AndroidScheduler::initHybrid), + makeNativeMethod("triggerUI", AndroidScheduler::triggerUI), + }); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidScheduler.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidScheduler.h new file mode 100644 index 00000000000000..482fe108b78c3c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/AndroidScheduler.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Scheduler.h" + +namespace reanimated { + +using namespace facebook; + +class AndroidScheduler : public jni::HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/Scheduler;"; + static jni::local_ref initHybrid( + jni::alias_ref jThis); + static void registerNatives(); + + std::shared_ptr getScheduler() { + return scheduler_; + } + + void scheduleOnUI(); + + private: + friend HybridBase; + + void triggerUI(); + + jni::global_ref javaPart_; + std::shared_ptr scheduler_; + + explicit AndroidScheduler( + jni::alias_ref jThis); +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/JNIHelper.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/JNIHelper.cpp new file mode 100644 index 00000000000000..2d0b20011a1e75 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/JNIHelper.cpp @@ -0,0 +1,59 @@ +#include "JNIHelper.h" + +namespace reanimated { + +using namespace facebook::jni; +using namespace facebook; +using namespace react; + +local_ref JNIHelper::PropsMap::create() { + return newInstance(); +} + +void JNIHelper::PropsMap::put( + const std::string &key, + jni::local_ref object) { + static auto method = + getClass() + ->getMethod, jni::local_ref)>("put"); + method(self(), jni::make_jstring(key), object); +} + +jni::local_ref JNIHelper::ConvertToPropsMap( + jsi::Runtime &rt, + const jsi::Object &props) { + auto map = PropsMap::create(); + + auto propNames = props.getPropertyNames(rt); + for (size_t i = 0, size = propNames.size(rt); i < size; i++) { + auto jsiKey = propNames.getValueAtIndex(rt, i).asString(rt); + auto value = props.getProperty(rt, jsiKey); + auto key = jsiKey.utf8(rt); + if (value.isUndefined() || value.isNull()) { + map->put(key, nullptr); + } else if (value.isBool()) { + map->put(key, JBoolean::valueOf(value.getBool())); + } else if (value.isNumber()) { + map->put(key, jni::autobox(value.asNumber())); + } else if (value.isString()) { + map->put(key, jni::make_jstring(value.asString(rt).utf8(rt))); + } else if (value.isObject()) { + if (value.asObject(rt).isArray(rt)) { + map->put( + key, + ReadableNativeArray::newObjectCxxArgs( + jsi::dynamicFromValue(rt, value))); + } else { + map->put( + key, + ReadableNativeMap::newObjectCxxArgs( + jsi::dynamicFromValue(rt, value))); + } + } + } + + return map; +} + +}; // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/JNIHelper.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/JNIHelper.h new file mode 100644 index 00000000000000..4be35556d55eac --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/JNIHelper.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace reanimated { + +using namespace facebook::jni; +using namespace facebook; +using namespace react; + +struct JNIHelper { + struct PropsMap : jni::JavaClass> { + static constexpr auto kJavaDescriptor = "Ljava/util/HashMap;"; + + static local_ref create(); + void put(const std::string &key, jni::local_ref object); + }; + + static jni::local_ref ConvertToPropsMap( + jsi::Runtime &rt, + const jsi::Object &props); +}; + +}; // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/LayoutAnimations.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/LayoutAnimations.cpp new file mode 100644 index 00000000000000..6e31ee2c077f77 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/LayoutAnimations.cpp @@ -0,0 +1,115 @@ +#include "LayoutAnimations.h" +#include "FeaturesConfig.h" +#include "Logger.h" + +namespace reanimated { + +LayoutAnimations::LayoutAnimations( + jni::alias_ref jThis) + : javaPart_(jni::make_global(jThis)) {} + +jni::local_ref LayoutAnimations::initHybrid( + jni::alias_ref jThis) { + return makeCxxInstance(jThis); +} + +void LayoutAnimations::setAnimationStartingBlock( + AnimationStartingBlock animationStartingBlock) { + this->animationStartingBlock_ = animationStartingBlock; +} + +void LayoutAnimations::startAnimationForTag( + int tag, + int type, + alias_ref> values) { + this->animationStartingBlock_(tag, type, values); +} + +void LayoutAnimations::progressLayoutAnimation( + int tag, + const jni::local_ref &updates, + bool isSharedTransition) { + static const auto method = + javaPart_->getClass() + ->getMethod::javaobject, bool)>( + "progressLayoutAnimation"); + method(javaPart_.get(), tag, updates.get(), isSharedTransition); +} + +void LayoutAnimations::endLayoutAnimation( + int tag, + bool cancelled, + bool removeView) { + static const auto method = + javaPart_->getClass()->getMethod( + "endLayoutAnimation"); + method(javaPart_.get(), tag, cancelled, removeView); +} + +void LayoutAnimations::setHasAnimationBlock( + HasAnimationBlock hasAnimationBlock) { + this->hasAnimationBlock_ = hasAnimationBlock; +} + +bool LayoutAnimations::hasAnimationForTag(int tag, int type) { + return hasAnimationBlock_(tag, type); +} + +void LayoutAnimations::setClearAnimationConfigBlock( + ClearAnimationConfigBlock clearAnimationConfigBlock) { + this->clearAnimationConfigBlock_ = clearAnimationConfigBlock; +} + +void LayoutAnimations::clearAnimationConfigForTag(int tag) { + clearAnimationConfigBlock_(tag); +} + +void LayoutAnimations::setCancelAnimationForTag( + CancelAnimationBlock cancelAnimationBlock) { + this->cancelAnimationBlock_ = cancelAnimationBlock; +} + +void LayoutAnimations::cancelAnimationForTag( + int tag, + int type, + jboolean cancelled, + jboolean removeView) { + this->cancelAnimationBlock_(tag, type, cancelled, removeView); +} + +bool LayoutAnimations::isLayoutAnimationEnabled() { + return FeaturesConfig::isLayoutAnimationEnabled(); +} + +void LayoutAnimations::setFindPrecedingViewTagForTransition( + FindPrecedingViewTagForTransitionBlock + findPrecedingViewTagForTransitionBlock) { + findPrecedingViewTagForTransitionBlock_ = + findPrecedingViewTagForTransitionBlock; +} + +int LayoutAnimations::findPrecedingViewTagForTransition(int tag) { + return findPrecedingViewTagForTransitionBlock_(tag); +} + +void LayoutAnimations::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", LayoutAnimations::initHybrid), + makeNativeMethod( + "startAnimationForTag", LayoutAnimations::startAnimationForTag), + makeNativeMethod( + "hasAnimationForTag", LayoutAnimations::hasAnimationForTag), + makeNativeMethod( + "clearAnimationConfigForTag", + LayoutAnimations::clearAnimationConfigForTag), + makeNativeMethod( + "cancelAnimationForTag", LayoutAnimations::cancelAnimationForTag), + makeNativeMethod( + "isLayoutAnimationEnabled", + LayoutAnimations::isLayoutAnimationEnabled), + makeNativeMethod( + "findPrecedingViewTagForTransition", + LayoutAnimations::findPrecedingViewTagForTransition), + }); +} +}; // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/LayoutAnimations.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/LayoutAnimations.h new file mode 100644 index 00000000000000..75a88208fdb2f2 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/LayoutAnimations.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include +#include "JNIHelper.h" + +namespace reanimated { + +using namespace facebook::jni; +using namespace facebook; + +class LayoutAnimations : public jni::HybridClass { + using AnimationStartingBlock = + std::function>)>; + using HasAnimationBlock = std::function; + using ClearAnimationConfigBlock = std::function; + using CancelAnimationBlock = + std::function; + using FindPrecedingViewTagForTransitionBlock = std::function; + + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/layoutReanimation/LayoutAnimations;"; + static jni::local_ref initHybrid( + jni::alias_ref jThis); + static void registerNatives(); + + void startAnimationForTag( + int tag, + int type, + alias_ref> values); + bool hasAnimationForTag(int tag, int type); + bool isLayoutAnimationEnabled(); + + void setAnimationStartingBlock(AnimationStartingBlock animationStartingBlock); + void setHasAnimationBlock(HasAnimationBlock hasAnimationBlock); + void setClearAnimationConfigBlock( + ClearAnimationConfigBlock clearAnimationConfigBlock); + void setCancelAnimationForTag(CancelAnimationBlock cancelAnimationBlock); + void setFindPrecedingViewTagForTransition( + FindPrecedingViewTagForTransitionBlock + findPrecedingViewTagForTransitionBlock); + + void progressLayoutAnimation( + int tag, + const jni::local_ref &updates, + bool isSharedTransition); + void endLayoutAnimation(int tag, bool cancelled, bool removeView); + void clearAnimationConfigForTag(int tag); + void cancelAnimationForTag( + int tag, + int type, + jboolean cancelled, + jboolean removeView); + int findPrecedingViewTagForTransition(int tag); + + private: + friend HybridBase; + jni::global_ref javaPart_; + AnimationStartingBlock animationStartingBlock_; + HasAnimationBlock hasAnimationBlock_; + ClearAnimationConfigBlock clearAnimationConfigBlock_; + CancelAnimationBlock cancelAnimationBlock_; + FindPrecedingViewTagForTransitionBlock + findPrecedingViewTagForTransitionBlock_; + + explicit LayoutAnimations( + jni::alias_ref jThis); +}; + +}; // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/NativeProxy.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/NativeProxy.cpp new file mode 100644 index 00000000000000..1386d81187e276 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/NativeProxy.cpp @@ -0,0 +1,573 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "AndroidErrorHandler.h" +#include "AndroidScheduler.h" +#include "JsiUtils.h" +#include "LayoutAnimationsManager.h" +#include "NativeProxy.h" +#include "PlatformDepMethodsHolder.h" +#include "ReanimatedRuntime.h" +#include "ReanimatedVersion.h" + +#ifdef RCT_NEW_ARCH_ENABLED +#include "FabricUtils.h" +#include "NewestShadowNodesRegistry.h" +#include "ReanimatedUIManagerBinding.h" +#endif + +namespace reanimated { + +using namespace facebook; +using namespace react; + +NativeProxy::NativeProxy( + jni::alias_ref jThis, + jsi::Runtime *rt, + std::shared_ptr jsCallInvoker, + std::shared_ptr scheduler, + jni::global_ref _layoutAnimations +#ifdef RCT_NEW_ARCH_ENABLED + , + jni::alias_ref + fabricUIManager +#endif + ) + : javaPart_(jni::make_global(jThis)), + runtime_(rt), + jsCallInvoker_(jsCallInvoker), + layoutAnimations_(std::move(_layoutAnimations)), + scheduler_(scheduler) +#ifdef RCT_NEW_ARCH_ENABLED + , + newestShadowNodesRegistry_(std::make_shared()) +#endif +{ +#ifdef RCT_NEW_ARCH_ENABLED + Binding *binding = fabricUIManager->getBinding(); + RuntimeExecutor runtimeExecutor = getRuntimeExecutorFromBinding(binding); + std::shared_ptr uiManager = + binding->getScheduler()->getUIManager(); + ReanimatedUIManagerBinding::createAndInstallIfNeeded( + *rt, runtimeExecutor, uiManager, newestShadowNodesRegistry_); +#endif +} + +NativeProxy::~NativeProxy() { + // removed temporary, new event listener mechanism need fix on the RN side + // reactScheduler_->removeEventListener(eventListener_); + + // cleanup all animated sensors here, since NativeProxy + // has already been destroyed when AnimatedSensorModule's + // destructor is ran + nativeReanimatedModule_->cleanupSensors(); +} + +jni::local_ref NativeProxy::initHybrid( + jni::alias_ref jThis, + jlong jsContext, + jni::alias_ref + jsCallInvokerHolder, + jni::alias_ref androidScheduler, + jni::alias_ref layoutAnimations +#ifdef RCT_NEW_ARCH_ENABLED + , + jni::alias_ref + fabricUIManager +#endif +) { + auto jsCallInvoker = jsCallInvokerHolder->cthis()->getCallInvoker(); + auto scheduler = androidScheduler->cthis()->getScheduler(); + scheduler->setJSCallInvoker(jsCallInvoker); + return makeCxxInstance( + jThis, + (jsi::Runtime *)jsContext, + jsCallInvoker, + scheduler, + make_global(layoutAnimations) +#ifdef RCT_NEW_ARCH_ENABLED + , + fabricUIManager +#endif + /**/); +} + +void NativeProxy::installJSIBindings( + jni::alias_ref messageQueueThread +#ifdef RCT_NEW_ARCH_ENABLED + , + jni::alias_ref + fabricUIManager +#endif + /**/) { + auto jsQueue = std::make_shared(messageQueueThread); + std::shared_ptr animatedRuntime = + ReanimatedRuntime::make(runtime_, jsQueue); + + std::shared_ptr errorHandler = + std::make_shared(scheduler_); + + auto module = std::make_shared( + jsCallInvoker_, + scheduler_, + animatedRuntime, + errorHandler, +#ifdef RCT_NEW_ARCH_ENABLED + // nothing +#else + bindThis(&NativeProxy::obtainProp), +#endif + getPlatformDependentMethods()); + + scheduler_->setRuntimeManager(module); + nativeReanimatedModule_ = module; + +#ifdef RCT_NEW_ARCH_ENABLED + Binding *binding = fabricUIManager->getBinding(); + std::shared_ptr uiManager = + binding->getScheduler()->getUIManager(); + module->setUIManager(uiManager); + module->setNewestShadowNodesRegistry(newestShadowNodesRegistry_); + newestShadowNodesRegistry_ = nullptr; +// removed temporary, new event listener mechanism need fix on the RN side +// eventListener_ = std::make_shared( +// [module, getCurrentTime](const RawEvent &rawEvent) { +// return module->handleRawEvent(rawEvent, getCurrentTime()); +// }); +// reactScheduler_ = binding->getScheduler(); +// reactScheduler_->addEventListener(eventListener_); +#endif + + auto &rt = *runtime_; + setGlobalProperties(rt, animatedRuntime); + registerEventHandler(); + setupLayoutAnimations(); + + rt.global().setProperty( + rt, + jsi::PropNameID::forAscii(rt, "__reanimatedModuleProxy"), + jsi::Object::createFromHostObject(rt, module)); +} + +bool NativeProxy::isAnyHandlerWaitingForEvent(std::string s) { + return nativeReanimatedModule_->isAnyHandlerWaitingForEvent(s); +} + +void NativeProxy::performOperations() { +#ifdef RCT_NEW_ARCH_ENABLED + nativeReanimatedModule_->performOperations(); +#endif +} + +void NativeProxy::registerNatives() { + registerHybrid( + {makeNativeMethod("initHybrid", NativeProxy::initHybrid), + makeNativeMethod("installJSIBindings", NativeProxy::installJSIBindings), + makeNativeMethod( + "isAnyHandlerWaitingForEvent", + NativeProxy::isAnyHandlerWaitingForEvent), + makeNativeMethod("performOperations", NativeProxy::performOperations)}); +} + +void NativeProxy::requestRender( + std::function onRender, + jsi::Runtime &rt) { + static const auto method = + getJniMethod("requestRender"); + method( + javaPart_.get(), + AnimationFrameCallback::newObjectCxxArgs(std::move(onRender)).get()); +} + +void NativeProxy::registerEventHandler() { + auto eventHandler = bindThis(&NativeProxy::handleEvent); + static const auto method = + getJniMethod("registerEventHandler"); + method( + javaPart_.get(), + EventHandler::newObjectCxxArgs(std::move(eventHandler)).get()); +} + +void NativeProxy::maybeFlushUIUpdatesQueue() { + static const auto method = getJniMethod("maybeFlushUIUpdatesQueue"); + method(javaPart_.get()); +} + +#ifdef RCT_NEW_ARCH_ENABLED +// nothing +#else +jsi::Value NativeProxy::obtainProp( + jsi::Runtime &rt, + const int viewTag, + const jsi::String &propName) { + static const auto method = + getJniMethod(int, jni::local_ref)>( + "obtainProp"); + local_ref propNameJStr = + jni::make_jstring(propName.utf8(rt).c_str()); + auto result = method(javaPart_.get(), viewTag, propNameJStr); + std::string str = result->toStdString(); + return jsi::Value(rt, jsi::String::createFromAscii(rt, str)); +} + +void NativeProxy::configureProps( + jsi::Runtime &rt, + const jsi::Value &uiProps, + const jsi::Value &nativeProps) { + static const auto method = getJniMethod( + "configureProps"); + method( + javaPart_.get(), + ReadableNativeArray::newObjectCxxArgs(jsi::dynamicFromValue(rt, uiProps)) + .get(), + ReadableNativeArray::newObjectCxxArgs( + jsi::dynamicFromValue(rt, nativeProps)) + .get()); +} + +void NativeProxy::updateProps( + jsi::Runtime &rt, + int viewTag, + const jsi::Value &viewName, + const jsi::Object &props) { + static const auto method = + getJniMethod::javaobject)>( + "updateProps"); + method( + javaPart_.get(), viewTag, JNIHelper::ConvertToPropsMap(rt, props).get()); +} + +void NativeProxy::scrollTo(int viewTag, double x, double y, bool animated) { + static const auto method = + getJniMethod("scrollTo"); + method(javaPart_.get(), viewTag, x, y, animated); +} + +std::vector> NativeProxy::measure(int viewTag) { + static const auto method = + getJniMethod(int)>("measure"); + local_ref output = method(javaPart_.get(), viewTag); + size_t size = output->size(); + auto elements = output->getRegion(0, size); + std::vector> result; + + result.push_back({"x", elements[0]}); + result.push_back({"y", elements[1]}); + + result.push_back({"pageX", elements[2]}); + result.push_back({"pageY", elements[3]}); + + result.push_back({"width", elements[4]}); + result.push_back({"height", elements[5]}); + + return result; +} +#endif // RCT_NEW_ARCH_ENABLED + +#ifdef RCT_NEW_ARCH_ENABLED +inline jni::local_ref castReadableMap( + jni::local_ref const &nativeMap) { + return make_local(reinterpret_cast(nativeMap.get())); +} + +void NativeProxy::synchronouslyUpdateUIProps( + jsi::Runtime &rt, + Tag tag, + const jsi::Value &props) { + static const auto method = + getJniMethod)>( + "synchronouslyUpdateUIProps"); + jni::local_ref uiProps = castReadableMap( + ReadableNativeMap::newObjectCxxArgs(jsi::dynamicFromValue(rt, props))); + method(javaPart_.get(), tag, uiProps); +} +#endif + +int NativeProxy::registerSensor( + int sensorType, + int interval, + int iosReferenceFrame, + std::function setter) { + static const auto method = + getJniMethod("registerSensor"); + return method( + javaPart_.get(), + sensorType, + interval, + SensorSetter::newObjectCxxArgs(std::move(setter)).get()); +} +void NativeProxy::unregisterSensor(int sensorId) { + static const auto method = getJniMethod("unregisterSensor"); + method(javaPart_.get(), sensorId); +} + +void NativeProxy::setGestureState(int handlerTag, int newState) { + static const auto method = getJniMethod("setGestureState"); + method(javaPart_.get(), handlerTag, newState); +} + +int NativeProxy::subscribeForKeyboardEvents( + std::function keyboardEventDataUpdater, + bool isStatusBarTranslucent) { + static const auto method = + getJniMethod( + "subscribeForKeyboardEvents"); + return method( + javaPart_.get(), + KeyboardEventDataUpdater::newObjectCxxArgs( + std::move(keyboardEventDataUpdater)) + .get(), + isStatusBarTranslucent); +} + +void NativeProxy::unsubscribeFromKeyboardEvents(int listenerId) { + static const auto method = + getJniMethod("unsubscribeFromKeyboardEvents"); + method(javaPart_.get(), listenerId); +} + +double NativeProxy::getCurrentTime() { + static const auto method = getJniMethod("getCurrentTime"); + jlong output = method(javaPart_.get()); + return static_cast(output); +} + +void NativeProxy::handleEvent( + jni::alias_ref eventKey, + jni::alias_ref event) { + // handles RCTEvents from RNGestureHandler + auto eventName = eventKey->toString(); + + // TODO: convert event directly to jsi::Value without JSON serialization + std::string eventAsString; + try { + eventAsString = event->toString(); + } catch (std::exception &) { + // Events from other libraries may contain NaN or INF values which + // cannot be represented in JSON. See + // https://github.com/software-mansion/react-native-reanimated/issues/1776 + // for details. + return; + } +#if REACT_NATIVE_MINOR_VERSION >= 72 + std::string eventJSON = eventAsString; +#else + // remove "{ NativeMap: " and " }" + std::string eventJSON = eventAsString.substr(13, eventAsString.length() - 15); +#endif + if (eventJSON == "null") { + return; + } + + jsi::Runtime &rt = *nativeReanimatedModule_->runtime; + jsi::Value payload; + try { + payload = jsi::Value::createFromJsonUtf8( + rt, reinterpret_cast(&eventJSON[0]), eventJSON.size()); + } catch (std::exception &) { + // Ignore events with malformed JSON payload. + return; + } + + nativeReanimatedModule_->handleEvent( + eventName, payload, this->getCurrentTime()); +} + +void NativeProxy::progressLayoutAnimation( + int tag, + const jsi::Object &newProps, + bool isSharedTransition) { + auto &rt = *nativeReanimatedModule_->runtime; + auto newPropsJNI = JNIHelper::ConvertToPropsMap(rt, newProps); + layoutAnimations_->cthis()->progressLayoutAnimation( + tag, newPropsJNI, isSharedTransition); +} + +PlatformDepMethodsHolder NativeProxy::getPlatformDependentMethods() { +#ifdef RCT_NEW_ARCH_ENABLED + // nothing +#else + auto updatePropsFunction = bindThis(&NativeProxy::updateProps); + + auto measureFunction = bindThis(&NativeProxy::measure); + + auto scrollToFunction = bindThis(&NativeProxy::scrollTo); +#endif + + auto getCurrentTime = bindThis(&NativeProxy::getCurrentTime); + + auto requestRender = bindThis(&NativeProxy::requestRender); + +#ifdef RCT_NEW_ARCH_ENABLED + auto synchronouslyUpdateUIPropsFunction = + bindThis(&NativeProxy::synchronouslyUpdateUIProps); +#else + auto configurePropsFunction = bindThis(&NativeProxy::configureProps); +#endif + + auto registerSensorFunction = bindThis(&NativeProxy::registerSensor); + auto unregisterSensorFunction = bindThis(&NativeProxy::unregisterSensor); + + auto setGestureStateFunction = bindThis(&NativeProxy::setGestureState); + + auto subscribeForKeyboardEventsFunction = + bindThis(&NativeProxy::subscribeForKeyboardEvents); + + auto unsubscribeFromKeyboardEventsFunction = + bindThis(&NativeProxy::unsubscribeFromKeyboardEvents); + + auto progressLayoutAnimation = + bindThis(&NativeProxy::progressLayoutAnimation); + + auto endLayoutAnimation = [this](int tag, bool isCancelled, bool removeView) { + this->layoutAnimations_->cthis()->endLayoutAnimation( + tag, isCancelled, removeView); + }; + + auto maybeFlushUiUpdatesQueueFunction = + bindThis(&NativeProxy::maybeFlushUIUpdatesQueue); + + return { + requestRender, +#ifdef RCT_NEW_ARCH_ENABLED + synchronouslyUpdateUIPropsFunction, +#else + updatePropsFunction, + scrollToFunction, + measureFunction, + configurePropsFunction, +#endif + getCurrentTime, + progressLayoutAnimation, + endLayoutAnimation, + registerSensorFunction, + unregisterSensorFunction, + setGestureStateFunction, + subscribeForKeyboardEventsFunction, + unsubscribeFromKeyboardEventsFunction, + maybeFlushUiUpdatesQueueFunction, + }; +} + +void NativeProxy::setGlobalProperties( + jsi::Runtime &jsRuntime, + const std::shared_ptr &reanimatedRuntime) { + auto workletRuntimeValue = + jsRuntime.global() + .getPropertyAsObject(jsRuntime, "ArrayBuffer") + .asFunction(jsRuntime) + .callAsConstructor(jsRuntime, {static_cast(sizeof(void *))}); + uintptr_t *workletRuntimeData = reinterpret_cast( + workletRuntimeValue.getObject(jsRuntime).getArrayBuffer(jsRuntime).data( + jsRuntime)); + workletRuntimeData[0] = reinterpret_cast(reanimatedRuntime.get()); + + jsRuntime.global().setProperty( + jsRuntime, "_WORKLET_RUNTIME", workletRuntimeValue); + + jsRuntime.global().setProperty(jsRuntime, "_WORKLET", false); + +#ifdef RCT_NEW_ARCH_ENABLED + jsRuntime.global().setProperty(jsRuntime, "_IS_FABRIC", true); +#else + jsRuntime.global().setProperty(jsRuntime, "_IS_FABRIC", false); +#endif + + auto version = getReanimatedVersionString(jsRuntime); + jsRuntime.global().setProperty(jsRuntime, "_REANIMATED_VERSION_CPP", version); +} + +void NativeProxy::setupLayoutAnimations() { + auto weakModule = + std::weak_ptr(nativeReanimatedModule_); + + layoutAnimations_->cthis()->setAnimationStartingBlock( + [weakModule]( + int tag, int type, alias_ref> values) { + auto module = weakModule.lock(); + if (module == nullptr) { + return; + } + auto &rt = *module->runtime; + auto errorHandler = module->errorHandler; + + jsi::Object yogaValues(rt); + for (const auto &entry : *values) { + try { + std::string keyString = entry.first->toStdString(); + std::string valueString = entry.second->toStdString(); + auto key = jsi::String::createFromAscii(rt, keyString); + if (keyString == "currentTransformMatrix" || + keyString == "targetTransformMatrix") { + jsi::Array matrix = + jsi_utils::convertStringToArray(rt, valueString, 9); + yogaValues.setProperty(rt, key, matrix); + } else { + auto value = stod(valueString); + yogaValues.setProperty(rt, key, value); + } + } catch (std::invalid_argument e) { + errorHandler->setError("Failed to convert value to number"); + errorHandler->raise(); + } + } + + module->layoutAnimationsManager().startLayoutAnimation( + rt, tag, static_cast(type), yogaValues); + }); + + layoutAnimations_->cthis()->setHasAnimationBlock( + [weakModule](int tag, int type) { + auto module = weakModule.lock(); + if (module == nullptr) { + return false; + } + + return module->layoutAnimationsManager().hasLayoutAnimation( + tag, static_cast(type)); + }); + + layoutAnimations_->cthis()->setClearAnimationConfigBlock( + [weakModule](int tag) { + auto module = weakModule.lock(); + if (module == nullptr) { + return; + } + + module->layoutAnimationsManager().clearLayoutAnimationConfig(tag); + }); + + layoutAnimations_->cthis()->setCancelAnimationForTag( + [weakModule](int tag, int type, jboolean cancelled, jboolean removeView) { + if (auto module = weakModule.lock()) { + jsi::Runtime &rt = *module->runtime; + module->layoutAnimationsManager().cancelLayoutAnimation( + rt, + tag, + static_cast(type), + cancelled, + removeView); + } + }); + + layoutAnimations_->cthis()->setFindPrecedingViewTagForTransition( + [weakModule](int tag) { + if (auto module = weakModule.lock()) { + return module->layoutAnimationsManager() + .findPrecedingViewTagForTransition(tag); + } else { + return -1; + } + }); +} + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/NativeProxy.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/NativeProxy.h new file mode 100644 index 00000000000000..9599c6ade7924b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/NativeProxy.h @@ -0,0 +1,275 @@ +#pragma once + +#ifdef RCT_NEW_ARCH_ENABLED +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "AndroidScheduler.h" +#include "JNIHelper.h" +#include "LayoutAnimations.h" +#include "NativeReanimatedModule.h" +#include "Scheduler.h" + +namespace reanimated { + +using namespace facebook; +using namespace facebook::jni; + +class AnimationFrameCallback : public HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/nativeProxy/AnimationFrameCallback;"; + + void onAnimationFrame(double timestampMs) { + callback_(timestampMs); + } + + static void registerNatives() { + javaClassStatic()->registerNatives({ + makeNativeMethod( + "onAnimationFrame", AnimationFrameCallback::onAnimationFrame), + }); + } + + private: + friend HybridBase; + + explicit AnimationFrameCallback(std::function callback) + : callback_(std::move(callback)) {} + + std::function callback_; +}; + +class EventHandler : public HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/nativeProxy/EventHandler;"; + + void receiveEvent( + jni::alias_ref eventKey, + jni::alias_ref event) { + handler_(eventKey, event); + } + + static void registerNatives() { + javaClassStatic()->registerNatives({ + makeNativeMethod("receiveEvent", EventHandler::receiveEvent), + }); + } + + private: + friend HybridBase; + + explicit EventHandler(std::function, + jni::alias_ref)> handler) + : handler_(std::move(handler)) {} + + std::function< + void(jni::alias_ref, jni::alias_ref)> + handler_; +}; + +class SensorSetter : public HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/nativeProxy/SensorSetter;"; + + void sensorSetter(jni::alias_ref value, int orientationDegrees) { + size_t size = value->size(); + auto elements = value->getRegion(0, size); + double array[7]; + for (int i = 0; i < size; i++) { + array[i] = elements[i]; + } + callback_(array, orientationDegrees); + } + + static void registerNatives() { + javaClassStatic()->registerNatives({ + makeNativeMethod("sensorSetter", SensorSetter::sensorSetter), + }); + } + + private: + friend HybridBase; + + explicit SensorSetter(std::function callback) + : callback_(std::move(callback)) {} + + std::function callback_; +}; + +class KeyboardEventDataUpdater : public HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/nativeProxy/KeyboardEventDataUpdater;"; + + void keyboardEventDataUpdater(int keyboardState, int height) { + callback_(keyboardState, height); + } + + static void registerNatives() { + javaClassStatic()->registerNatives({ + makeNativeMethod( + "keyboardEventDataUpdater", + KeyboardEventDataUpdater::keyboardEventDataUpdater), + }); + } + + private: + friend HybridBase; + + explicit KeyboardEventDataUpdater(std::function callback) + : callback_(std::move(callback)) {} + + std::function callback_; +}; + +class NativeProxy : public jni::HybridClass { + public: + static auto constexpr kJavaDescriptor = + "Labi49_0_0/com/swmansion/reanimated/NativeProxy;"; + static jni::local_ref initHybrid( + jni::alias_ref jThis, + jlong jsContext, + jni::alias_ref + jsCallInvokerHolder, + jni::alias_ref scheduler, + jni::alias_ref layoutAnimations +#ifdef RCT_NEW_ARCH_ENABLED + , + jni::alias_ref + fabricUIManager +#endif + /**/); + static void registerNatives(); + + ~NativeProxy(); + + private: + friend HybridBase; + jni::global_ref javaPart_; + jsi::Runtime *runtime_; + std::shared_ptr jsCallInvoker_; + std::shared_ptr nativeReanimatedModule_; + jni::global_ref layoutAnimations_; + std::shared_ptr scheduler_; +#ifdef RCT_NEW_ARCH_ENABLED + std::shared_ptr newestShadowNodesRegistry_; + +// removed temporary, new event listener mechanism need fix on the RN side +// std::shared_ptr reactScheduler_; +// std::shared_ptr eventListener_; +#endif +#ifdef RCT_NEW_ARCH_ENABLED + void installJSIBindings( + jni::alias_ref messageQueueThread, + jni::alias_ref fabricUIManager); + void synchronouslyUpdateUIProps( + jsi::Runtime &rt, + Tag viewTag, + const jsi::Value &uiProps); +#else + void installJSIBindings( + jni::alias_ref messageQueueThread); +#endif + PlatformDepMethodsHolder getPlatformDependentMethods(); + void setGlobalProperties( + jsi::Runtime &jsRuntime, + const std::shared_ptr &reanimatedRuntime); + void setupLayoutAnimations(); + + double getCurrentTime(); + bool isAnyHandlerWaitingForEvent(std::string); + void performOperations(); + void requestRender(std::function onRender, jsi::Runtime &rt); + void registerEventHandler(); + void maybeFlushUIUpdatesQueue(); + void setGestureState(int handlerTag, int newState); + int registerSensor( + int sensorType, + int interval, + int iosReferenceFrame, + std::function setter); + void unregisterSensor(int sensorId); + int subscribeForKeyboardEvents( + std::function keyboardEventDataUpdater, + bool isStatusBarTranslucent); + void unsubscribeFromKeyboardEvents(int listenerId); +#ifdef RCT_NEW_ARCH_ENABLED + // nothing +#else + jsi::Value + obtainProp(jsi::Runtime &rt, const int viewTag, const jsi::String &propName); + void configureProps( + jsi::Runtime &rt, + const jsi::Value &uiProps, + const jsi::Value &nativeProps); + void updateProps( + jsi::Runtime &rt, + int viewTag, + const jsi::Value &viewName, + const jsi::Object &props); + void scrollTo(int viewTag, double x, double y, bool animated); + std::vector> measure(int viewTag); +#endif + void handleEvent( + jni::alias_ref eventKey, + jni::alias_ref event); + + void progressLayoutAnimation( + int tag, + const jsi::Object &newProps, + bool isSharedTransition); + + /*** + * Wraps a method of `NativeProxy` in a function object capturing `this` + * @tparam TReturn return type of passed method + * @tparam TParams paramater types of passed method + * @param methodPtr pointer to method to be wrapped + * @return a function object with the same signature as the method, calling + * that method on `this` + */ + template + std::function bindThis( + TReturn (NativeProxy::*methodPtr)(TParams...)) { + return [this, methodPtr](TParams &&...args) { + return (this->*methodPtr)(std::forward(args)...); + }; + } + + template + JMethod getJniMethod(std::string const &methodName) { + return javaPart_->getClass()->getMethod(methodName.c_str()); + } + + explicit NativeProxy( + jni::alias_ref jThis, + jsi::Runtime *rt, + std::shared_ptr jsCallInvoker, + std::shared_ptr scheduler, + jni::global_ref _layoutAnimations +#ifdef RCT_NEW_ARCH_ENABLED + , + jni::alias_ref + fabricUIManager +#endif + /**/); +}; + +} // namespace reanimated diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/OnLoad.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/OnLoad.cpp new file mode 100644 index 00000000000000..644f222a3a3c77 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/OnLoad.cpp @@ -0,0 +1,18 @@ +#include + +#include "AndroidScheduler.h" +#include "LayoutAnimations.h" +#include "Logger.h" +#include "NativeProxy.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::jni::initialize(vm, [] { + reanimated::NativeProxy::registerNatives(); + reanimated::AnimationFrameCallback::registerNatives(); + reanimated::EventHandler::registerNatives(); + reanimated::AndroidScheduler::registerNatives(); + reanimated::LayoutAnimations::registerNatives(); + reanimated::SensorSetter::registerNatives(); + reanimated::KeyboardEventDataUpdater::registerNatives(); + }); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/TurboModule.cpp b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/TurboModule.cpp new file mode 100644 index 00000000000000..6247bf99fe475d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/TurboModule.cpp @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TurboModule.h" + +using namespace facebook; + +namespace facebook { +namespace react { + +TurboModule::TurboModule( + const std::string &name, + std::shared_ptr jsInvoker) + : name_(name), jsInvoker_(jsInvoker) {} + +TurboModule::~TurboModule() {} + +jsi::Value TurboModule::get( + jsi::Runtime &runtime, + const jsi::PropNameID &propName) { + std::string propNameUtf8 = propName.utf8(runtime); + auto p = methodMap_.find(propNameUtf8); + if (p == methodMap_.end()) { + // Method was not found, let JS decide what to do. + return jsi::Value::undefined(); + } + MethodMetadata meta = p->second; + return jsi::Function::createFromHostFunction( + runtime, + propName, + meta.argCount, + [this, meta]( + facebook::jsi::Runtime &rt, + const facebook::jsi::Value &thisVal, + const facebook::jsi::Value *args, + size_t count) { return meta.invoker(rt, *this, args, count); }); +} + +} // namespace react +} // namespace facebook diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/TurboModule.h b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/TurboModule.h new file mode 100644 index 00000000000000..a1d85a9154a094 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/cpp/TurboModule.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +/** + * For now, support the same set of return types as existing impl. + * This can be improved to support richer typed objects. + */ +enum TurboModuleMethodValueKind { + VoidKind, + BooleanKind, + NumberKind, + StringKind, + ObjectKind, + ArrayKind, + FunctionKind, + PromiseKind, +}; + +/** + * Base HostObject class for every module to be exposed to JS + */ +class JSI_EXPORT TurboModule : public facebook::jsi::HostObject { + public: + TurboModule(const std::string &name, std::shared_ptr jsInvoker); + virtual ~TurboModule(); + + facebook::jsi::Value get( + facebook::jsi::Runtime &runtime, + const facebook::jsi::PropNameID &propName) override; + + const std::string name_; + std::shared_ptr jsInvoker_; + + protected: + struct MethodMetadata { + size_t argCount; + facebook::jsi::Value (*invoker)( + facebook::jsi::Runtime &rt, + TurboModule &turboModule, + const facebook::jsi::Value *args, + size_t count); + }; + + std::unordered_map methodMap_; +}; + +/** + * An app/platform-specific provider function to get an instance of a module + * given a name. + */ +using TurboModuleProviderFunctionType = + std::function(const std::string &name)>; + +} // namespace react +} // namespace facebook diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/facebook/react/uimanager/UIManagerReanimatedHelper.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/facebook/react/uimanager/UIManagerReanimatedHelper.java new file mode 100644 index 00000000000000..30b61374ee40f6 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/facebook/react/uimanager/UIManagerReanimatedHelper.java @@ -0,0 +1,15 @@ +package abi49_0_0.com.facebook.react.uimanager; + +/** + * This class provides a way to workaround limited visibility of + * UIViewOperationQueue#getUIViewOperationQueue. We rely on accessing that method to check if + * operation queue is empty or not. This in turn indicates if we are in a middle of processing batch + * of operations from JS. In such a case we can rely on the enqueued update operations to be flushed + * onto the shadow view hierarchy. Otherwise we want to trigger "dispatchViewUpdates" and enforce + * flush immediately. + */ +public class UIManagerReanimatedHelper { + public static boolean isOperationQueueEmpty(UIImplementation uiImplementation) { + return uiImplementation.getUIViewOperationQueue().isEmpty(); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/common/GestureHandlerStateManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/common/GestureHandlerStateManager.java new file mode 100644 index 00000000000000..676e378aa0ba9b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/common/GestureHandlerStateManager.java @@ -0,0 +1,5 @@ +package abi49_0_0.com.swmansion.common; + +public interface GestureHandlerStateManager { + void setGestureHandlerState(int handlerTag, int newState); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/CopiedEvent.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/CopiedEvent.java new file mode 100644 index 00000000000000..89dd7a09acc5ef --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/CopiedEvent.java @@ -0,0 +1,43 @@ +package abi49_0_0.com.swmansion.reanimated; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.WritableArray; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.uimanager.events.Event; +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter; + +public class CopiedEvent { + private int targetTag; + private String eventName; + private WritableMap payload; + + CopiedEvent(Event event) { + event.dispatch( + new RCTEventEmitter() { + @Override + public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event) { + CopiedEvent.this.targetTag = targetTag; + CopiedEvent.this.eventName = eventName; + CopiedEvent.this.payload = event.copy(); + } + + @Override + public void receiveTouches( + String eventName, WritableArray touches, WritableArray changedIndices) { + // noop + } + }); + } + + public int getTargetTag() { + return targetTag; + } + + public String getEventName() { + return eventName; + } + + public WritableMap getPayload() { + return payload; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/MapUtils.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/MapUtils.java new file mode 100644 index 00000000000000..7cc287a3bfc6bc --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/MapUtils.java @@ -0,0 +1,26 @@ +package abi49_0_0.com.swmansion.reanimated; + +import abi49_0_0.com.facebook.react.bridge.JSApplicationCausedNativeException; +import abi49_0_0.com.facebook.react.bridge.NoSuchKeyException; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class MapUtils { + public static int getInt(ReadableMap map, @Nonnull String name, String errorMsg) { + try { + return map.getInt(name); + } catch (NoSuchKeyException e) { + throw new JSApplicationCausedNativeException(errorMsg); + } + } + + @Nullable + public static String getString(ReadableMap map, @Nonnull String name, String errorMsg) { + try { + return map.getString(name); + } catch (NoSuchKeyException e) { + throw new JSApplicationCausedNativeException(errorMsg); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/NativeMethodsHelper.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/NativeMethodsHelper.java new file mode 100644 index 00000000000000..1bf00bab631422 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/NativeMethodsHelper.java @@ -0,0 +1,112 @@ +package abi49_0_0.com.swmansion.reanimated; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.util.Log; +import android.view.View; +import android.view.ViewParent; +import abi49_0_0.com.facebook.react.uimanager.PixelUtil; +import abi49_0_0.com.facebook.react.uimanager.RootViewUtil; +import abi49_0_0.com.facebook.react.views.scroll.ReactHorizontalScrollView; +import abi49_0_0.com.facebook.react.views.scroll.ReactScrollView; +import abi49_0_0.com.facebook.react.views.swiperefresh.ReactSwipeRefreshLayout; + +public class NativeMethodsHelper { + + public static float[] measure(View view) { + View rootView = (View) RootViewUtil.getRootView(view); + if (rootView == null || view == null) { + float result[] = new float[6]; + result[0] = -1234567; + return result; + } + + int buffer[] = new int[4]; + computeBoundingBox(rootView, buffer); + int rootX = buffer[0]; + int rootY = buffer[1]; + computeBoundingBox(view, buffer); + buffer[0] -= rootX; + buffer[1] -= rootY; + + float result[] = new float[6]; + result[0] = result[1] = 0; + for (int i = 2; i < 6; ++i) result[i] = PixelUtil.toDIPFromPixel(buffer[i - 2]); + + return result; + } + + public static void scrollTo(View view, double argX, double argY, boolean animated) { + int x = Math.round(PixelUtil.toPixelFromDIP(argX)); + int y = Math.round(PixelUtil.toPixelFromDIP(argY)); + boolean isHorizontal = view instanceof ReactHorizontalScrollView; + + if (!isHorizontal) { + if (view instanceof ReactSwipeRefreshLayout) { + view = findScrollView((ReactSwipeRefreshLayout) view); + } + if (!(view instanceof ReactScrollView)) { + Log.w( + "REANIMATED", + "NativeMethodsHelper: Unhandled scroll view type - allowed only {ReactScrollView, ReactHorizontalScrollView}"); + return; + } + } + + if (animated) { + final View finalView = view; + if (isHorizontal) { + view.post(() -> ((ReactHorizontalScrollView) finalView).smoothScrollTo(x, y)); + } else { + view.post(() -> ((ReactScrollView) finalView).smoothScrollTo(x, y)); + } + } else { + view.scrollTo(x, y); + } + } + + private static ReactScrollView findScrollView(ReactSwipeRefreshLayout view) { + for (int i = 0; i < view.getChildCount(); i++) { + if (view.getChildAt(i) instanceof ReactScrollView) { + return (ReactScrollView) view.getChildAt(i); + } + } + return null; + } + + private static void computeBoundingBox(View view, int[] outputBuffer) { + RectF boundingBox = new RectF(); + boundingBox.set(0, 0, view.getWidth(), view.getHeight()); + mapRectFromViewToWindowCoords(view, boundingBox); + + outputBuffer[0] = Math.round(boundingBox.left); + outputBuffer[1] = Math.round(boundingBox.top); + outputBuffer[2] = Math.round(boundingBox.right - boundingBox.left); + outputBuffer[3] = Math.round(boundingBox.bottom - boundingBox.top); + } + + private static void mapRectFromViewToWindowCoords(View view, RectF rect) { + Matrix matrix = view.getMatrix(); + if (!matrix.isIdentity()) { + matrix.mapRect(rect); + } + + rect.offset(view.getLeft(), view.getTop()); + + ViewParent parent = view.getParent(); + while (parent instanceof View) { + View parentView = (View) parent; + + rect.offset(-parentView.getScrollX(), -parentView.getScrollY()); + + matrix = parentView.getMatrix(); + if (!matrix.isIdentity()) { + matrix.mapRect(rect); + } + + rect.offset(parentView.getLeft(), parentView.getTop()); + + parent = parentView.getParent(); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/NodesManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/NodesManager.java new file mode 100644 index 00000000000000..4fbb13f15ecb1f --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/NodesManager.java @@ -0,0 +1,455 @@ +package abi49_0_0.com.swmansion.reanimated; + +import static java.lang.Float.NaN; + +import android.view.View; +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.GuardedRunnable; +import abi49_0_0.com.facebook.react.bridge.JavaOnlyMap; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableType; +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil; +import abi49_0_0.com.facebook.react.bridge.WritableArray; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.modules.core.DeviceEventManagerModule; +import abi49_0_0.com.facebook.react.modules.core.ReactChoreographer; +import abi49_0_0.com.facebook.react.uimanager.GuardedFrameCallback; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.ReactShadowNode; +import abi49_0_0.com.facebook.react.uimanager.ReactStylesDiffMap; +import abi49_0_0.com.facebook.react.uimanager.UIImplementation; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.UIManagerReanimatedHelper; +import abi49_0_0.com.facebook.react.uimanager.events.Event; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcherListener; +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.AnimationsManager; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Nullable; + +public class NodesManager implements EventDispatcherListener { + + public void scrollTo(int viewTag, double x, double y, boolean animated) { + View view; + try { + view = mUIManager.resolveView(viewTag); + } catch (IllegalViewOperationException e) { + e.printStackTrace(); + return; + } + NativeMethodsHelper.scrollTo(view, x, y, animated); + } + + public float[] measure(int viewTag) { + View view; + try { + view = mUIManager.resolveView(viewTag); + } catch (IllegalViewOperationException e) { + e.printStackTrace(); + return (new float[] {NaN, NaN, NaN, NaN, NaN, NaN}); + } + return NativeMethodsHelper.measure(view); + } + + public interface OnAnimationFrame { + void onAnimationFrame(double timestampMs); + } + + private AnimationsManager mAnimationManager; + private final UIImplementation mUIImplementation; + private final DeviceEventManagerModule.RCTDeviceEventEmitter mEventEmitter; + private final ReactChoreographer mReactChoreographer; + private final GuardedFrameCallback mChoreographerCallback; + protected final UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver; + private final AtomicBoolean mCallbackPosted = new AtomicBoolean(); + private final ReactContext mContext; + private final UIManagerModule mUIManager; + private ReactApplicationContext mReactApplicationContext; + private RCTEventEmitter mCustomEventHandler; + private List mFrameCallbacks = new ArrayList<>(); + private ConcurrentLinkedQueue mEventQueue = new ConcurrentLinkedQueue<>(); + public double currentFrameTimeMs; + public Set uiProps = Collections.emptySet(); + public Set nativeProps = Collections.emptySet(); + private ReaCompatibility compatibility; + + public NativeProxy getNativeProxy() { + return mNativeProxy; + } + + private NativeProxy mNativeProxy; + + public AnimationsManager getAnimationsManager() { + return mAnimationManager; + } + + public void onCatalystInstanceDestroy() { + if (mAnimationManager != null) { + mAnimationManager.onCatalystInstanceDestroy(); + } + + if (mNativeProxy != null) { + mNativeProxy.onCatalystInstanceDestroy(); + mNativeProxy = null; + } + } + + public void initWithContext(ReactApplicationContext reactApplicationContext) { + mReactApplicationContext = reactApplicationContext; + mNativeProxy = new NativeProxy(reactApplicationContext); + mAnimationManager.setScheduler(getNativeProxy().getScheduler()); + compatibility = new ReaCompatibility(reactApplicationContext); + compatibility.registerFabricEventListener(this); + } + + private final class NativeUpdateOperation { + public int mViewTag; + public WritableMap mNativeProps; + + public NativeUpdateOperation(int viewTag, WritableMap nativeProps) { + mViewTag = viewTag; + mNativeProps = nativeProps; + } + } + + private Queue mOperationsInBatch = new LinkedList<>(); + private boolean mTryRunBatchUpdatesSynchronously = false; + + public NodesManager(ReactContext context) { + mContext = context; + mUIManager = context.getNativeModule(UIManagerModule.class); + mUIImplementation = mUIManager.getUIImplementation(); + mCustomEventNamesResolver = mUIManager.getDirectEventNamesResolver(); + mEventEmitter = context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class); + + mReactChoreographer = ReactChoreographer.getInstance(); + mChoreographerCallback = + new GuardedFrameCallback(context) { + @Override + protected void doFrameGuarded(long frameTimeNanos) { + onAnimationFrame(frameTimeNanos); + } + }; + + // We register as event listener at the end, because we pass `this` and we haven't finished + // contructing an object yet. + // This lead to a crash described in + // https://github.com/software-mansion/react-native-reanimated/issues/604 which was caused by + // Nodes Manager being constructed on UI thread and registering for events. + // Events are handled in the native modules thread in the `onEventDispatch()` method. + // This method indirectly uses `mChoreographerCallback` which was created after event + // registration, creating race condition + mUIManager.getEventDispatcher().addListener(this); + + mAnimationManager = new AnimationsManager(mContext, mUIManager); + } + + public void onHostPause() { + if (mCallbackPosted.get()) { + stopUpdatingOnAnimationFrame(); + mCallbackPosted.set(true); + } + } + + public boolean isAnimationRunning() { + return mCallbackPosted.get(); + } + + public void onHostResume() { + if (mCallbackPosted.getAndSet(false)) { + startUpdatingOnAnimationFrame(); + } + } + + public void startUpdatingOnAnimationFrame() { + if (!mCallbackPosted.getAndSet(true)) { + mReactChoreographer.postFrameCallback( + ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, mChoreographerCallback); + } + } + + private void stopUpdatingOnAnimationFrame() { + if (mCallbackPosted.getAndSet(false)) { + mReactChoreographer.removeFrameCallback( + ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, mChoreographerCallback); + } + } + + public void performOperations() { + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + mNativeProxy.performOperations(); + } else if (!mOperationsInBatch.isEmpty()) { + final Queue copiedOperationsQueue = mOperationsInBatch; + mOperationsInBatch = new LinkedList<>(); + final boolean trySynchronously = mTryRunBatchUpdatesSynchronously; + mTryRunBatchUpdatesSynchronously = false; + final Semaphore semaphore = new Semaphore(0); + mContext.runOnNativeModulesQueueThread( + new GuardedRunnable(mContext.getExceptionHandler()) { + @Override + public void runGuarded() { + boolean queueWasEmpty = + UIManagerReanimatedHelper.isOperationQueueEmpty(mUIImplementation); + boolean shouldDispatchUpdates = trySynchronously && queueWasEmpty; + if (!shouldDispatchUpdates) { + semaphore.release(); + } + while (!copiedOperationsQueue.isEmpty()) { + NativeUpdateOperation op = copiedOperationsQueue.remove(); + ReactShadowNode shadowNode = mUIImplementation.resolveShadowNode(op.mViewTag); + if (shadowNode != null) { + mUIManager.updateView(op.mViewTag, shadowNode.getViewClass(), op.mNativeProps); + } + } + if (queueWasEmpty) { + mUIImplementation.dispatchViewUpdates(-1); // no associated batchId + } + if (shouldDispatchUpdates) { + semaphore.release(); + } + } + }); + if (trySynchronously) { + try { + semaphore.tryAcquire(16, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // if the thread is interruped we just continue and let the layout update happen + // asynchronously + } + } + } + } + + private void onAnimationFrame(long frameTimeNanos) { + currentFrameTimeMs = frameTimeNanos / 1000000.; + + while (!mEventQueue.isEmpty()) { + CopiedEvent copiedEvent = mEventQueue.poll(); + handleEvent(copiedEvent.getTargetTag(), copiedEvent.getEventName(), copiedEvent.getPayload()); + } + + if (!mFrameCallbacks.isEmpty()) { + List frameCallbacks = mFrameCallbacks; + mFrameCallbacks = new ArrayList<>(frameCallbacks.size()); + for (int i = 0, size = frameCallbacks.size(); i < size; i++) { + frameCallbacks.get(i).onAnimationFrame(currentFrameTimeMs); + } + } + + performOperations(); + + mCallbackPosted.set(false); + + if (!mFrameCallbacks.isEmpty() || !mEventQueue.isEmpty()) { + // enqueue next frame + startUpdatingOnAnimationFrame(); + } + } + + public void enqueueUpdateViewOnNativeThread( + int viewTag, WritableMap nativeProps, boolean trySynchronously) { + if (trySynchronously) { + mTryRunBatchUpdatesSynchronously = true; + } + mOperationsInBatch.add(new NativeUpdateOperation(viewTag, nativeProps)); + } + + public void configureProps(Set uiPropsSet, Set nativePropsSet) { + uiProps = uiPropsSet; + nativeProps = nativePropsSet; + } + + public void postOnAnimation(OnAnimationFrame onAnimationFrame) { + mFrameCallbacks.add(onAnimationFrame); + startUpdatingOnAnimationFrame(); + } + + @Override + public void onEventDispatch(Event event) { + // Events can be dispatched from any thread so we have to make sure handleEvent is run from the + // UI thread. + if (UiThreadUtil.isOnUiThread()) { + handleEvent(event); + performOperations(); + } else { + boolean shouldSaveEvent = false; + String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName()); + int viewTag = event.getViewTag(); + String key = viewTag + eventName; + + shouldSaveEvent |= + (mCustomEventHandler != null + && mNativeProxy != null + && mNativeProxy.isAnyHandlerWaitingForEvent(key)); + if (shouldSaveEvent) { + mEventQueue.offer(new CopiedEvent(event)); + } + startUpdatingOnAnimationFrame(); + } + } + + private void handleEvent(Event event) { + // If the event has a different name in native, convert it to it's JS name. + String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName()); + int viewTag = event.getViewTag(); + if (mCustomEventHandler != null) { + event.dispatch(mCustomEventHandler); + } + } + + private void handleEvent(int targetTag, String eventName, @Nullable WritableMap event) { + if (mCustomEventHandler != null) { + mCustomEventHandler.receiveEvent(targetTag, eventName, event); + } + } + + public UIManagerModule.CustomEventNamesResolver getEventNameResolver() { + return mCustomEventNamesResolver; + } + + public void registerEventHandler(RCTEventEmitter handler) { + mCustomEventHandler = handler; + } + + public void sendEvent(String name, WritableMap body) { + mEventEmitter.emit(name, body); + } + + public void updateProps(int viewTag, Map props) { + // TODO: update PropsNode to use this method instead of its own way of updating props + boolean hasUIProps = false; + boolean hasNativeProps = false; + boolean hasJSProps = false; + JavaOnlyMap newUIProps = new JavaOnlyMap(); + WritableMap newJSProps = Arguments.createMap(); + WritableMap newNativeProps = Arguments.createMap(); + + for (Map.Entry entry : props.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (uiProps.contains(key)) { + hasUIProps = true; + addProp(newUIProps, key, value); + } else if (nativeProps.contains(key)) { + hasNativeProps = true; + addProp(newNativeProps, key, value); + } else { + hasJSProps = true; + addProp(newJSProps, key, value); + } + } + + if (viewTag != View.NO_ID) { + if (hasUIProps) { + mUIImplementation.synchronouslyUpdateViewOnUIThread( + viewTag, new ReactStylesDiffMap(newUIProps)); + } + if (hasNativeProps) { + enqueueUpdateViewOnNativeThread(viewTag, newNativeProps, true); + } + if (hasJSProps) { + WritableMap evt = Arguments.createMap(); + evt.putInt("viewTag", viewTag); + evt.putMap("props", newJSProps); + sendEvent("onReanimatedPropsChange", evt); + } + } + } + + public void synchronouslyUpdateUIProps(int viewTag, ReadableMap uiProps) { + compatibility.synchronouslyUpdateUIProps(viewTag, uiProps); + } + + public String obtainProp(int viewTag, String propName) { + View view = mUIManager.resolveView(viewTag); + String result = + "error: unknown propName " + propName + ", currently supported: opacity, zIndex"; + if (propName.equals("opacity")) { + Float opacity = view.getAlpha(); + result = Float.toString(opacity); + } else if (propName.equals("zIndex")) { + Float zIndex = view.getElevation(); + result = Float.toString(zIndex); + } + return result; + } + + private static WritableMap copyReadableMap(ReadableMap map) { + WritableMap copy = Arguments.createMap(); + copy.merge(map); + return copy; + } + + private static WritableArray copyReadableArray(ReadableArray array) { + WritableArray copy = Arguments.createArray(); + for (int i = 0; i < array.size(); i++) { + ReadableType type = array.getType(i); + switch (type) { + case Boolean: + copy.pushBoolean(array.getBoolean(i)); + break; + case String: + copy.pushString(array.getString(i)); + break; + case Null: + copy.pushNull(); + break; + case Number: + copy.pushDouble(array.getDouble(i)); + break; + case Map: + copy.pushMap(copyReadableMap(array.getMap(i))); + break; + case Array: + copy.pushArray(copyReadableArray(array.getArray(i))); + break; + default: + throw new IllegalStateException("Unknown type of ReadableArray"); + } + } + return copy; + } + + private static void addProp(WritableMap propMap, String key, Object value) { + if (value == null) { + propMap.putNull(key); + } else if (value instanceof Double) { + propMap.putDouble(key, (Double) value); + } else if (value instanceof Integer) { + propMap.putInt(key, (Integer) value); + } else if (value instanceof Number) { + propMap.putDouble(key, ((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + propMap.putBoolean(key, (Boolean) value); + } else if (value instanceof String) { + propMap.putString(key, (String) value); + } else if (value instanceof ReadableArray) { + if (!(value instanceof WritableArray)) { + propMap.putArray(key, copyReadableArray((ReadableArray) value)); + } else { + propMap.putArray(key, (ReadableArray) value); + } + } else if (value instanceof ReadableMap) { + if (!(value instanceof WritableMap)) { + propMap.putMap(key, copyReadableMap((ReadableMap) value)); + } else { + propMap.putMap(key, (ReadableMap) value); + } + } else { + throw new IllegalStateException("Unknown type of animated value"); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedMessageQueueThreadBase.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedMessageQueueThreadBase.java new file mode 100644 index 00000000000000..01b77fd4f54b56 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedMessageQueueThreadBase.java @@ -0,0 +1,72 @@ +package abi49_0_0.com.swmansion.reanimated; + +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.queue.MessageQueueThread; +import abi49_0_0.com.facebook.react.bridge.queue.MessageQueueThreadImpl; +import abi49_0_0.com.facebook.react.bridge.queue.MessageQueueThreadPerfStats; +import abi49_0_0.com.facebook.react.bridge.queue.MessageQueueThreadSpec; +import java.lang.reflect.Field; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +// This class is an almost exact copy of MessageQueueThreadImpl taken from here: +// https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java +// The only method that has changed is `quitSynchronous()` (see comment above +// function implementation for details). +@DoNotStrip +public abstract class ReanimatedMessageQueueThreadBase implements MessageQueueThread { + protected final MessageQueueThreadImpl messageQueueThread; + + public ReanimatedMessageQueueThreadBase() { + messageQueueThread = + MessageQueueThreadImpl.create( + MessageQueueThreadSpec.mainThreadSpec(), + exception -> { + throw new RuntimeException(exception); + }); + } + + @Override + public Future callOnQueue(Callable callable) { + return messageQueueThread.callOnQueue(callable); + } + + @Override + public boolean isOnThread() { + return messageQueueThread.isOnThread(); + } + + @Override + public void assertIsOnThread() { + messageQueueThread.assertIsOnThread(); + } + + @Override + public void assertIsOnThread(String s) { + messageQueueThread.assertIsOnThread(s); + } + + // We don't want to quit the main looper (which is what MessageQueueThreadImpl would have done), + // but we still want to prevent anything else from executing. + @Override + public void quitSynchronous() { + try { + Field mIsFinished = messageQueueThread.getClass().getDeclaredField("mIsFinished"); + mIsFinished.setAccessible(true); + mIsFinished.set(messageQueueThread, true); + mIsFinished.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public MessageQueueThreadPerfStats getPerfStats() { + return messageQueueThread.getPerfStats(); + } + + @Override + public void resetPerfStats() { + messageQueueThread.resetPerfStats(); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedModule.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedModule.java new file mode 100644 index 00000000000000..15404b2d0e284c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedModule.java @@ -0,0 +1,126 @@ +package abi49_0_0.com.swmansion.reanimated; + +import android.util.Log; +import abi49_0_0.com.facebook.react.bridge.LifecycleEventListener; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyManager; +import abi49_0_0.com.facebook.react.uimanager.UIBlock; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModuleListener; +import java.util.ArrayList; +import javax.annotation.Nullable; + +@ReactModule(name = ReanimatedModule.NAME) +public class ReanimatedModule extends ReactContextBaseJavaModule + implements LifecycleEventListener, UIManagerModuleListener { + + public static final String NAME = "ReanimatedModule"; + + private interface UIThreadOperation { + void execute(NodesManager nodesManager); + } + + private ArrayList mOperations = new ArrayList<>(); + private @Nullable NodesManager mNodesManager; + + public ReanimatedModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public void initialize() { + ReactApplicationContext reactCtx = getReactApplicationContext(); + UIManagerModule uiManager = reactCtx.getNativeModule(UIManagerModule.class); + reactCtx.addLifecycleEventListener(this); + uiManager.addUIManagerListener(this); + } + + @Override + public void onHostPause() { + if (mNodesManager != null) { + mNodesManager.onHostPause(); + } + } + + @Override + public void onHostResume() { + if (mNodesManager != null) { + mNodesManager.onHostResume(); + } + } + + @Override + public void onHostDestroy() { + // do nothing + } + + @Override + public void willDispatchViewUpdates(final UIManagerModule uiManager) { + if (mOperations.isEmpty()) { + return; + } + final ArrayList operations = mOperations; + mOperations = new ArrayList<>(); + uiManager.addUIBlock( + new UIBlock() { + @Override + public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { + NodesManager nodesManager = getNodesManager(); + for (UIThreadOperation operation : operations) { + operation.execute(nodesManager); + } + } + }); + } + + @Override + public String getName() { + return NAME; + } + + /*package*/ + public NodesManager getNodesManager() { + if (mNodesManager == null) { + mNodesManager = new NodesManager(getReactApplicationContext()); + } + + return mNodesManager; + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public void installTurboModule() { + // When debugging in chrome the JS context is not available. + // https://github.com/facebook/react-native/blob/v0.67.0-rc.6/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java#L25 + Utils.isChromeDebugger = getReactApplicationContext().getJavaScriptContextHolder().get() == 0; + + if (!Utils.isChromeDebugger) { + this.getNodesManager().initWithContext(getReactApplicationContext()); + } else { + Log.w( + "[REANIMATED]", + "Unable to create Reanimated Native Module. You can ignore this message if you are using Chrome Debugger now."); + } + } + + @ReactMethod + public void addListener(String eventName) { + // Keep: Required for RN built in Event Emitter Calls. + } + + @ReactMethod + public void removeListeners(Integer count) { + // Keep: Required for RN built in Event Emitter Calls. + } + + @Override + public void onCatalystInstanceDestroy() { + super.onCatalystInstanceDestroy(); + + if (mNodesManager != null) { + mNodesManager.onCatalystInstanceDestroy(); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedPackage.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedPackage.java new file mode 100644 index 00000000000000..4a7f18400237d2 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/ReanimatedPackage.java @@ -0,0 +1,97 @@ +package abi49_0_0.com.swmansion.reanimated; + +import static abi49_0_0.com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_END; +import static abi49_0_0.com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_START; + +import abi49_0_0.com.facebook.react.ReactApplication; +import abi49_0_0.com.facebook.react.ReactInstanceManager; +import abi49_0_0.com.facebook.react.ReactPackage; +import abi49_0_0.com.facebook.react.TurboReactPackage; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactMarker; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.facebook.react.module.model.ReactModuleInfo; +import abi49_0_0.com.facebook.react.module.model.ReactModuleInfoProvider; +import abi49_0_0.com.facebook.react.turbomodule.core.interfaces.TurboModule; +import abi49_0_0.com.facebook.react.uimanager.ReanimatedUIManager; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.facebook.systrace.Systrace; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ReanimatedPackage extends TurboReactPackage implements ReactPackage { + + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(ReanimatedModule.NAME)) { + return new ReanimatedModule(reactContext); + } + if (name.equals(ReanimatedUIManager.NAME)) { + return createUIManager(reactContext); + } + return null; + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + Class[] moduleList = + new Class[] { + ReanimatedModule.class, ReanimatedUIManager.class, + }; + + final Map reactModuleInfoMap = new HashMap<>(); + for (Class moduleClass : moduleList) { + ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); + + reactModuleInfoMap.put( + reactModule.name(), + new ReactModuleInfo( + reactModule.name(), + moduleClass.getName(), + true, + reactModule.needsEagerInit(), + reactModule.hasConstants(), + reactModule.isCxxModule(), + TurboModule.class.isAssignableFrom(moduleClass))); + } + + return new ReactModuleInfoProvider() { + @Override + public Map getReactModuleInfos() { + return reactModuleInfoMap; + } + }; + } + + private UIManagerModule createUIManager(final ReactApplicationContext reactContext) { + ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_START); + Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createUIManagerModule"); + final ReactInstanceManager reactInstanceManager = getReactInstanceManager(reactContext); + List viewManagers = reactInstanceManager.getOrCreateViewManagers(reactContext); + int minTimeLeftInFrameForNonBatchedOperationMs = -1; + try { + return ReanimatedUIManagerFactory.create( + reactContext, viewManagers, minTimeLeftInFrameForNonBatchedOperationMs); + } finally { + Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); + ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_END); + } + } + + /** + * Get the {@link ReactInstanceManager} used by this app. By default, assumes {@link + * ReactApplicationContext#getApplicationContext()} is an instance of {@link ReactApplication} and + * calls {@link ReactApplication#getReactNativeHost().getReactInstanceManager()}. Override this + * method if your application class does not implement {@code ReactApplication} or you simply have + * a different mechanism for storing a {@code ReactInstanceManager}, e.g. as a static field + * somewhere. + */ + public ReactInstanceManager getReactInstanceManager(ReactApplicationContext reactContext) { + return ((ReactApplication) reactContext.getApplicationContext()) + .getReactNativeHost() + .getReactInstanceManager(); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/Scheduler.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/Scheduler.java new file mode 100644 index 00000000000000..0e512d1055e02e --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/Scheduler.java @@ -0,0 +1,51 @@ +package abi49_0_0.com.swmansion.reanimated; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.GuardedRunnable; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil; +import java.util.concurrent.atomic.AtomicBoolean; + +public class Scheduler { + + @DoNotStrip + @SuppressWarnings("unused") + private final HybridData mHybridData; + + private final ReactApplicationContext mContext; + private final AtomicBoolean mActive = new AtomicBoolean(true); + + private final Runnable mUIThreadRunnable = + new Runnable() { + @Override + public void run() { + if (mActive.get()) { + triggerUI(); + } + } + }; + + public Scheduler(ReactApplicationContext context) { + mHybridData = initHybrid(); + mContext = context; + } + + private native HybridData initHybrid(); + + public native void triggerUI(); + + @DoNotStrip + private void scheduleOnUI() { + UiThreadUtil.runOnUiThread( + new GuardedRunnable(mContext.getExceptionHandler()) { + public void runGuarded() { + mUIThreadRunnable.run(); + } + }); + } + + public void deactivate() { + mActive.set(false); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/Utils.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/Utils.java new file mode 100644 index 00000000000000..811dec74872ae9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/Utils.java @@ -0,0 +1,38 @@ +package abi49_0_0.com.swmansion.reanimated; + +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableMapKeySetIterator; +import java.util.HashMap; +import java.util.Map; + +public class Utils { + + public static boolean isChromeDebugger = false; + + public static Map processMapping(ReadableMap style) { + ReadableMapKeySetIterator iter = style.keySetIterator(); + HashMap mapping = new HashMap<>(); + while (iter.hasNextKey()) { + String propKey = iter.nextKey(); + int nodeIndex = style.getInt(propKey); + mapping.put(propKey, nodeIndex); + } + return mapping; + } + + public static int[] processIntArray(ReadableArray ary) { + int size = ary.size(); + int[] res = new int[size]; + for (int i = 0; i < size; i++) { + res[i] = ary.getInt(i); + } + return res; + } + + public static String simplifyStringNumbersList(String list) { + // transforms string: '[1, 2, 3]' -> '1 2 3' + // to make usage of std::istringstream in C++ easier + return list.replace(",", "").replace("[", "").replace("]", ""); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/keyboardObserver/ReanimatedKeyboardEventListener.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/keyboardObserver/ReanimatedKeyboardEventListener.java new file mode 100644 index 00000000000000..ce0f52fcc5ef7c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/keyboardObserver/ReanimatedKeyboardEventListener.java @@ -0,0 +1,173 @@ +package abi49_0_0.com.swmansion.reanimated.keyboardObserver; + +import android.os.Handler; +import android.os.Looper; +import android.view.View; +import android.widget.FrameLayout; +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsAnimationCompat; +import androidx.core.view.WindowInsetsCompat; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.uimanager.PixelUtil; +import abi49_0_0.com.swmansion.reanimated.BuildConfig; +import abi49_0_0.com.swmansion.reanimated.nativeProxy.KeyboardEventDataUpdater; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; + +public class ReanimatedKeyboardEventListener { + enum KeyboardState { + UNKNOWN(0), + OPENING(1), + OPEN(2), + CLOSING(3), + CLOSED(4); + + private final int value; + + KeyboardState(int value) { + this.value = value; + } + + public int asInt() { + return value; + } + } + + private final WeakReference reactContext; + private int nextListenerId = 0; + private KeyboardState state; + private final HashMap listeners = new HashMap<>(); + private boolean isStatusBarTranslucent = false; + + public ReanimatedKeyboardEventListener(WeakReference reactContext) { + this.reactContext = reactContext; + } + + private View getRootView() { + return reactContext.get().getCurrentActivity().getWindow().getDecorView(); + } + + private void setupWindowInsets() { + View rootView = getRootView(); + WindowCompat.setDecorFitsSystemWindows( + reactContext.get().getCurrentActivity().getWindow(), false); + ViewCompat.setOnApplyWindowInsetsListener( + rootView, + (v, insets) -> { + int paddingBottom = 0; + if (!BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + && BuildConfig.REACT_NATIVE_MINOR_VERSION < 70) { + paddingBottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; + } + int paddingTop = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top; + View content = + rootView.getRootView().findViewById(abi49_0_0.com.swmansion.reanimated.R.id.action_bar_root); + + FrameLayout.LayoutParams params = + new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + if (isStatusBarTranslucent) { + params.setMargins(0, 0, 0, 0); + } else { + params.setMargins(0, paddingTop, 0, paddingBottom); + } + content.setLayoutParams(params); + return insets; + }); + } + + private void updateKeyboard(int keyboardHeight) { + for (KeyboardEventDataUpdater listener : listeners.values()) { + listener.keyboardEventDataUpdater(state.asInt(), keyboardHeight); + } + } + + private class WindowInsetsCallback extends WindowInsetsAnimationCompat.Callback { + private int keyboardHeight = 0; + + public WindowInsetsCallback() { + super(WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE); + } + + @NonNull + @Override + public WindowInsetsAnimationCompat.BoundsCompat onStart( + @NonNull WindowInsetsAnimationCompat animation, + @NonNull WindowInsetsAnimationCompat.BoundsCompat bounds) { + state = keyboardHeight == 0 ? KeyboardState.OPENING : KeyboardState.CLOSING; + updateKeyboard(keyboardHeight); + return super.onStart(animation, bounds); + } + + @NonNull + @Override + public WindowInsetsCompat onProgress( + @NonNull WindowInsetsCompat insets, + @NonNull List runningAnimations) { + + keyboardHeight = + (int) + PixelUtil.toDIPFromPixel( + Math.max( + 0, + insets.getInsets(WindowInsetsCompat.Type.ime()).bottom + - insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom)); + updateKeyboard(keyboardHeight); + return insets; + } + + @Override + public void onEnd(@NonNull WindowInsetsAnimationCompat animation) { + state = keyboardHeight == 0 ? KeyboardState.CLOSED : KeyboardState.OPEN; + updateKeyboard(keyboardHeight); + } + } + + private void setUpCallbacks() { + View rootView = getRootView(); + new Handler(Looper.getMainLooper()).post(this::setupWindowInsets); + ViewCompat.setWindowInsetsAnimationCallback(rootView, new WindowInsetsCallback()); + } + + public int subscribeForKeyboardEvents( + KeyboardEventDataUpdater updater, boolean isStatusBarTranslucent) { + int listenerId = nextListenerId++; + if (listeners.isEmpty()) { + this.isStatusBarTranslucent = isStatusBarTranslucent; + setUpCallbacks(); + } + listeners.put(listenerId, updater); + return listenerId; + } + + private void bringBackWindowInsets() { + WindowCompat.setDecorFitsSystemWindows( + reactContext.get().getCurrentActivity().getWindow(), !isStatusBarTranslucent); + ViewCompat.setOnApplyWindowInsetsListener(getRootView(), null); + ViewCompat.setWindowInsetsAnimationCallback(getRootView(), null); + View content = + getRootView().getRootView().findViewById(abi49_0_0.com.swmansion.reanimated.R.id.action_bar_root); + + FrameLayout.LayoutParams params = + new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + params.setMargins(0, 0, 0, 0); + content.setLayoutParams(params); + } + + private void removeCallbacks() { + View rootView = getRootView(); + new Handler(Looper.getMainLooper()).post(this::bringBackWindowInsets); + ViewCompat.setWindowInsetsAnimationCallback(rootView, null); + } + + public void unsubscribeFromKeyboardEvents(int listenerId) { + listeners.remove(listenerId); + if (listeners.isEmpty()) { + removeCallbacks(); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java new file mode 100644 index 00000000000000..f803248a92f41e --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java @@ -0,0 +1,695 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.app.Activity; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import abi49_0_0.com.facebook.react.bridge.JavaOnlyMap; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableNativeArray; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.uimanager.IViewManagerWithChildren; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.PixelUtil; +import abi49_0_0.com.facebook.react.uimanager.ReactStylesDiffMap; +import abi49_0_0.com.facebook.react.uimanager.RootView; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.swmansion.reanimated.Scheduler; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import javax.annotation.Nullable; + +public class AnimationsManager implements ViewHierarchyObserver { + private WeakReference mScheduler; + private ReactContext mContext; + private UIManagerModule mUIManager; + private NativeMethodsHolder mNativeMethodsHolder; + + private HashSet mEnteringViews = new HashSet<>(); + private HashMap mEnteringViewTargetValues = new HashMap<>(); + private HashMap mExitingViews = new HashMap<>(); + private HashMap mExitingSubviewCountMap = new HashMap<>(); + private HashSet mAncestorsToRemove = new HashSet<>(); + private HashMap mCallbacks = new HashMap<>(); + private ReanimatedNativeHierarchyManager mReanimatedNativeHierarchyManager; + private boolean isCatalystInstanceDestroyed; + private SharedTransitionManager mSharedTransitionManager; + + public void setReanimatedNativeHierarchyManager( + ReanimatedNativeHierarchyManager reanimatedNativeHierarchyManager) { + this.mReanimatedNativeHierarchyManager = reanimatedNativeHierarchyManager; + } + + public ReanimatedNativeHierarchyManager getReanimatedNativeHierarchyManager() { + return mReanimatedNativeHierarchyManager; + } + + public void setScheduler(Scheduler scheduler) { + mScheduler = new WeakReference<>(scheduler); + } + + public AnimationsManager(ReactContext context, UIManagerModule uiManagerModule) { + mContext = context; + mUIManager = uiManagerModule; + isCatalystInstanceDestroyed = false; + mSharedTransitionManager = new SharedTransitionManager(this); + } + + public void onCatalystInstanceDestroy() { + isCatalystInstanceDestroyed = true; + mNativeMethodsHolder = null; + mContext = null; + mUIManager = null; + mExitingViews = null; + mExitingSubviewCountMap = null; + mAncestorsToRemove = null; + mCallbacks = null; + } + + @Override + public void onViewRemoval(View view, ViewGroup parent, Runnable callback) { + if (isCatalystInstanceDestroyed) { + return; + } + Integer tag = view.getId(); + mCallbacks.put(tag, callback); + + if (!removeOrAnimateExitRecursive(view, true)) { + removeView(view, parent); + } + } + + @Override + public void onViewCreate(View view, ViewGroup parent, Snapshot after) { + if (isCatalystInstanceDestroyed) { + return; + } + maybeRegisterSharedView(view); + + if (!hasAnimationForTag(view.getId(), LayoutAnimations.Types.ENTERING)) { + return; + } + + Scheduler strongScheduler = mScheduler.get(); + if (strongScheduler != null) { + strongScheduler.triggerUI(); + } + int tag = view.getId(); + HashMap targetValues = after.toTargetMap(); + + if (targetValues != null) { + HashMap preparedValues = prepareDataForAnimationWorklet(targetValues, true); + mNativeMethodsHolder.startAnimation(tag, LayoutAnimations.Types.ENTERING, preparedValues); + mEnteringViews.add(tag); + } + } + + @Override + public void onViewUpdate(View view, Snapshot before, Snapshot after) { + if (isCatalystInstanceDestroyed) { + return; + } + int tag = view.getId(); + + if (!hasAnimationForTag(tag, LayoutAnimations.Types.LAYOUT)) { + if (mEnteringViews.contains(tag)) { + // store values to restore after `entering` finishes + mEnteringViewTargetValues.put( + tag, + new Rect( + after.originX, + after.originY, + after.originX + after.width, + after.originY + after.height)); + // restore layout before the update, so the `entering` + // can continue from its current location + view.layout( + before.originX, + before.originY, + before.originX + before.width, + before.originY + before.height); + } + return; + } + + HashMap startValues = before.toCurrentMap(); + HashMap targetValues = after.toTargetMap(); + + // If startValues are equal to targetValues it means that there was no UI Operation changing + // layout of the View. So dirtiness of that View is false positive + boolean doNotStartLayout = true; + for (int i = 0; i < Snapshot.targetKeysToTransform.size(); ++i) { + double startV = + ((Number) startValues.get(Snapshot.currentKeysToTransform.get(i))).doubleValue(); + double targetV = + ((Number) targetValues.get(Snapshot.targetKeysToTransform.get(i))).doubleValue(); + if (startV != targetV) { + doNotStartLayout = false; + } + } + if (doNotStartLayout) { + return; + } + + // View must be in Layout state + HashMap preparedStartValues = + prepareDataForAnimationWorklet(startValues, false); + HashMap preparedTargetValues = + prepareDataForAnimationWorklet(targetValues, true); + HashMap preparedValues = new HashMap<>(preparedTargetValues); + for (String key : preparedStartValues.keySet()) { + preparedValues.put(key, preparedStartValues.get(key)); + } + mNativeMethodsHolder.startAnimation(tag, LayoutAnimations.Types.LAYOUT, preparedValues); + } + + public void maybeRegisterSharedView(View view) { + if (hasAnimationForTag(view.getId(), LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION)) { + mSharedTransitionManager.notifyAboutNewView(view); + } + } + + public void progressLayoutAnimation( + int tag, Map newStyle, boolean isSharedTransition) { + View view = resolveView(tag); + + if (view == null) { + return; + } + + ViewGroup parent = (ViewGroup) view.getParent(); + + if (parent == null) { + return; + } + + ViewManager viewManager = resolveViewManager(tag); + ViewManager parentViewManager = resolveViewManager(parent.getId()); + + if (viewManager == null) { + return; + } + + setNewProps(newStyle, view, viewManager, parentViewManager, parent.getId(), isSharedTransition); + } + + public void endLayoutAnimation(int tag, boolean cancelled, boolean removeView) { + View view = resolveView(tag); + + if (view == null) { + return; + } + + Rect target = mEnteringViewTargetValues.get(tag); + if (!removeView && mEnteringViews.contains(tag) && target != null) { + view.layout(target.left, target.top, target.right, target.bottom); + } + mEnteringViews.remove(tag); + mEnteringViewTargetValues.remove(tag); + + if (removeView) { + if (view instanceof ViewGroup && mAncestorsToRemove.contains(tag)) { + cancelAnimationsInSubviews((ViewGroup) view); + } + + mExitingViews.remove(tag); + maybeDropAncestors(view); + + ViewGroup parent = (ViewGroup) view.getParent(); + removeView(view, parent); + } + mSharedTransitionManager.finishSharedAnimation(tag); + } + + public void printSubTree(View view, int level) { + if (level == 0) { + Log.v("rea", "----------------------"); + } + if (view == null) { + return; + } + StringBuilder out = new StringBuilder(); + for (int i = 0; i < level; ++i) { + out.append("+"); + } + out.append(" TAG:"); + out.append(view.getId()); + out.append(" CLASS:"); + out.append(view.getClass().getSimpleName()); + Log.v("rea", out.toString()); + + if (view instanceof ViewGroup) { + for (int i = 0; i < ((ViewGroup) view).getChildCount(); ++i) { + printSubTree(((ViewGroup) view).getChildAt(i), level + 1); + } + } + } + + public HashMap prepareDataForAnimationWorklet( + HashMap values, boolean isTargetValues) { + return prepareDataForAnimationWorklet(values, isTargetValues, false); + } + + public HashMap prepareDataForAnimationWorklet( + HashMap values, boolean isTargetValues, boolean addTransform) { + HashMap preparedValues = new HashMap<>(); + ArrayList keys; + if (isTargetValues) { + keys = Snapshot.targetKeysToTransform; + } else { + keys = Snapshot.currentKeysToTransform; + } + for (String key : keys) { + preparedValues.put(key, PixelUtil.toDIPFromPixel((int) values.get(key))); + } + + if (addTransform) { + String key = + isTargetValues ? Snapshot.TARGET_TRANSFORM_MATRIX : Snapshot.CURRENT_TRANSFORM_MATRIX; + preparedValues.put(key, values.get(key)); + } + + DisplayMetrics displayMetrics = new DisplayMetrics(); + Activity currentActivity = mContext.getCurrentActivity(); + if (currentActivity != null) { + currentActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int height = displayMetrics.heightPixels; + int width = displayMetrics.widthPixels; + preparedValues.put("windowWidth", PixelUtil.toDIPFromPixel(width)); + preparedValues.put("windowHeight", PixelUtil.toDIPFromPixel(height)); + } else { + preparedValues.put("windowWidth", PixelUtil.toDIPFromPixel(0)); + preparedValues.put("windowHeight", PixelUtil.toDIPFromPixel(0)); + } + return preparedValues; + } + + public void setNativeMethods(NativeMethodsHolder nativeMethods) { + mNativeMethodsHolder = nativeMethods; + mSharedTransitionManager.setNativeMethods(nativeMethods); + } + + public void setNewProps( + Map props, + View view, + ViewManager viewManager, + ViewManager parentViewManager, + Integer parentTag, + boolean isPositionAbsolute) { + float x = + (props.get(Snapshot.ORIGIN_X) != null) + ? ((Double) props.get(Snapshot.ORIGIN_X)).floatValue() + : PixelUtil.toDIPFromPixel(view.getLeft()); + float y = + (props.get(Snapshot.ORIGIN_Y) != null) + ? ((Double) props.get(Snapshot.ORIGIN_Y)).floatValue() + : PixelUtil.toDIPFromPixel(view.getTop()); + float width = + (props.get(Snapshot.WIDTH) != null) + ? ((Double) props.get(Snapshot.WIDTH)).floatValue() + : PixelUtil.toDIPFromPixel(view.getWidth()); + float height = + (props.get(Snapshot.HEIGHT) != null) + ? ((Double) props.get(Snapshot.HEIGHT)).floatValue() + : PixelUtil.toDIPFromPixel(view.getHeight()); + + if (props.containsKey(Snapshot.TRANSFORM_MATRIX)) { + float[] matrixValues = new float[9]; + if (props.get(Snapshot.TRANSFORM_MATRIX) instanceof ReadableNativeArray) { + // this array comes from JavaScript + ReadableNativeArray matrixArray = + (ReadableNativeArray) props.get(Snapshot.TRANSFORM_MATRIX); + for (int i = 0; i < 9; i++) { + matrixValues[i] = ((Double) matrixArray.getDouble(i)).floatValue(); + } + } else { + // this array comes from Java + ArrayList casted = (ArrayList) props.get(Snapshot.TRANSFORM_MATRIX); + for (int i = 0; i < 9; i++) { + matrixValues[i] = casted.get(i); + } + } + view.setScaleX(matrixValues[0]); + view.setScaleY(matrixValues[4]); + // as far, let's support only scale and translation. Rotation maybe the future feature + // (http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf) + + props.remove(Snapshot.TRANSFORM_MATRIX); + } + + updateLayout( + view, parentViewManager, parentTag, view.getId(), x, y, width, height, isPositionAbsolute); + props.remove(Snapshot.ORIGIN_X); + props.remove(Snapshot.ORIGIN_Y); + props.remove(Snapshot.GLOBAL_ORIGIN_X); + props.remove(Snapshot.GLOBAL_ORIGIN_Y); + props.remove(Snapshot.WIDTH); + props.remove(Snapshot.HEIGHT); + + if (props.size() == 0) { + return; + } + + JavaOnlyMap javaOnlyMap = new JavaOnlyMap(); + for (String key : props.keySet()) { + addProp(javaOnlyMap, key, props.get(key)); + } + + viewManager.updateProperties(view, new ReactStylesDiffMap(javaOnlyMap)); + } + + private static void addProp(WritableMap propMap, String key, Object value) { + if (value == null) { + propMap.putNull(key); + } else if (value instanceof Double) { + propMap.putDouble(key, (Double) value); + } else if (value instanceof Integer) { + propMap.putInt(key, (Integer) value); + } else if (value instanceof Number) { + propMap.putDouble(key, ((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + propMap.putBoolean(key, (Boolean) value); + } else if (value instanceof String) { + propMap.putString(key, (String) value); + } else if (value instanceof ReadableArray) { + propMap.putArray(key, (ReadableArray) value); + } else if (value instanceof ReadableMap) { + propMap.putMap(key, (ReadableMap) value); + } else { + throw new IllegalStateException("Unknown type of animated value [Layout Animations]"); + } + } + + public void updateLayout( + View viewToUpdate, + ViewManager parentViewManager, + int parentTag, + int tag, + float xf, + float yf, + float widthf, + float heightf, + boolean isPositionAbsolute) { + + int x = Math.round(PixelUtil.toPixelFromDIP(xf)); + int y = Math.round(PixelUtil.toPixelFromDIP(yf)); + int width = Math.round(PixelUtil.toPixelFromDIP(widthf)); + int height = Math.round(PixelUtil.toPixelFromDIP(heightf)); + // Even though we have exact dimensions, we still call measure because some platform views + // (e.g. + // Switch) assume that method will always be called before onLayout and onDraw. They use it to + // calculate and cache information used in the draw pass. For most views, onMeasure can be + // stubbed out to only call setMeasuredDimensions. For ViewGroups, onLayout should be stubbed + // out to not recursively call layout on its children: React Native already handles doing + // that. + // + // Also, note measure and layout need to be called *after* all View properties have been + // updated + // because of caching and calculation that may occur in onMeasure and onLayout. Layout + // operations should also follow the native view hierarchy and go top to bottom for + // consistency + // with standard layout passes (some views may depend on this). + + viewToUpdate.measure( + View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); + + // We update the layout of the ReactRootView when there is a change in the layout of its + // child. + // This is required to re-measure the size of the native View container (usually a + // FrameLayout) that is configured with layout_height = WRAP_CONTENT or layout_width = + // WRAP_CONTENT + // + // This code is going to be executed ONLY when there is a change in the size of the Root + // View defined in the js side. Changes in the layout of inner views will not trigger an + // update + // on the layout of the Root View. + ViewParent parent = viewToUpdate.getParent(); + if (parent instanceof RootView) { + parent.requestLayout(); + } + + // Check if the parent of the view has to layout the view, or the child has to lay itself out. + if (parentTag % 10 == 1 && parentViewManager != null) { // parentTag % 10 == 1 - ParentIsARoot + IViewManagerWithChildren parentViewManagerWithChildren; + if (parentViewManager instanceof IViewManagerWithChildren) { + parentViewManagerWithChildren = (IViewManagerWithChildren) parentViewManager; + } else { + throw new IllegalViewOperationException( + "Trying to use view with tag " + + parentTag + + " as a parent, but its Manager doesn't implement IViewManagerWithChildren"); + } + if (!parentViewManagerWithChildren.needsCustomLayoutForChildren()) { + viewToUpdate.layout(x, y, x + width, y + height); + } + } else { + if (isPositionAbsolute) { + Point newPoint = new Point(x, y); + View viewToUpdateParent = (View) viewToUpdate.getParent(); + Point convertedPoint = convertScreenLocationToViewCoordinates(newPoint, viewToUpdateParent); + x = convertedPoint.x; + y = convertedPoint.y; + } + viewToUpdate.layout(x, y, x + width, y + height); + } + } + + public boolean hasAnimationForTag(int tag, int type) { + return mNativeMethodsHolder.hasAnimation(tag, type); + } + + public boolean isLayoutAnimationEnabled() { + return mNativeMethodsHolder != null && mNativeMethodsHolder.isLayoutAnimationEnabled(); + } + + private boolean removeOrAnimateExitRecursive(View view, boolean shouldRemove) { + int tag = view.getId(); + ViewManager viewManager = resolveViewManager(tag); + + if (viewManager != null && viewManager.getName().equals("RNSScreenStack")) { + cancelAnimationsRecursive(view); + return false; + } + + boolean hasExitAnimation = + hasAnimationForTag(tag, LayoutAnimations.Types.EXITING) || mExitingViews.containsKey(tag); + boolean hasAnimatedChildren = false; + shouldRemove = shouldRemove && !hasExitAnimation; + + if (hasAnimationForTag(tag, LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION)) { + mSharedTransitionManager.notifyAboutRemovedView(view); + mSharedTransitionManager.makeSnapshot(view); + } + + ArrayList toBeRemoved = new ArrayList<>(); + + // we might want to keep this view around + // because one of the (children's) children + // has an exiting animation + if (view instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) view; + for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) { + View child = viewGroup.getChildAt(i); + if (removeOrAnimateExitRecursive(child, shouldRemove)) { + hasAnimatedChildren = true; + } else if (shouldRemove) { + toBeRemoved.add(child); + } + } + } + + boolean wantAnimateExit = hasExitAnimation || hasAnimatedChildren; + + if (hasExitAnimation) { + Snapshot before = new Snapshot(view, mReanimatedNativeHierarchyManager); + HashMap currentValues = before.toCurrentMap(); + HashMap preparedValues = prepareDataForAnimationWorklet(currentValues, false); + if (!mExitingViews.containsKey(tag)) { + mExitingViews.put(tag, view); + registerExitingAncestors(view); + mNativeMethodsHolder.startAnimation(tag, LayoutAnimations.Types.EXITING, preparedValues); + } + } + + mNativeMethodsHolder.clearAnimationConfig(tag); + + if (!wantAnimateExit) { + return false; + } + + if (hasAnimatedChildren) { + mAncestorsToRemove.add(tag); + } + + for (View child : toBeRemoved) { + removeView(child, (ViewGroup) view); + } + + return true; + } + + public void clearAnimationConfigForTag(int tag) { + View view = resolveView(tag); + if (view != null) { + clearAnimationConfigRecursive(view); + } + } + + public void clearAnimationConfigRecursive(View view) { + mNativeMethodsHolder.clearAnimationConfig(view.getId()); + if (view instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) view; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + clearAnimationConfigRecursive(viewGroup.getChildAt(i)); + } + } + } + + public void cancelAnimationsInSubviews(View view) { + cancelAnimationsRecursive(view); + clearAnimationConfigRecursive(view); + } + + private void registerExitingAncestors(View view) { + View parent = (View) view.getParent(); + while (parent != null && !(parent instanceof RootView)) { + int tag = parent.getId(); + Integer previousValue = mExitingSubviewCountMap.get(tag); + int newValue = previousValue != null ? previousValue + 1 : 1; + mExitingSubviewCountMap.put(tag, newValue); + + parent = (View) parent.getParent(); + } + } + + private void maybeDropAncestors(View exitingView) { + if (!(exitingView.getParent() instanceof View)) { + return; + } + View parent = (View) exitingView.getParent(); + while (parent != null && !(parent instanceof RootView)) { + View view = parent; + parent = (View) view.getParent(); + int tag = view.getId(); + Integer ancestorOfCount = mExitingSubviewCountMap.get(tag); + ancestorOfCount = ancestorOfCount != null ? ancestorOfCount - 1 : 0; + if (ancestorOfCount <= 0) { + if (mAncestorsToRemove.contains(tag)) { + mAncestorsToRemove.remove(tag); + if (!mExitingViews.containsKey(tag)) { + removeView(view, (ViewGroup) parent); + } + } + mExitingSubviewCountMap.remove(tag); + } else { + mExitingSubviewCountMap.put(tag, ancestorOfCount); + } + } + } + + private void removeView(View view, @Nullable ViewGroup parent) { + int tag = view.getId(); + if (mCallbacks.containsKey(tag)) { + Runnable callback = mCallbacks.get(tag); + mCallbacks.remove(tag); + if (callback != null) { + callback.run(); + } + } else { + mReanimatedNativeHierarchyManager.publicDropView(view); + } + + if (parent != null) { + parent.removeView(view); + } + } + + public void cancelAnimationsRecursive(View view) { + if (mExitingViews.containsKey(view.getId())) { + endLayoutAnimation(view.getId(), true, true); + } else if (view instanceof ViewGroup && mExitingSubviewCountMap.containsKey(view.getId())) { + cancelAnimationsInSubviews((ViewGroup) view); + } + } + + private void cancelAnimationsInSubviews(ViewGroup view) { + for (int i = view.getChildCount() - 1; i >= 0; i--) { + View child = view.getChildAt(i); + + if (child == null) { + continue; + } + + if (mExitingViews.containsKey(child.getId())) { + endLayoutAnimation(child.getId(), true, true); + } else if (child instanceof ViewGroup && mExitingSubviewCountMap.containsKey(child.getId())) { + cancelAnimationsInSubviews((ViewGroup) child); + } + } + } + + private View resolveView(int tag) { + if (mExitingViews.containsKey(tag)) { + return mExitingViews.get(tag); + } else { + View view = mSharedTransitionManager.getTransitioningView(tag); + if (view != null) { + return view; + } + } + + try { + return mUIManager.resolveView(tag); + } catch (IllegalViewOperationException e) { + // view has been removed already + return null; + } + } + + private ViewManager resolveViewManager(int tag) { + try { + return mReanimatedNativeHierarchyManager.resolveViewManager(tag); + } catch (Exception e) { + return null; + } + } + + private static Point convertScreenLocationToViewCoordinates(Point fromPoint, View parentView) { + int[] toPoint = {0, 0}; + if (parentView != null) { + parentView.getLocationOnScreen(toPoint); + } + return new Point(fromPoint.x - toPoint[0], fromPoint.y - toPoint[1]); + } + + public void screenDidLayout() { + mSharedTransitionManager.screenDidLayout(); + } + + public void viewDidLayout(View view) { + mSharedTransitionManager.viewDidLayout(view); + } + + public void notifyAboutViewsRemoval(int[] tagsToDelete) { + mSharedTransitionManager.onViewsRemoval(tagsToDelete); + } + + public void makeSnapshotOfTopScreenViews(ViewGroup stack) { + mSharedTransitionManager.doSnapshotForTopScreenViews(stack); + } + + protected ReactContext getContext() { + return mContext; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java new file mode 100644 index 00000000000000..c44baf8be370e9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java @@ -0,0 +1,85 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.soloader.SoLoader; +import abi49_0_0.com.swmansion.reanimated.ReanimatedModule; +import java.lang.ref.WeakReference; +import java.util.Map; + +public class LayoutAnimations { + public static class Types { + static final int ENTERING = 1; + static final int EXITING = 2; + static final int LAYOUT = 3; + static final int SHARED_ELEMENT_TRANSITION = 4; + } + + static { + SoLoader.loadLibrary("reanimated_abi49_0_0"); + } + + @DoNotStrip + @SuppressWarnings("unused") + private final HybridData mHybridData; + + private final WeakReference mContext; + private WeakReference mWeakAnimationsManager = new WeakReference<>(null); + + public LayoutAnimations(ReactApplicationContext context) { + mContext = new WeakReference<>(context); + mHybridData = initHybrid(); + } + + private native HybridData initHybrid(); + + // LayoutReanimation + public native void startAnimationForTag(int tag, int type, Map values); + + public native boolean hasAnimationForTag(int tag, int type); + + public native void clearAnimationConfigForTag(int tag); + + public native void cancelAnimationForTag( + int tag, int type, boolean cancelled, boolean removeView); + + public native boolean isLayoutAnimationEnabled(); + + public native int findPrecedingViewTagForTransition(int tag); + + private void endLayoutAnimation(int tag, boolean cancelled, boolean removeView) { + AnimationsManager animationsManager = getAnimationsManager(); + if (animationsManager == null) { + return; + } + animationsManager.endLayoutAnimation(tag, cancelled, removeView); + } + + private void progressLayoutAnimation( + int tag, Map newStyle, boolean isSharedTransition) { + AnimationsManager animationsManager = getAnimationsManager(); + if (animationsManager == null) { + return; + } + animationsManager.progressLayoutAnimation(tag, newStyle, isSharedTransition); + } + + private AnimationsManager getAnimationsManager() { + AnimationsManager animationsManager = mWeakAnimationsManager.get(); + if (animationsManager != null) { + return mWeakAnimationsManager.get(); + } + + ReactApplicationContext context = mContext.get(); + if (context == null) { + return null; + } + + animationsManager = + context.getNativeModule(ReanimatedModule.class).getNodesManager().getAnimationsManager(); + + mWeakAnimationsManager = new WeakReference<>(animationsManager); + return animationsManager; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java new file mode 100644 index 00000000000000..283ee51d8d191b --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java @@ -0,0 +1,17 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import java.util.HashMap; + +public interface NativeMethodsHolder { + void startAnimation(int tag, int type, HashMap values); + + boolean hasAnimation(int tag, int type); + + void clearAnimationConfig(int tag); + + void cancelAnimation(int tag, int type, boolean cancelled, boolean removeView); + + boolean isLayoutAnimationEnabled(); + + int findPrecedingViewTagForTransition(int tag); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/SharedElement.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/SharedElement.java new file mode 100644 index 00000000000000..1b76ea19d9b6c9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/SharedElement.java @@ -0,0 +1,19 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.view.View; + +public class SharedElement { + + public View sourceView; + public Snapshot sourceViewSnapshot; + public View targetView; + public Snapshot targetViewSnapshot; + + public SharedElement( + View sourceView, Snapshot sourceViewSnapshot, View targetView, Snapshot targetViewSnapshot) { + this.sourceView = sourceView; + this.sourceViewSnapshot = sourceViewSnapshot; + this.targetView = targetView; + this.targetViewSnapshot = targetViewSnapshot; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/SharedTransitionManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/SharedTransitionManager.java new file mode 100644 index 00000000000000..21b1d3b6994d64 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/SharedTransitionManager.java @@ -0,0 +1,610 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.app.Activity; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.PixelUtil; +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; + +public class SharedTransitionManager { + private final AnimationsManager mAnimationsManager; + private NativeMethodsHolder mNativeMethodsHolder; + private final List mAddedSharedViews = new ArrayList<>(); + private final Map mSharedTransitionParent = new HashMap<>(); + private final Map mSharedTransitionInParentIndex = new HashMap<>(); + private boolean mIsSharedTransitionActive; + private final Map mSnapshotRegistry = new HashMap<>(); + private final Map mCurrentSharedTransitionViews = new HashMap<>(); + private View mTransitionContainer; + private final List mRemovedSharedViews = new ArrayList<>(); + private final Set mViewTagsToHide = new HashSet<>(); + private final Map mDisableCleaningForViewTag = new HashMap<>(); + private List mSharedElements = new ArrayList<>(); + private final Map mViewsWithCanceledAnimation = new HashMap<>(); + + public SharedTransitionManager(AnimationsManager animationsManager) { + mAnimationsManager = animationsManager; + } + + protected void notifyAboutNewView(View view) { + mAddedSharedViews.add(view); + } + + protected void notifyAboutRemovedView(View view) { + mRemovedSharedViews.add(view); + } + + @Nullable + protected View getTransitioningView(int tag) { + return mCurrentSharedTransitionViews.get(tag); + } + + protected void screenDidLayout() { + tryStartSharedTransitionForViews(mAddedSharedViews, true); + mAddedSharedViews.clear(); + } + + protected void viewDidLayout(View view) { + maybeRestartAnimationWithNewLayout(view); + } + + protected void onViewsRemoval(int[] tagsToDelete) { + if (tagsToDelete == null) { + return; + } + restoreVisibility(); + visitTreeForTags(tagsToDelete, new SnapshotTreeVisitor()); + if (mRemovedSharedViews.size() > 0) { + // this happens when navigation goes back + boolean animationStarted = tryStartSharedTransitionForViews(mRemovedSharedViews, false); + if (!animationStarted) { + mRemovedSharedViews.clear(); + return; + } + ConfigCleanerTreeVisitor configCleanerTreeVisitor = new ConfigCleanerTreeVisitor(); + for (View removedSharedView : mRemovedSharedViews) { + visitTree(removedSharedView, configCleanerTreeVisitor); + } + mRemovedSharedViews.clear(); + visitTreeForTags(tagsToDelete, configCleanerTreeVisitor); + } else if (mCurrentSharedTransitionViews.size() > 0) { + // this happens when navigation goes back and previous shared animation is still running + List viewsWithNewTransition = new ArrayList<>(); + for (View view : mCurrentSharedTransitionViews.values()) { + for (int tagToDelete : tagsToDelete) { + if (isViewChildParentWithTag(view, tagToDelete)) { + viewsWithNewTransition.add(view); + } + } + } + tryStartSharedTransitionForViews(viewsWithNewTransition, false); + for (View view : viewsWithNewTransition) { + clearAllSharedConfigsForView(view); + } + } + } + + private void restoreVisibility() { + ReanimatedNativeHierarchyManager reanimatedNativeHierarchyManager = + mAnimationsManager.getReanimatedNativeHierarchyManager(); + for (int viewTag : mViewTagsToHide) { + View view = reanimatedNativeHierarchyManager.resolveView(viewTag); + if (view != null) { + view.setVisibility(View.VISIBLE); + } + } + mViewTagsToHide.clear(); + } + + private boolean isViewChildParentWithTag(View view, int parentTag) { + View parent = mSharedTransitionParent.get(view.getId()); + while (parent != null) { + if (parent.getId() == parentTag) { + return true; + } + if (parent.getClass().getSimpleName().equals("Screen")) { + return false; + } + if (parent instanceof View) { + parent = (View) parent.getParent(); + } else { + return false; + } + } + return false; + } + + protected void doSnapshotForTopScreenViews(ViewGroup stack) { + int screensCount = stack.getChildCount(); + if (screensCount > 0) { + View firstStackChild = stack.getChildAt(0); + if (firstStackChild instanceof ViewGroup) { + View screen = ((ViewGroup) firstStackChild).getChildAt(0); + visitNativeTreeAndMakeSnapshot(screen); + } else { + Log.e("[Reanimated]", "Unable to recognize screen on stack."); + } + } + } + + protected void setNativeMethods(NativeMethodsHolder nativeMethods) { + mNativeMethodsHolder = nativeMethods; + } + + private void maybeRestartAnimationWithNewLayout(View view) { + View sharedView = mCurrentSharedTransitionViews.get(view.getId()); + if (sharedView == null) { + return; + } + List sharedElementsToRestart = new ArrayList<>(); + for (SharedElement sharedElement : mSharedElements) { + if (sharedElement.targetView == sharedView) { + sharedElementsToRestart.add(sharedElement); + View sourceView = sharedElement.sourceView; + View targetView = sharedElement.targetView; + + Snapshot newSourceViewSnapshot = new Snapshot(sourceView); + Snapshot currentTargetViewSnapshot = mSnapshotRegistry.get(targetView.getId()); + Snapshot newTargetViewSnapshot = new Snapshot(targetView); + + int newOriginX = + currentTargetViewSnapshot.originX + - currentTargetViewSnapshot.originXByParent + + newTargetViewSnapshot.originX; + int newOriginY = + currentTargetViewSnapshot.originY + - currentTargetViewSnapshot.originYByParent + + newTargetViewSnapshot.originY; + + currentTargetViewSnapshot.originX = newOriginX; + currentTargetViewSnapshot.originY = newOriginY; + currentTargetViewSnapshot.globalOriginX = newOriginX; + currentTargetViewSnapshot.globalOriginY = newOriginY; + currentTargetViewSnapshot.originXByParent = newTargetViewSnapshot.originXByParent; + currentTargetViewSnapshot.originYByParent = newTargetViewSnapshot.originYByParent; + currentTargetViewSnapshot.height = newTargetViewSnapshot.height; + currentTargetViewSnapshot.width = newTargetViewSnapshot.width; + sharedElement.sourceViewSnapshot = newSourceViewSnapshot; + sharedElement.targetViewSnapshot = currentTargetViewSnapshot; + + disableCleaningForViewTag(sourceView.getId()); + disableCleaningForViewTag(targetView.getId()); + } + } + startSharedTransition(sharedElementsToRestart); + } + + private boolean tryStartSharedTransitionForViews( + List sharedViews, boolean withNewElements) { + if (sharedViews.isEmpty()) { + return false; + } + sortViewsByTags(sharedViews); + List sharedElements = + getSharedElementsForCurrentTransition(sharedViews, withNewElements); + if (sharedElements.isEmpty()) { + return false; + } + setupTransitionContainer(); + reparentSharedViewsForCurrentTransition(sharedElements); + startSharedTransition(sharedElements); + return true; + } + + private void sortViewsByTags(List views) { + /* + All shared views during the transition have the same parent. It is problematic if parent + view and their children are in the same transition. To keep the valid order in the z-axis, + we need to sort views by tags. Parent tag is lower than children tags. + */ + Collections.sort(views, (v1, v2) -> Integer.compare(v2.getId(), v1.getId())); + } + + private List getSharedElementsForCurrentTransition( + List sharedViews, boolean addedNewScreen) { + List newTransitionViews = new ArrayList<>(); + Set viewTags = new HashSet<>(); + if (!addedNewScreen) { + for (View view : sharedViews) { + viewTags.add(view.getId()); + } + } + List sharedElements = new ArrayList<>(); + ReanimatedNativeHierarchyManager reanimatedNativeHierarchyManager = + mAnimationsManager.getReanimatedNativeHierarchyManager(); + for (View sharedView : sharedViews) { + int targetViewTag = + mNativeMethodsHolder.findPrecedingViewTagForTransition(sharedView.getId()); + boolean bothAreRemoved = !addedNewScreen && viewTags.contains(targetViewTag); + if (targetViewTag < 0) { + continue; + } + View viewSource, viewTarget; + if (addedNewScreen) { + viewSource = reanimatedNativeHierarchyManager.resolveView(targetViewTag); + viewTarget = sharedView; + } else { + viewSource = sharedView; + viewTarget = reanimatedNativeHierarchyManager.resolveView(targetViewTag); + } + if (bothAreRemoved) { + // case for nested stack + clearAllSharedConfigsForView(viewSource); + clearAllSharedConfigsForView(viewTarget); + continue; + } + + boolean isSourceViewInTransition = + mCurrentSharedTransitionViews.containsKey(viewSource.getId()); + boolean isTargetViewInTransition = + mCurrentSharedTransitionViews.containsKey(viewTarget.getId()); + + if (!(isSourceViewInTransition || isTargetViewInTransition)) { + View viewSourceScreen = findScreen(viewSource); + View viewTargetScreen = findScreen(viewTarget); + if (viewSourceScreen == null || viewTargetScreen == null) { + continue; + } + + ViewGroup stack = (ViewGroup) findStack(viewSourceScreen); + if (stack == null) { + continue; + } + + ViewGroupManager stackViewGroupManager = + (ViewGroupManager) reanimatedNativeHierarchyManager.resolveViewManager(stack.getId()); + int screensCount = stackViewGroupManager.getChildCount(stack); + + if (screensCount < 2) { + continue; + } + + View topScreen = stackViewGroupManager.getChildAt(stack, screensCount - 1); + View secondScreen = stackViewGroupManager.getChildAt(stack, screensCount - 2); + boolean isValidConfiguration; + if (addedNewScreen) { + isValidConfiguration = + secondScreen.getId() == viewSourceScreen.getId() + && topScreen.getId() == viewTargetScreen.getId(); + } else { + isValidConfiguration = + topScreen.getId() == viewSourceScreen.getId() + && secondScreen.getId() == viewTargetScreen.getId(); + } + if (!isValidConfiguration) { + continue; + } + } + + Snapshot sourceViewSnapshot = null; + if (addedNewScreen) { + mViewTagsToHide.add(viewSource.getId()); + if (isSourceViewInTransition) { + sourceViewSnapshot = new Snapshot(viewSource); + } else { + makeSnapshot(viewSource); + } + makeSnapshot(viewTarget); + } else if (isSourceViewInTransition) { + makeSnapshot(viewSource); + } + if (sourceViewSnapshot == null) { + sourceViewSnapshot = mSnapshotRegistry.get(viewSource.getId()); + } + Snapshot targetViewSnapshot = mSnapshotRegistry.get(viewTarget.getId()); + + newTransitionViews.add(viewSource); + newTransitionViews.add(viewTarget); + + SharedElement sharedElement = + new SharedElement(viewSource, sourceViewSnapshot, viewTarget, targetViewSnapshot); + sharedElements.add(sharedElement); + } + + if (!newTransitionViews.isEmpty()) { + for (View view : mCurrentSharedTransitionViews.values()) { + if (newTransitionViews.contains(view)) { + disableCleaningForViewTag(view.getId()); + } else { + mViewsWithCanceledAnimation.put(view.getId(), view); + } + } + mCurrentSharedTransitionViews.clear(); + for (View view : newTransitionViews) { + mCurrentSharedTransitionViews.put(view.getId(), view); + } + List viewsWithCanceledAnimation = new ArrayList<>(mViewsWithCanceledAnimation.values()); + for (View view : viewsWithCanceledAnimation) { + cancelAnimation(view); + finishSharedAnimation(view.getId()); + } + } + + mSharedElements = sharedElements; + return sharedElements; + } + + private void setupTransitionContainer() { + if (!mIsSharedTransitionActive) { + mIsSharedTransitionActive = true; + ReactContext context = mAnimationsManager.getContext(); + Activity currentActivity = context.getCurrentActivity(); + if (currentActivity == null) { + return; + } + ViewGroup rootView = (ViewGroup) currentActivity.getWindow().getDecorView().getRootView(); + if (mTransitionContainer == null) { + mTransitionContainer = new ReactViewGroup(context); + } + rootView.addView(mTransitionContainer); + mTransitionContainer.bringToFront(); + } + } + + private void reparentSharedViewsForCurrentTransition(List sharedElements) { + for (SharedElement sharedElement : sharedElements) { + View viewSource = sharedElement.sourceView; + View viewTarget = sharedElement.targetView; + + if (!mSharedTransitionParent.containsKey(viewSource.getId())) { + mSharedTransitionParent.put(viewSource.getId(), (View) viewSource.getParent()); + mSharedTransitionInParentIndex.put( + viewSource.getId(), ((ViewGroup) viewSource.getParent()).indexOfChild(viewSource)); + ((ViewGroup) viewSource.getParent()).removeView(viewSource); + ((ViewGroup) mTransitionContainer).addView(viewSource); + } + + if (!mSharedTransitionParent.containsKey(viewTarget.getId())) { + mSharedTransitionParent.put(viewTarget.getId(), (View) viewTarget.getParent()); + mSharedTransitionInParentIndex.put( + viewTarget.getId(), ((ViewGroup) viewTarget.getParent()).indexOfChild(viewTarget)); + ((ViewGroup) viewTarget.getParent()).removeView(viewTarget); + ((ViewGroup) mTransitionContainer).addView(viewTarget); + } + } + } + + private void startSharedTransition(List sharedElements) { + for (SharedElement sharedElement : sharedElements) { + startSharedAnimationForView( + sharedElement.sourceView, + sharedElement.sourceViewSnapshot, + sharedElement.targetViewSnapshot); + startSharedAnimationForView( + sharedElement.targetView, + sharedElement.sourceViewSnapshot, + sharedElement.targetViewSnapshot); + } + } + + private void startSharedAnimationForView(View view, Snapshot before, Snapshot after) { + HashMap targetValues = after.toTargetMap(); + HashMap startValues = before.toCurrentMap(); + + HashMap preparedStartValues = + mAnimationsManager.prepareDataForAnimationWorklet(startValues, false, true); + HashMap preparedTargetValues = + mAnimationsManager.prepareDataForAnimationWorklet(targetValues, true, true); + HashMap preparedValues = new HashMap<>(preparedTargetValues); + preparedValues.putAll(preparedStartValues); + + mNativeMethodsHolder.startAnimation( + view.getId(), LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION, preparedValues); + } + + protected void finishSharedAnimation(int tag) { + if (mDisableCleaningForViewTag.containsKey(tag)) { + enableCleaningForViewTag(tag); + return; + } + View view = mCurrentSharedTransitionViews.get(tag); + if (view == null) { + view = mViewsWithCanceledAnimation.get(tag); + if (view != null) { + mViewsWithCanceledAnimation.remove(view.getId()); + } + } + if (view != null) { + int viewTag = view.getId(); + ((ViewGroup) mTransitionContainer).removeView(view); + View parentView = mSharedTransitionParent.get(viewTag); + int childIndex = mSharedTransitionInParentIndex.get(viewTag); + ViewGroup parentViewGroup = ((ViewGroup) parentView); + if (childIndex <= parentViewGroup.getChildCount()) { + parentViewGroup.addView(view, childIndex); + } else { + parentViewGroup.addView(view); + } + Snapshot viewSourcePreviousSnapshot = mSnapshotRegistry.get(viewTag); + if (viewSourcePreviousSnapshot != null) { + int originY = viewSourcePreviousSnapshot.originY; + if (findStack(view) == null) { + viewSourcePreviousSnapshot.originY = viewSourcePreviousSnapshot.originYByParent; + } + Map snapshotMap = viewSourcePreviousSnapshot.toBasicMap(); + Map preparedValues = new HashMap<>(); + for (String key : snapshotMap.keySet()) { + Object value = snapshotMap.get(key); + if (key.equals(Snapshot.TRANSFORM_MATRIX)) { + preparedValues.put(key, value); + } else { + preparedValues.put(key, (double) PixelUtil.toDIPFromPixel((int) value)); + } + } + mAnimationsManager.progressLayoutAnimation(viewTag, preparedValues, true); + viewSourcePreviousSnapshot.originY = originY; + } + if (mViewTagsToHide.contains(tag)) { + view.setVisibility(View.INVISIBLE); + } + mCurrentSharedTransitionViews.remove(viewTag); + mSharedTransitionParent.remove(viewTag); + mSharedTransitionInParentIndex.remove(viewTag); + } + if (mCurrentSharedTransitionViews.isEmpty()) { + if (mTransitionContainer != null) { + ViewParent transitionContainerParent = mTransitionContainer.getParent(); + if (transitionContainerParent != null) { + ((ViewGroup) transitionContainerParent).removeView(mTransitionContainer); + } + } + mSharedElements.clear(); + mIsSharedTransitionActive = false; + } + } + + @Nullable + private View findScreen(View view) { + ViewParent parent = view.getParent(); + while (parent != null) { + if (parent.getClass().getSimpleName().equals("Screen")) { + return (View) parent; + } + parent = parent.getParent(); + } + return null; + } + + @Nullable + private View findStack(View view) { + ViewParent parent = view.getParent(); + while (parent != null) { + if (parent.getClass().getSimpleName().equals("ScreenStack")) { + return (View) parent; + } + parent = parent.getParent(); + } + return null; + } + + protected void makeSnapshot(View view) { + Snapshot snapshot = new Snapshot(view); + mSnapshotRegistry.put(view.getId(), snapshot); + } + + interface TreeVisitor { + void run(View view); + } + + class SnapshotTreeVisitor implements TreeVisitor { + public void run(View view) { + if (mAnimationsManager.hasAnimationForTag( + view.getId(), LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION)) { + mRemovedSharedViews.add(view); + makeSnapshot(view); + } + } + } + + class ConfigCleanerTreeVisitor implements TreeVisitor { + public void run(View view) { + mNativeMethodsHolder.clearAnimationConfig(view.getId()); + } + } + + protected void visitTreeForTags(int[] viewTags, TreeVisitor treeVisitor) { + if (viewTags == null) { + return; + } + ReanimatedNativeHierarchyManager reanimatedNativeHierarchyManager = + mAnimationsManager.getReanimatedNativeHierarchyManager(); + for (int viewTag : viewTags) { + View view = reanimatedNativeHierarchyManager.resolveView(viewTag); + visitTree(view, treeVisitor); + } + } + + private void visitTree(View view, TreeVisitor treeVisitor) { + int tag = view.getId(); + if (tag == -1) { + return; + } + ViewGroup viewGroup; + ViewGroupManager viewGroupManager = null; + ReanimatedNativeHierarchyManager reanimatedNativeHierarchyManager = + mAnimationsManager.getReanimatedNativeHierarchyManager(); + try { + treeVisitor.run(view); + + if (!(view instanceof ViewGroup)) { + return; + } + viewGroup = (ViewGroup) view; + ViewManager viewManager = reanimatedNativeHierarchyManager.resolveViewManager(tag); + if (viewManager instanceof ViewGroupManager) { + viewGroupManager = (ViewGroupManager) viewManager; + } + } catch (IllegalViewOperationException e) { + return; + } + if (viewGroupManager == null) { + return; + } + for (int i = 0; i < viewGroupManager.getChildCount(viewGroup); i++) { + View child = viewGroupManager.getChildAt(viewGroup, i); + visitTree(child, treeVisitor); + } + } + + void visitNativeTreeAndMakeSnapshot(View view) { + if (!(view instanceof ViewGroup)) { + return; + } + ViewGroup viewGroup = (ViewGroup) view; + if (mAnimationsManager.hasAnimationForTag( + view.getId(), LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION)) { + makeSnapshot(view); + } + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View child = viewGroup.getChildAt(i); + visitNativeTreeAndMakeSnapshot(child); + } + } + + private void clearAllSharedConfigsForView(View view) { + int viewTag = view.getId(); + mSnapshotRegistry.remove(viewTag); + mNativeMethodsHolder.clearAnimationConfig(viewTag); + } + + private void cancelAnimation(View view) { + int viewTag = view.getId(); + mNativeMethodsHolder.cancelAnimation( + viewTag, LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION, true, true); + } + + private void disableCleaningForViewTag(int viewTag) { + Integer counter = mDisableCleaningForViewTag.get(viewTag); + if (counter != null) { + mDisableCleaningForViewTag.put(viewTag, counter + 1); + } else { + mDisableCleaningForViewTag.put(viewTag, 1); + } + } + + private void enableCleaningForViewTag(int viewTag) { + Integer counter = mDisableCleaningForViewTag.get(viewTag); + if (counter == null) { + return; + } + if (counter == 1) { + mDisableCleaningForViewTag.remove(viewTag); + } else { + mDisableCleaningForViewTag.put(viewTag, counter - 1); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/Snapshot.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/Snapshot.java new file mode 100644 index 00000000000000..3c5dd2a6df9ec3 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/Snapshot.java @@ -0,0 +1,191 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.view.View; +import android.view.ViewGroup; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class Snapshot { + public static final String WIDTH = "width"; + public static final String HEIGHT = "height"; + public static final String ORIGIN_X = "originX"; + public static final String ORIGIN_Y = "originY"; + public static final String TRANSFORM_MATRIX = "transformMatrix"; + public static final String GLOBAL_ORIGIN_X = "globalOriginX"; + public static final String GLOBAL_ORIGIN_Y = "globalOriginY"; + + public static final String CURRENT_WIDTH = "currentWidth"; + public static final String CURRENT_HEIGHT = "currentHeight"; + public static final String CURRENT_ORIGIN_X = "currentOriginX"; + public static final String CURRENT_ORIGIN_Y = "currentOriginY"; + public static final String CURRENT_TRANSFORM_MATRIX = "currentTransformMatrix"; + public static final String CURRENT_GLOBAL_ORIGIN_X = "currentGlobalOriginX"; + public static final String CURRENT_GLOBAL_ORIGIN_Y = "currentGlobalOriginY"; + + public static final String TARGET_WIDTH = "targetWidth"; + public static final String TARGET_HEIGHT = "targetHeight"; + public static final String TARGET_ORIGIN_X = "targetOriginX"; + public static final String TARGET_ORIGIN_Y = "targetOriginY"; + public static final String TARGET_TRANSFORM_MATRIX = "targetTransformMatrix"; + public static final String TARGET_GLOBAL_ORIGIN_X = "targetGlobalOriginX"; + public static final String TARGET_GLOBAL_ORIGIN_Y = "targetGlobalOriginY"; + + public View view; + public ViewGroup parent; + public ViewManager viewManager; + public ViewManager parentViewManager; + public int width; + public int height; + public int originX; + public int originY; + public int globalOriginX; + public int globalOriginY; + public List transformMatrix = + new ArrayList<>(Arrays.asList(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f)); + public int originXByParent; + public int originYByParent; + private float[] identityMatrix = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + + public static ArrayList targetKeysToTransform = + new ArrayList<>( + Arrays.asList( + Snapshot.TARGET_WIDTH, + Snapshot.TARGET_HEIGHT, + Snapshot.TARGET_ORIGIN_X, + Snapshot.TARGET_ORIGIN_Y, + Snapshot.TARGET_GLOBAL_ORIGIN_X, + Snapshot.TARGET_GLOBAL_ORIGIN_Y)); + public static ArrayList currentKeysToTransform = + new ArrayList<>( + Arrays.asList( + Snapshot.CURRENT_WIDTH, + Snapshot.CURRENT_HEIGHT, + Snapshot.CURRENT_ORIGIN_X, + Snapshot.CURRENT_ORIGIN_Y, + Snapshot.CURRENT_GLOBAL_ORIGIN_X, + Snapshot.CURRENT_GLOBAL_ORIGIN_Y)); + + Snapshot(View view, NativeViewHierarchyManager viewHierarchyManager) { + parent = (ViewGroup) view.getParent(); + try { + viewManager = viewHierarchyManager.resolveViewManager(view.getId()); + parentViewManager = viewHierarchyManager.resolveViewManager(parent.getId()); + } catch (IllegalViewOperationException | NullPointerException e) { + // do nothing + } + width = view.getWidth(); + height = view.getHeight(); + originX = view.getLeft(); + originY = view.getTop(); + this.view = view; + int[] location = new int[2]; + view.getLocationOnScreen(location); + globalOriginX = location[0]; + globalOriginY = location[1]; + } + + public Snapshot(View view) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + originX = location[0]; + originY = location[1]; + width = view.getWidth(); + height = view.getHeight(); + + View transformedView = findTransformedView(view); + if (transformedView != null) { + float[] transformMatrixArray = new float[9]; + transformedView.getMatrix().getValues(transformMatrixArray); + transformMatrix = new ArrayList<>(); + for (int i = 0; i < 9; i++) { + transformMatrix.add(transformMatrixArray[i]); + } + transformMatrix.set(0, transformedView.getScaleX()); + transformMatrix.set(4, transformedView.getScaleY()); + transformMatrix.set(2, transformedView.getTranslationX()); + transformMatrix.set(5, transformedView.getTranslationY()); + + originX -= (width - width * transformedView.getScaleX()) / 2; + originY -= (height - height * transformedView.getScaleY()) / 2; + } + originXByParent = view.getLeft(); + originYByParent = view.getTop(); + } + + private void addTargetConfig(HashMap data) { + data.put(Snapshot.TARGET_ORIGIN_Y, originY); + data.put(Snapshot.TARGET_ORIGIN_X, originX); + data.put(Snapshot.TARGET_GLOBAL_ORIGIN_Y, globalOriginY); + data.put(Snapshot.TARGET_GLOBAL_ORIGIN_X, globalOriginX); + data.put(Snapshot.TARGET_HEIGHT, height); + data.put(Snapshot.TARGET_WIDTH, width); + data.put(Snapshot.TARGET_TRANSFORM_MATRIX, transformMatrix); + } + + private void addCurrentConfig(HashMap data) { + data.put(Snapshot.CURRENT_ORIGIN_Y, originY); + data.put(Snapshot.CURRENT_ORIGIN_X, originX); + data.put(Snapshot.CURRENT_GLOBAL_ORIGIN_Y, globalOriginY); + data.put(Snapshot.CURRENT_GLOBAL_ORIGIN_X, globalOriginX); + data.put(Snapshot.CURRENT_HEIGHT, height); + data.put(Snapshot.CURRENT_WIDTH, width); + data.put(Snapshot.CURRENT_TRANSFORM_MATRIX, transformMatrix); + } + + private void addBasicConfig(HashMap data) { + data.put(Snapshot.ORIGIN_Y, originY); + data.put(Snapshot.ORIGIN_X, originX); + data.put(Snapshot.GLOBAL_ORIGIN_Y, globalOriginY); + data.put(Snapshot.GLOBAL_ORIGIN_X, globalOriginX); + data.put(Snapshot.HEIGHT, height); + data.put(Snapshot.WIDTH, width); + data.put(Snapshot.TRANSFORM_MATRIX, transformMatrix); + } + + public HashMap toTargetMap() { + HashMap data = new HashMap<>(); + addTargetConfig(data); + return data; + } + + public HashMap toCurrentMap() { + HashMap data = new HashMap<>(); + addCurrentConfig(data); + return data; + } + + public HashMap toBasicMap() { + HashMap data = new HashMap<>(); + addBasicConfig(data); + return data; + } + + private View findTransformedView(View view) { + View transformedView = null; + boolean isTransformed = false; + do { + if (transformedView == null) { + transformedView = view; + } else { + if (!(transformedView.getParent() instanceof View)) { + break; + } + transformedView = (View) transformedView.getParent(); + } + if (transformedView == null) { + break; + } + float[] transformArray = new float[9]; + transformedView.getMatrix().getValues(transformArray); + isTransformed = !Arrays.equals(transformArray, identityMatrix); + } while (!isTransformed + && transformedView != null + && !transformedView.getClass().getSimpleName().equals("Screen")); + return (isTransformed && transformedView != null) ? transformedView : null; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/ViewHierarchyObserver.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/ViewHierarchyObserver.java new file mode 100644 index 00000000000000..52621994b6bfce --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/layoutReanimation/ViewHierarchyObserver.java @@ -0,0 +1,12 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.view.View; +import android.view.ViewGroup; + +public interface ViewHierarchyObserver { + void onViewRemoval(View view, ViewGroup parent, Runnable callback); + + void onViewCreate(View view, ViewGroup parent, Snapshot after); + + void onViewUpdate(View view, Snapshot before, Snapshot after); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/AnimationFrameCallback.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/AnimationFrameCallback.java new file mode 100644 index 00000000000000..ddd2158f2ab254 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/AnimationFrameCallback.java @@ -0,0 +1,19 @@ +package abi49_0_0.com.swmansion.reanimated.nativeProxy; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.swmansion.reanimated.NodesManager; + +@DoNotStrip +public class AnimationFrameCallback implements NodesManager.OnAnimationFrame { + + @DoNotStrip private final HybridData mHybridData; + + @DoNotStrip + private AnimationFrameCallback(HybridData hybridData) { + mHybridData = hybridData; + } + + @Override + public native void onAnimationFrame(double timestampMs); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/EventHandler.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/EventHandler.java new file mode 100644 index 00000000000000..675f7b6bba9ea8 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/EventHandler.java @@ -0,0 +1,35 @@ +package abi49_0_0.com.swmansion.reanimated.nativeProxy; + +import androidx.annotation.Nullable; +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.WritableArray; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter; + +@DoNotStrip +public class EventHandler implements RCTEventEmitter { + + @DoNotStrip private final HybridData mHybridData; + UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver; + + @DoNotStrip + private EventHandler(HybridData hybridData) { + mHybridData = hybridData; + } + + @Override + public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event) { + String resolvedEventName = mCustomEventNamesResolver.resolveCustomEventName(eventName); + receiveEvent(targetTag + resolvedEventName, event); + } + + public native void receiveEvent(String eventKey, @Nullable WritableMap event); + + @Override + public void receiveTouches( + String eventName, WritableArray touches, WritableArray changedIndices) { + // not interested in processing touch events this way, we process raw events only + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/KeyboardEventDataUpdater.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/KeyboardEventDataUpdater.java new file mode 100644 index 00000000000000..52236ac3f79a4c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/KeyboardEventDataUpdater.java @@ -0,0 +1,16 @@ +package abi49_0_0.com.swmansion.reanimated.nativeProxy; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; + +@DoNotStrip +public class KeyboardEventDataUpdater { + @DoNotStrip private final HybridData mHybridData; + + @DoNotStrip + private KeyboardEventDataUpdater(HybridData hybridData) { + mHybridData = hybridData; + } + + public native void keyboardEventDataUpdater(int keyboardState, int height); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/NativeProxyCommon.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/NativeProxyCommon.java new file mode 100644 index 00000000000000..19556eab6b6acf --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/NativeProxyCommon.java @@ -0,0 +1,213 @@ +package abi49_0_0.com.swmansion.reanimated.nativeProxy; + +import android.os.SystemClock; +import android.util.Log; +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.ReactApplication; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableNativeArray; +import abi49_0_0.com.facebook.react.devsupport.interfaces.DevSupportManager; +import com.facebook.soloader.SoLoader; +import abi49_0_0.com.swmansion.common.GestureHandlerStateManager; +import abi49_0_0.com.swmansion.reanimated.NativeProxy; +import abi49_0_0.com.swmansion.reanimated.NodesManager; +import abi49_0_0.com.swmansion.reanimated.ReanimatedModule; +import abi49_0_0.com.swmansion.reanimated.Scheduler; +import abi49_0_0.com.swmansion.reanimated.Utils; +import abi49_0_0.com.swmansion.reanimated.keyboardObserver.ReanimatedKeyboardEventListener; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.AnimationsManager; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.LayoutAnimations; +import abi49_0_0.com.swmansion.reanimated.sensor.ReanimatedSensorContainer; +import abi49_0_0.com.swmansion.reanimated.sensor.ReanimatedSensorType; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public abstract class NativeProxyCommon { + static { + SoLoader.loadLibrary("reanimated_abi49_0_0"); + } + + protected NodesManager mNodesManager; + protected final WeakReference mContext; + protected Scheduler mScheduler; + private ReanimatedSensorContainer reanimatedSensorContainer; + private final GestureHandlerStateManager gestureHandlerStateManager; + private ReanimatedKeyboardEventListener reanimatedKeyboardEventListener; + private Long firstUptime = SystemClock.uptimeMillis(); + private boolean slowAnimationsEnabled = false; + + protected NativeProxyCommon(ReactApplicationContext context) { + mScheduler = new Scheduler(context); + mContext = new WeakReference<>(context); + reanimatedSensorContainer = new ReanimatedSensorContainer(mContext); + reanimatedKeyboardEventListener = new ReanimatedKeyboardEventListener(mContext); + addDevMenuOption(); + + GestureHandlerStateManager tempHandlerStateManager; + try { + Class gestureHandlerModuleClass = + (Class) + Class.forName("abi49_0_0.com.swmansion.gesturehandler.react.RNGestureHandlerModule"); + tempHandlerStateManager = + (GestureHandlerStateManager) context.getNativeModule(gestureHandlerModuleClass); + } catch (ClassCastException | ClassNotFoundException e) { + tempHandlerStateManager = null; + } + gestureHandlerStateManager = tempHandlerStateManager; + } + + public Scheduler getScheduler() { + return mScheduler; + } + + private void toggleSlowAnimations() { + slowAnimationsEnabled = !slowAnimationsEnabled; + if (slowAnimationsEnabled) { + firstUptime = SystemClock.uptimeMillis(); + } + } + + private void addDevMenuOption() { + // In Expo, `ApplicationContext` is not an instance of `ReactApplication` + if (mContext.get().getApplicationContext() instanceof ReactApplication) { + final DevSupportManager devSupportManager = + ((ReactApplication) mContext.get().getApplicationContext()) + .getReactNativeHost() + .getReactInstanceManager() + .getDevSupportManager(); + + devSupportManager.addCustomDevOption( + "Toggle slow animations (Reanimated)", this::toggleSlowAnimations); + } + } + + @DoNotStrip + public void requestRender(AnimationFrameCallback callback) { + mNodesManager.postOnAnimation(callback); + } + + @DoNotStrip + public void updateProps(int viewTag, Map props) { + mNodesManager.updateProps(viewTag, props); + } + + @DoNotStrip + public void synchronouslyUpdateUIProps(int viewTag, ReadableMap uiProps) { + mNodesManager.synchronouslyUpdateUIProps(viewTag, uiProps); + } + + @DoNotStrip + public String obtainProp(int viewTag, String propName) { + return mNodesManager.obtainProp(viewTag, propName); + } + + @DoNotStrip + public void scrollTo(int viewTag, double x, double y, boolean animated) { + mNodesManager.scrollTo(viewTag, x, y, animated); + } + + @DoNotStrip + public void setGestureState(int handlerTag, int newState) { + if (gestureHandlerStateManager != null) { + gestureHandlerStateManager.setGestureHandlerState(handlerTag, newState); + } + } + + @DoNotStrip + public long getCurrentTime() { + if (slowAnimationsEnabled) { + final long ANIMATIONS_DRAG_FACTOR = 10; + return this.firstUptime + + (SystemClock.uptimeMillis() - this.firstUptime) / ANIMATIONS_DRAG_FACTOR; + } else { + return SystemClock.uptimeMillis(); + } + } + + @DoNotStrip + public float[] measure(int viewTag) { + return mNodesManager.measure(viewTag); + } + + @DoNotStrip + public void configureProps(ReadableNativeArray uiProps, ReadableNativeArray nativeProps) { + Set uiPropsSet = convertProps(uiProps); + Set nativePropsSet = convertProps(nativeProps); + mNodesManager.configureProps(uiPropsSet, nativePropsSet); + } + + private Set convertProps(ReadableNativeArray props) { + Set propsSet = new HashSet<>(); + ArrayList propsList = props.toArrayList(); + for (int i = 0; i < propsList.size(); i++) { + propsSet.add((String) propsList.get(i)); + } + return propsSet; + } + + @DoNotStrip + public void registerEventHandler(EventHandler handler) { + handler.mCustomEventNamesResolver = mNodesManager.getEventNameResolver(); + mNodesManager.registerEventHandler(handler); + } + + @DoNotStrip + public int registerSensor(int sensorType, int interval, SensorSetter setter) { + return reanimatedSensorContainer.registerSensor( + ReanimatedSensorType.getInstanceById(sensorType), interval, setter); + } + + @DoNotStrip + public void unregisterSensor(int sensorId) { + reanimatedSensorContainer.unregisterSensor(sensorId); + } + + @DoNotStrip + public int subscribeForKeyboardEvents( + KeyboardEventDataUpdater keyboardEventDataUpdater, boolean isStatusBarTranslucent) { + return reanimatedKeyboardEventListener.subscribeForKeyboardEvents( + keyboardEventDataUpdater, isStatusBarTranslucent); + } + + @DoNotStrip + public void unsubscribeFromKeyboardEvents(int listenerId) { + reanimatedKeyboardEventListener.unsubscribeFromKeyboardEvents(listenerId); + } + + protected abstract HybridData getHybridData(); + + public void onCatalystInstanceDestroy() { + mScheduler.deactivate(); + getHybridData().resetNative(); + } + + public void prepareLayoutAnimations(LayoutAnimations layoutAnimations) { + if (Utils.isChromeDebugger) { + Log.w("[REANIMATED]", "You can not use LayoutAnimation with enabled Chrome Debugger"); + return; + } + mNodesManager = mContext.get().getNativeModule(ReanimatedModule.class).getNodesManager(); + + AnimationsManager animationsManager = + mContext + .get() + .getNativeModule(ReanimatedModule.class) + .getNodesManager() + .getAnimationsManager(); + + animationsManager.setNativeMethods(NativeProxy.createNativeMethodsHolder(layoutAnimations)); + } + + @DoNotStrip + void maybeFlushUIUpdatesQueue() { + if (!mNodesManager.isAnimationRunning()) { + mNodesManager.performOperations(); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/SensorSetter.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/SensorSetter.java new file mode 100644 index 00000000000000..60bb42e0aa065a --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/nativeProxy/SensorSetter.java @@ -0,0 +1,17 @@ +package abi49_0_0.com.swmansion.reanimated.nativeProxy; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; + +@DoNotStrip +public class SensorSetter { + + @DoNotStrip private final HybridData mHybridData; + + @DoNotStrip + private SensorSetter(HybridData hybridData) { + mHybridData = hybridData; + } + + public native void sensorSetter(float[] value, int orientationDegrees); +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensor.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensor.java new file mode 100644 index 00000000000000..4fa8fdeab72170 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensor.java @@ -0,0 +1,51 @@ +package abi49_0_0.com.swmansion.reanimated.sensor; + +import static android.content.Context.WINDOW_SERVICE; + +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.view.Display; +import android.view.WindowManager; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.swmansion.reanimated.nativeProxy.SensorSetter; +import java.lang.ref.WeakReference; + +public class ReanimatedSensor { + + ReanimatedSensorListener listener; + SensorManager sensorManager; + Sensor sensor; + ReanimatedSensorType sensorType; + int interval; + + ReanimatedSensor( + WeakReference reactContext, + ReanimatedSensorType sensorType, + int interval, + SensorSetter setter) { + WindowManager wm = (WindowManager) reactContext.get().getSystemService(WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + listener = new ReanimatedSensorListener(setter, interval, display); + sensorManager = + (SensorManager) reactContext.get().getSystemService(reactContext.get().SENSOR_SERVICE); + this.sensorType = sensorType; + if (interval == -1) { + this.interval = SensorManager.SENSOR_DELAY_UI; + } else { + this.interval = interval; + } + } + + boolean initialize() { + sensor = sensorManager.getDefaultSensor(sensorType.getType()); + if (sensor != null) { + sensorManager.registerListener(listener, sensor, interval * 1000); + return true; + } + return false; + } + + void cancel() { + sensorManager.unregisterListener(listener, sensor); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorContainer.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorContainer.java new file mode 100644 index 00000000000000..f646d29a6f2f93 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorContainer.java @@ -0,0 +1,39 @@ +package abi49_0_0.com.swmansion.reanimated.sensor; + +import android.util.Log; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.swmansion.reanimated.nativeProxy.SensorSetter; +import java.lang.ref.WeakReference; +import java.util.HashMap; + +public class ReanimatedSensorContainer { + + private int nextSensorId = 0; + private final WeakReference reactContext; + private final HashMap sensors = new HashMap<>(); + + public ReanimatedSensorContainer(WeakReference reactContext) { + this.reactContext = reactContext; + } + + public int registerSensor(ReanimatedSensorType sensorType, int interval, SensorSetter setter) { + ReanimatedSensor sensor = new ReanimatedSensor(reactContext, sensorType, interval, setter); + int sensorId = -1; + if (sensor.initialize()) { + sensorId = nextSensorId; + nextSensorId++; + sensors.put(sensorId, sensor); + } + return sensorId; + } + + public void unregisterSensor(int sensorId) { + ReanimatedSensor sensor = sensors.get(sensorId); + if (sensor != null) { + sensor.cancel(); + sensors.remove(sensorId); + } else { + Log.e("Reanimated", "Tried to unregister nonexistent sensor"); + } + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorListener.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorListener.java new file mode 100644 index 00000000000000..c968cfbd73d775 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorListener.java @@ -0,0 +1,80 @@ +package abi49_0_0.com.swmansion.reanimated.sensor; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.view.Display; +import android.view.Surface; +import abi49_0_0.com.swmansion.reanimated.nativeProxy.SensorSetter; + +public class ReanimatedSensorListener implements SensorEventListener { + + private SensorSetter setter; + private double lastRead = (double) System.currentTimeMillis(); + private final double interval; + + private float[] rotation = new float[9]; + private float[] orientation = new float[3]; + private float[] quaternion = new float[4]; + + private final Display display; + + ReanimatedSensorListener(SensorSetter setter, double interval, Display display) { + this.setter = setter; + this.interval = interval; + this.display = display; + } + + @Override + public void onSensorChanged(SensorEvent event) { + double current = (double) System.currentTimeMillis(); + if (current - lastRead < interval) { + return; + } + int sensorType = event.sensor.getType(); + lastRead = current; + + int orientationDegrees; + switch (display.getRotation()) { + case Surface.ROTATION_90: + orientationDegrees = 90; + break; + case Surface.ROTATION_180: + orientationDegrees = 180; + break; + case Surface.ROTATION_270: + orientationDegrees = 270; + break; + default: + orientationDegrees = 0; + break; + } + + if (sensorType == Sensor.TYPE_ROTATION_VECTOR) { + SensorManager.getQuaternionFromVector(quaternion, event.values); + SensorManager.getRotationMatrixFromVector(rotation, event.values); + SensorManager.getOrientation(rotation, orientation); + float[] data = + new float[] { + quaternion[1], // qx + quaternion[2], // qy + quaternion[3], // qz + quaternion[0], // qw + // make Android consistent with iOS, which is better documented here: + // https://developer.apple.com/documentation/coremotion/getting_processed_device-motion_data/understanding_reference_frames_and_device_attitude + -orientation[0], // yaw + -orientation[1], // pitch + orientation[2] // roll + }; + setter.sensorSetter(data, orientationDegrees); + } else { + // Set the opposite values to be consistent with iOS + float[] data = new float[] {-event.values[0], -event.values[1], -event.values[2]}; + setter.sensorSetter(data, orientationDegrees); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {} +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorType.java b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorType.java new file mode 100644 index 00000000000000..e6de2ad1ee9a85 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/main/java/abi49_0_0/com/swmansion/reanimated/sensor/ReanimatedSensorType.java @@ -0,0 +1,37 @@ +package abi49_0_0.com.swmansion.reanimated.sensor; + +import android.hardware.Sensor; + +public enum ReanimatedSensorType { + ACCELEROMETER(Sensor.TYPE_LINEAR_ACCELERATION), + GYROSCOPE(Sensor.TYPE_GYROSCOPE), + GRAVITY(Sensor.TYPE_GRAVITY), + MAGNETIC_FIELD(Sensor.TYPE_MAGNETIC_FIELD), + ROTATION_VECTOR(Sensor.TYPE_ROTATION_VECTOR); + + private final int type; + + ReanimatedSensorType(int type) { + this.type = type; + } + + public int getType() { + return type; + } + + public static ReanimatedSensorType getInstanceById(int typeId) { + switch (typeId) { + case 1: + return ReanimatedSensorType.ACCELEROMETER; + case 2: + return ReanimatedSensorType.GYROSCOPE; + case 3: + return ReanimatedSensorType.GRAVITY; + case 4: + return ReanimatedSensorType.MAGNETIC_FIELD; + case 5: + return ReanimatedSensorType.ROTATION_VECTOR; + } + throw new IllegalArgumentException("[Reanimated] Unknown sensor type"); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libfolly_runtime_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libfolly_runtime_abi49_0_0.so new file mode 100644 index 00000000000000..8fd73f1f80f3ad Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libfolly_runtime_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libglog_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libglog_abi49_0_0.so new file mode 100644 index 00000000000000..a94eed3c0e3350 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libglog_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libjsi_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..d7ea20b9700292 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libreactnativejni_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libreactnativejni_abi49_0_0.so new file mode 100644 index 00000000000000..ac1b7e382b6690 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libreactnativejni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libreanimated_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libreanimated_abi49_0_0.so new file mode 100644 index 00000000000000..af8569e1d354b3 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/arm64-v8a/libreanimated_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libfolly_runtime_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libfolly_runtime_abi49_0_0.so new file mode 100644 index 00000000000000..fed9994e72f589 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libfolly_runtime_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libglog_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libglog_abi49_0_0.so new file mode 100644 index 00000000000000..6632cdce3d82aa Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libglog_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libjsi_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..967a7a3fa36e8e Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libreactnativejni_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libreactnativejni_abi49_0_0.so new file mode 100644 index 00000000000000..f06fb2cbb7b5cd Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libreactnativejni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libreanimated_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libreanimated_abi49_0_0.so new file mode 100644 index 00000000000000..af235fe4d44a98 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/armeabi-v7a/libreanimated_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libfolly_runtime_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libfolly_runtime_abi49_0_0.so new file mode 100644 index 00000000000000..8c26a4e6bac821 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libfolly_runtime_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libglog_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libglog_abi49_0_0.so new file mode 100644 index 00000000000000..1ff998d01f1287 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libglog_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libjsi_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..feda4776839fe0 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libreactnativejni_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libreactnativejni_abi49_0_0.so new file mode 100644 index 00000000000000..4b24963db68a17 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libreactnativejni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libreanimated_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libreanimated_abi49_0_0.so new file mode 100644 index 00000000000000..fd2c9bef4c53e2 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86/libreanimated_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libfolly_runtime_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libfolly_runtime_abi49_0_0.so new file mode 100644 index 00000000000000..c739fabeaf6679 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libfolly_runtime_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libglog_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libglog_abi49_0_0.so new file mode 100644 index 00000000000000..9bac04c80dbbe6 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libglog_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libjsi_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libjsi_abi49_0_0.so new file mode 100644 index 00000000000000..9019353cac3769 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libjsi_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libreactnativejni_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libreactnativejni_abi49_0_0.so new file mode 100644 index 00000000000000..44422f1104ac49 Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libreactnativejni_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libreanimated_abi49_0_0.so b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libreanimated_abi49_0_0.so new file mode 100644 index 00000000000000..81665796e18b5e Binary files /dev/null and b/android/vendored/sdk49/react-native-reanimated/android/src/main/jniLibs/x86_64/libreanimated_abi49_0_0.so differ diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/paper/java/abi49_0_0/com/swmansion/reanimated/NativeProxy.java b/android/vendored/sdk49/react-native-reanimated/android/src/paper/java/abi49_0_0/com/swmansion/reanimated/NativeProxy.java new file mode 100644 index 00000000000000..ac0db166a81897 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/paper/java/abi49_0_0/com/swmansion/reanimated/NativeProxy.java @@ -0,0 +1,119 @@ +package abi49_0_0.com.swmansion.reanimated; + +import static abi49_0_0.com.swmansion.reanimated.Utils.simplifyStringNumbersList; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.queue.MessageQueueThread; +import abi49_0_0.com.facebook.react.turbomodule.core.CallInvokerHolderImpl; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.LayoutAnimations; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.NativeMethodsHolder; +import abi49_0_0.com.swmansion.reanimated.nativeProxy.NativeProxyCommon; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +public class NativeProxy extends NativeProxyCommon { + @DoNotStrip + @SuppressWarnings("unused") + private final HybridData mHybridData; + + public NativeProxy(ReactApplicationContext context) { + super(context); + CallInvokerHolderImpl holder = + (CallInvokerHolderImpl) context.getCatalystInstance().getJSCallInvokerHolder(); + LayoutAnimations LayoutAnimations = new LayoutAnimations(context); + mHybridData = + initHybrid( + context.getJavaScriptContextHolder().get(), + holder, + mScheduler, + LayoutAnimations); + prepareLayoutAnimations(LayoutAnimations); + ReanimatedMessageQueueThread messageQueueThread = new ReanimatedMessageQueueThread(); + installJSIBindings(messageQueueThread); + } + + private native HybridData initHybrid( + long jsContext, + CallInvokerHolderImpl jsCallInvokerHolder, + Scheduler scheduler, + LayoutAnimations LayoutAnimations); + + private native void installJSIBindings(MessageQueueThread messageQueueThread); + + public native boolean isAnyHandlerWaitingForEvent(String eventName); + + public native void performOperations(); + + @Override + protected HybridData getHybridData() { + return mHybridData; + } + + public static NativeMethodsHolder createNativeMethodsHolder(LayoutAnimations layoutAnimations) { + WeakReference weakLayoutAnimations = new WeakReference<>(layoutAnimations); + return new NativeMethodsHolder() { + @Override + public void startAnimation(int tag, int type, HashMap values) { + LayoutAnimations layoutAnimations = weakLayoutAnimations.get(); + if (layoutAnimations != null) { + HashMap preparedValues = new HashMap<>(); + for (String key : values.keySet()) { + String stringValue = values.get(key).toString(); + if (key.endsWith("TransformMatrix")) { + preparedValues.put(key, simplifyStringNumbersList(stringValue)); + } else { + preparedValues.put(key, stringValue); + } + } + layoutAnimations.startAnimationForTag(tag, type, preparedValues); + } + } + + @Override + public boolean isLayoutAnimationEnabled() { + LayoutAnimations layoutAnimations = weakLayoutAnimations.get(); + if (layoutAnimations != null) { + return layoutAnimations.isLayoutAnimationEnabled(); + } + return false; + } + + @Override + public boolean hasAnimation(int tag, int type) { + LayoutAnimations layoutAnimations = weakLayoutAnimations.get(); + if (layoutAnimations != null) { + return layoutAnimations.hasAnimationForTag(tag, type); + } + return false; + } + + @Override + public void clearAnimationConfig(int tag) { + LayoutAnimations layoutAnimations = weakLayoutAnimations.get(); + if (layoutAnimations != null) { + layoutAnimations.clearAnimationConfigForTag(tag); + } + } + + @Override + public void cancelAnimation(int tag, int type, boolean cancelled, boolean removeView) { + LayoutAnimations layoutAnimations = weakLayoutAnimations.get(); + if (layoutAnimations != null) { + layoutAnimations.cancelAnimationForTag(tag, type, cancelled, removeView); + } + } + + @Override + public int findPrecedingViewTagForTransition(int tag) { + LayoutAnimations layoutAnimations = weakLayoutAnimations.get(); + if (layoutAnimations != null) { + return layoutAnimations.findPrecedingViewTagForTransition(tag); + } + return -1; + } + }; + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/paper/java/abi49_0_0/com/swmansion/reanimated/ReaCompatibility.java b/android/vendored/sdk49/react-native-reanimated/android/src/paper/java/abi49_0_0/com/swmansion/reanimated/ReaCompatibility.java new file mode 100644 index 00000000000000..4346e874fe4eef --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/paper/java/abi49_0_0/com/swmansion/reanimated/ReaCompatibility.java @@ -0,0 +1,17 @@ +package abi49_0_0.com.swmansion.reanimated; + +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.swmansion.reanimated.NodesManager; + +class ReaCompatibility { + public ReaCompatibility(ReactApplicationContext reactApplicationContext) { + + } + public void registerFabricEventListener(NodesManager nodeManager) { + + } + public void synchronouslyUpdateUIProps(int viewTag, ReadableMap uiProps) { + + } +} \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/70/com/swmansion/reanimated/ReanimatedUIManagerFactory.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/70/com/swmansion/reanimated/ReanimatedUIManagerFactory.java new file mode 100644 index 00000000000000..9ceb5afc7e4c96 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/70/com/swmansion/reanimated/ReanimatedUIManagerFactory.java @@ -0,0 +1,16 @@ +package abi49_0_0.com.swmansion.reanimated; + +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.uimanager.ReanimatedUIManager; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; + +import java.util.List; + +public class ReanimatedUIManagerFactory { + + public static UIManagerModule create(ReactApplicationContext reactContext, List viewManagers, int minTimeLeftInFrameForNonBatchedOperationMs) { + return new ReanimatedUIManager(reactContext, viewManagers, minTimeLeftInFrameForNonBatchedOperationMs); + } + +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/70/com/swmansion/reanimated/layoutReanimation/ReanimatedUIManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/70/com/swmansion/reanimated/layoutReanimation/ReanimatedUIManager.java new file mode 100644 index 00000000000000..b7df07e74fc895 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/70/com/swmansion/reanimated/layoutReanimation/ReanimatedUIManager.java @@ -0,0 +1,292 @@ +package abi49_0_0.com.facebook.react.uimanager; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.Callback; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher; +import java.util.List; + +class ReaUiImplementationProvider extends UIImplementationProvider { + + @Override + UIImplementation createUIImplementation( + ReactApplicationContext reactContext, + ViewManagerRegistry viewManagerRegistry, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + return new abi49_0_0.com.facebook.react.uimanager.ReanimatedUIImplementation( + reactContext, + viewManagerRegistry, + eventDispatcher, + minTimeLeftInFrameForNonBatchedOperationMs); + } +} + +@ReactModule(name = UIManagerModule.NAME) +public class ReanimatedUIManager extends UIManagerModule { + + public ReanimatedUIManager( + ReactApplicationContext reactContext, + List viewManagersList, + int minTimeLeftInFrameForNonBatchedOperationMs) { + super( + reactContext, + viewManagersList, + new ReaUiImplementationProvider(), + minTimeLeftInFrameForNonBatchedOperationMs); + } + + public void onBatchComplete() { + super.onBatchComplete(); + } + + @Override + public boolean canOverrideExistingModule() { + return true; + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public @Nullable WritableMap getConstantsForViewManager(@Nullable String viewManagerName) { + return super.getConstantsForViewManager(viewManagerName); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public WritableMap getDefaultEventTypes() { + return super.getDefaultEventTypes(); + } + + /** Unregisters a new root view. */ + @ReactMethod + public void removeRootView(int rootViewTag) { + super.removeRootView(rootViewTag); + } + + @ReactMethod + public void createView(int tag, String className, int rootViewTag, ReadableMap props) { + super.createView(tag, className, rootViewTag, props); + } + + @ReactMethod + public void updateView(final int tag, final String className, final ReadableMap props) { + super.updateView(tag, className, props); + } + + /** + * Interface for adding/removing/moving views within a parent view from JS. + * + * @param viewTag the view tag of the parent view + * @param moveFrom a list of indices in the parent view to move views from + * @param moveTo parallel to moveFrom, a list of indices in the parent view to move views to + * @param addChildTags a list of tags of views to add to the parent + * @param addAtIndices parallel to addChildTags, a list of indices to insert those children at + * @param removeFrom a list of indices of views to permanently remove. The memory for the + * corresponding views and data structures should be reclaimed. + */ + @ReactMethod + public void manageChildren( + int viewTag, + @Nullable ReadableArray moveFrom, + @Nullable ReadableArray moveTo, + @Nullable ReadableArray addChildTags, + @Nullable ReadableArray addAtIndices, + @Nullable ReadableArray removeFrom) { + super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom); + } + + /** + * Interface for fast tracking the initial adding of views. Children view tags are assumed to be + * in order + * + * @param viewTag the view tag of the parent view + * @param childrenTags An array of tags to add to the parent in order + */ + @ReactMethod + public void setChildren(int viewTag, ReadableArray childrenTags) { + super.setChildren(viewTag, childrenTags); + } + + /** + * Replaces the View specified by oldTag with the View specified by newTag within oldTag's parent. + * This resolves to a simple {@link #manageChildren} call, but React doesn't have enough info in + * JS to formulate it itself. + * + * @deprecated This method will not be available in Fabric UIManager class. + */ + @ReactMethod + @Deprecated + public void replaceExistingNonRootView(int oldTag, int newTag) { + super.replaceExistingNonRootView(oldTag, newTag); + } + + /** + * Method which takes a container tag and then releases all subviews for that container upon + * receipt. + * + * @param containerTag the tag of the container for which the subviews must be removed + * @deprecated This method will not be available in Fabric UIManager class. + */ + @ReactMethod + @Deprecated + public void removeSubviewsFromContainerWithID(int containerTag) { + super.removeSubviewsFromContainerWithID(containerTag); + } + + /** + * Determines the location on screen, width, and height of the given view and returns the values + * via an async callback. + */ + @ReactMethod + public void measure(int reactTag, Callback callback) { + super.measure(reactTag, callback); + } + + /** + * Determines the location on screen, width, and height of the given view relative to the device + * screen and returns the values via an async callback. This is the absolute position including + * things like the status bar + */ + @ReactMethod + public void measureInWindow(int reactTag, Callback callback) { + super.measureInWindow(reactTag, callback); + } + + /** + * Measures the view specified by tag relative to the given ancestorTag. This means that the + * returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the + * given outputBuffer. We allow ancestor view and measured view to be the same, in which case the + * position always will be (0, 0) and method will only measure the view dimensions. + * + *

NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible + * window which can cause unexpected results when measuring relative to things like ScrollViews + * that can have offset content on the screen. + */ + @ReactMethod + public void measureLayout( + int tag, int ancestorTag, Callback errorCallback, Callback successCallback) { + super.measureLayout(tag, ancestorTag, errorCallback, successCallback); + } + + /** + * Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent. + * + *

NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible + * window which can cause unexpected results when measuring relative to things like ScrollViews + * that can have offset content on the screen. + * + * @deprecated this method will not be available in FabricUIManager class. + */ + @ReactMethod + @Deprecated + public void measureLayoutRelativeToParent( + int tag, Callback errorCallback, Callback successCallback) { + super.measureLayoutRelativeToParent(tag, errorCallback, successCallback); + } + + /** + * Find the touch target child native view in the supplied root view hierarchy, given a react + * target location. + * + *

This method is currently used only by Element Inspector DevTool. + * + * @param reactTag the tag of the root view to traverse + * @param point an array containing both X and Y target location + * @param callback will be called if with the identified child view react ID, and measurement + * info. If no view was found, callback will be invoked with no data. + */ + @ReactMethod + public void findSubviewIn( + final int reactTag, final ReadableArray point, final Callback callback) { + super.findSubviewIn(reactTag, point, callback); + } + + /** + * Check if the first shadow node is the descendant of the second shadow node + * + * @deprecated this method will not be available in FabricUIManager class. + */ + @ReactMethod + @Deprecated + public void viewIsDescendantOf( + final int reactTag, final int ancestorReactTag, final Callback callback) { + super.viewIsDescendantOf(reactTag, ancestorReactTag, callback); + } + + @ReactMethod + public void setJSResponder(int reactTag, boolean blockNativeResponder) { + super.setJSResponder(reactTag, blockNativeResponder); + } + + @ReactMethod + public void clearJSResponder() { + super.clearJSResponder(); + } + + @ReactMethod + public void dispatchViewManagerCommand( + int reactTag, Dynamic commandId, @Nullable ReadableArray commandArgs) { + super.dispatchViewManagerCommand(reactTag, commandId, commandArgs); + } + + /** + * Show a PopupMenu. + * + * @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this + * needs to be the tag of a native view (shadow views can not be anchors) + * @param items the menu items as an array of strings + * @param error will be called if there is an error displaying the menu + * @param success will be called with the position of the selected item as the first argument, or + * no arguments if the menu is dismissed + */ + @ReactMethod + public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) { + super.showPopupMenu(reactTag, items, error, success); + } + + @ReactMethod + public void dismissPopupMenu() { + super.dismissPopupMenu(); + } + + /** + * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled + * explicitly in order to avoid regression in existing application written for iOS using this API. + * + *

Warning : This method will be removed in future version of React Native, and layout + * animation will be enabled by default, so always check for its existence before invoking it. + * + *

TODO(9139831) : remove this method once layout animation is fully stable. + * + * @param enabled whether layout animation is enabled or not + */ + @ReactMethod + public void setLayoutAnimationEnabledExperimental(boolean enabled) { + super.setLayoutAnimationEnabledExperimental(enabled); + } + + /** + * Configure an animation to be used for the native layout changes, and native views creation. The + * animation will only apply during the current batch operations. + * + *

TODO(7728153) : animating view deletion is currently not supported. + * + * @param config the configuration of the animation for view addition/removal/update. + * @param success will be called when the animation completes, or when the animation get + * interrupted. In this case, callback parameter will be false. + * @param error will be called if there was an error processing the animation + */ + @ReactMethod + public void configureNextLayoutAnimation(ReadableMap config, Callback success, Callback error) { + super.configureNextLayoutAnimation(config, success, error); + } + + @ReactMethod + public void sendAccessibilityEvent(int tag, int eventType) { + super.sendAccessibilityEvent(tag, eventType); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/latest/com/swmansion/reanimated/ReanimatedUIManagerFactory.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/latest/com/swmansion/reanimated/ReanimatedUIManagerFactory.java new file mode 100644 index 00000000000000..9c89a2e4dac16c --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/latest/com/swmansion/reanimated/ReanimatedUIManagerFactory.java @@ -0,0 +1,63 @@ +package abi49_0_0.com.swmansion.reanimated; + +import android.os.Build; +import android.util.Log; + +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.uimanager.ReanimatedUIImplementation; +import abi49_0_0.com.facebook.react.uimanager.ReanimatedUIManager; +import abi49_0_0.com.facebook.react.uimanager.UIImplementation; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManagerRegistry; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.List; + +public class ReanimatedUIManagerFactory { + + public static UIManagerModule create(ReactApplicationContext reactContext, List viewManagers, int minTimeLeftInFrameForNonBatchedOperationMs) { + ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); + + UIManagerModule uiManagerModule = + new ReanimatedUIManager( + reactContext, viewManagers, minTimeLeftInFrameForNonBatchedOperationMs); + + UIImplementation uiImplementation = + new ReanimatedUIImplementation( + reactContext, + viewManagerRegistry, + uiManagerModule.getEventDispatcher(), + minTimeLeftInFrameForNonBatchedOperationMs); + + Class clazz = uiManagerModule.getClass().getSuperclass(); + if (clazz == null) { + Log.e("reanimated", "unable to resolve super class of ReanimatedUIManager"); + return uiManagerModule; + } + + try { + Field uiImplementationField = clazz.getDeclaredField("mUIImplementation"); + uiImplementationField.setAccessible(true); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + // accessFlags is supported only by API >=23 + Field modifiersField = Field.class.getDeclaredField("accessFlags"); + modifiersField.setAccessible(true); + modifiersField.setInt( + uiImplementationField, uiImplementationField.getModifiers() & ~Modifier.FINAL); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + uiImplementationField.set(uiManagerModule, uiImplementation); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + + return uiManagerModule; + } + +} \ No newline at end of file diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedUIManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedUIManager.java new file mode 100644 index 00000000000000..8a8bb65eeb2388 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/ReanimatedUIManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedUIManager.java @@ -0,0 +1,271 @@ +package abi49_0_0.com.facebook.react.uimanager; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.Callback; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import java.util.List; + +@ReactModule(name = UIManagerModule.NAME) +public class ReanimatedUIManager extends UIManagerModule { + + public ReanimatedUIManager( + ReactApplicationContext reactContext, + List viewManagersList, + int minTimeLeftInFrameForNonBatchedOperationMs) { + super(reactContext, viewManagersList, minTimeLeftInFrameForNonBatchedOperationMs); + } + + public void onBatchComplete() { + super.onBatchComplete(); + } + + @Override + public boolean canOverrideExistingModule() { + return true; + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public @Nullable WritableMap getConstantsForViewManager(@Nullable String viewManagerName) { + return super.getConstantsForViewManager(viewManagerName); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public WritableMap getDefaultEventTypes() { + return super.getDefaultEventTypes(); + } + + /** Unregisters a new root view. */ + @ReactMethod + public void removeRootView(int rootViewTag) { + super.removeRootView(rootViewTag); + } + + @ReactMethod + public void createView(int tag, String className, int rootViewTag, ReadableMap props) { + super.createView(tag, className, rootViewTag, props); + } + + @ReactMethod + public void updateView(final int tag, final String className, final ReadableMap props) { + super.updateView(tag, className, props); + } + + /** + * Interface for adding/removing/moving views within a parent view from JS. + * + * @param viewTag the view tag of the parent view + * @param moveFrom a list of indices in the parent view to move views from + * @param moveTo parallel to moveFrom, a list of indices in the parent view to move views to + * @param addChildTags a list of tags of views to add to the parent + * @param addAtIndices parallel to addChildTags, a list of indices to insert those children at + * @param removeFrom a list of indices of views to permanently remove. The memory for the + * corresponding views and data structures should be reclaimed. + */ + @ReactMethod + public void manageChildren( + int viewTag, + @Nullable ReadableArray moveFrom, + @Nullable ReadableArray moveTo, + @Nullable ReadableArray addChildTags, + @Nullable ReadableArray addAtIndices, + @Nullable ReadableArray removeFrom) { + super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom); + } + + /** + * Interface for fast tracking the initial adding of views. Children view tags are assumed to be + * in order + * + * @param viewTag the view tag of the parent view + * @param childrenTags An array of tags to add to the parent in order + */ + @ReactMethod + public void setChildren(int viewTag, ReadableArray childrenTags) { + super.setChildren(viewTag, childrenTags); + } + + /** + * Replaces the View specified by oldTag with the View specified by newTag within oldTag's parent. + * This resolves to a simple {@link #manageChildren} call, but React doesn't have enough info in + * JS to formulate it itself. + * + * @deprecated This method will not be available in Fabric UIManager class. + */ + @ReactMethod + @Deprecated + public void replaceExistingNonRootView(int oldTag, int newTag) { + super.replaceExistingNonRootView(oldTag, newTag); + } + + /** + * Method which takes a container tag and then releases all subviews for that container upon + * receipt. + * + * @param containerTag the tag of the container for which the subviews must be removed + * @deprecated This method will not be available in Fabric UIManager class. + */ + @ReactMethod + @Deprecated + public void removeSubviewsFromContainerWithID(int containerTag) { + super.removeSubviewsFromContainerWithID(containerTag); + } + + /** + * Determines the location on screen, width, and height of the given view and returns the values + * via an async callback. + */ + @ReactMethod + public void measure(int reactTag, Callback callback) { + super.measure(reactTag, callback); + } + + /** + * Determines the location on screen, width, and height of the given view relative to the device + * screen and returns the values via an async callback. This is the absolute position including + * things like the status bar + */ + @ReactMethod + public void measureInWindow(int reactTag, Callback callback) { + super.measureInWindow(reactTag, callback); + } + + /** + * Measures the view specified by tag relative to the given ancestorTag. This means that the + * returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the + * given outputBuffer. We allow ancestor view and measured view to be the same, in which case the + * position always will be (0, 0) and method will only measure the view dimensions. + * + *

NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible + * window which can cause unexpected results when measuring relative to things like ScrollViews + * that can have offset content on the screen. + */ + @ReactMethod + public void measureLayout( + int tag, int ancestorTag, Callback errorCallback, Callback successCallback) { + super.measureLayout(tag, ancestorTag, errorCallback, successCallback); + } + + /** + * Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent. + * + *

NB: Unlike {@link #measure}, this will measure relative to the view layout, not the visible + * window which can cause unexpected results when measuring relative to things like ScrollViews + * that can have offset content on the screen. + * + * @deprecated this method will not be available in FabricUIManager class. + */ + @ReactMethod + @Deprecated + public void measureLayoutRelativeToParent( + int tag, Callback errorCallback, Callback successCallback) { + super.measureLayoutRelativeToParent(tag, errorCallback, successCallback); + } + + /** + * Find the touch target child native view in the supplied root view hierarchy, given a react + * target location. + * + *

This method is currently used only by Element Inspector DevTool. + * + * @param reactTag the tag of the root view to traverse + * @param point an array containing both X and Y target location + * @param callback will be called if with the identified child view react ID, and measurement + * info. If no view was found, callback will be invoked with no data. + */ + @ReactMethod + public void findSubviewIn( + final int reactTag, final ReadableArray point, final Callback callback) { + super.findSubviewIn(reactTag, point, callback); + } + + /** + * Check if the first shadow node is the descendant of the second shadow node + * + * @deprecated this method will not be available in FabricUIManager class. + */ + @ReactMethod + @Deprecated + public void viewIsDescendantOf( + final int reactTag, final int ancestorReactTag, final Callback callback) { + super.viewIsDescendantOf(reactTag, ancestorReactTag, callback); + } + + @ReactMethod + public void setJSResponder(int reactTag, boolean blockNativeResponder) { + super.setJSResponder(reactTag, blockNativeResponder); + } + + @ReactMethod + public void clearJSResponder() { + super.clearJSResponder(); + } + + @ReactMethod + public void dispatchViewManagerCommand( + int reactTag, Dynamic commandId, @Nullable ReadableArray commandArgs) { + super.dispatchViewManagerCommand(reactTag, commandId, commandArgs); + } + + /** + * Show a PopupMenu. + * + * @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this + * needs to be the tag of a native view (shadow views can not be anchors) + * @param items the menu items as an array of strings + * @param error will be called if there is an error displaying the menu + * @param success will be called with the position of the selected item as the first argument, or + * no arguments if the menu is dismissed + */ + @ReactMethod + public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) { + super.showPopupMenu(reactTag, items, error, success); + } + + @ReactMethod + public void dismissPopupMenu() { + super.dismissPopupMenu(); + } + + /** + * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled + * explicitly in order to avoid regression in existing application written for iOS using this API. + * + *

Warning : This method will be removed in future version of React Native, and layout + * animation will be enabled by default, so always check for its existence before invoking it. + * + *

TODO(9139831) : remove this method once layout animation is fully stable. + * + * @param enabled whether layout animation is enabled or not + */ + @ReactMethod + public void setLayoutAnimationEnabledExperimental(boolean enabled) { + super.setLayoutAnimationEnabledExperimental(enabled); + } + + /** + * Configure an animation to be used for the native layout changes, and native views creation. The + * animation will only apply during the current batch operations. + * + *

TODO(7728153) : animating view deletion is currently not supported. + * + * @param config the configuration of the animation for view addition/removal/update. + * @param success will be called when the animation completes, or when the animation get + * interrupted. In this case, callback parameter will be false. + * @param error will be called if there was an error processing the animation + */ + @ReactMethod + public void configureNextLayoutAnimation(ReadableMap config, Callback success, Callback error) { + super.configureNextLayoutAnimation(config, success, error); + } + + @ReactMethod + public void sendAccessibilityEvent(int tag, int eventType) { + super.sendAccessibilityEvent(tag, eventType); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/UIImplementation/64/com/swmansion/reanimated/layoutReanimation/ReanimatedUIImplementation.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/UIImplementation/64/com/swmansion/reanimated/layoutReanimation/ReanimatedUIImplementation.java new file mode 100644 index 00000000000000..dc8de3f76a2a01 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/UIImplementation/64/com/swmansion/reanimated/layoutReanimation/ReanimatedUIImplementation.java @@ -0,0 +1,68 @@ +package abi49_0_0.com.facebook.react.uimanager; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.ReanimatedNativeHierarchyManager; +import java.util.List; + +public class ReanimatedUIImplementation extends UIImplementation { + public ReanimatedUIImplementation( + ReactApplicationContext reactContext, + UIManagerModule.ViewManagerResolver viewManagerResolver, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + this( + reactContext, + new ViewManagerRegistry(viewManagerResolver), + eventDispatcher, + minTimeLeftInFrameForNonBatchedOperationMs); + } + + public ReanimatedUIImplementation( + ReactApplicationContext reactContext, + List viewManagerList, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + this( + reactContext, + new ViewManagerRegistry(viewManagerList), + eventDispatcher, + minTimeLeftInFrameForNonBatchedOperationMs); + } + + public ReanimatedUIImplementation( + ReactApplicationContext reactContext, + ViewManagerRegistry viewManagerRegistry, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + super( + reactContext, + viewManagerRegistry, + new UIViewOperationQueue( + reactContext, + new ReanimatedNativeHierarchyManager(viewManagerRegistry, reactContext), + minTimeLeftInFrameForNonBatchedOperationMs), + eventDispatcher); + } + + /** + * Invoked when there is a mutation in a node tree. + * + * @param tag react tag of the node we want to manage + * @param indicesToRemove ordered (asc) list of indicies at which view should be removed + * @param viewsToAdd ordered (asc based on mIndex property) list of tag-index pairs that represent + * a view which should be added at the specified index + * @param tagsToDelete list of tags corresponding to views that should be removed + */ + public void manageChildren( + int viewTag, + @Nullable ReadableArray moveFrom, + @Nullable ReadableArray moveTo, + @Nullable ReadableArray addChildTags, + @Nullable ReadableArray addAtIndices, + @Nullable ReadableArray removeFrom) { + super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/UIImplementation/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedUIImplementation.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/UIImplementation/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedUIImplementation.java new file mode 100644 index 00000000000000..a7c680e0f1cf5a --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/UIImplementation/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedUIImplementation.java @@ -0,0 +1,68 @@ +package abi49_0_0.com.facebook.react.uimanager; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher; +import abi49_0_0.com.swmansion.reanimated.layoutReanimation.ReanimatedNativeHierarchyManager; +import java.util.List; + +public class ReanimatedUIImplementation extends UIImplementation { + public ReanimatedUIImplementation( + ReactApplicationContext reactContext, + ViewManagerResolver viewManagerResolver, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + this( + reactContext, + new ViewManagerRegistry(viewManagerResolver), + eventDispatcher, + minTimeLeftInFrameForNonBatchedOperationMs); + } + + public ReanimatedUIImplementation( + ReactApplicationContext reactContext, + List viewManagerList, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + this( + reactContext, + new ViewManagerRegistry(viewManagerList), + eventDispatcher, + minTimeLeftInFrameForNonBatchedOperationMs); + } + + public ReanimatedUIImplementation( + ReactApplicationContext reactContext, + ViewManagerRegistry viewManagerRegistry, + EventDispatcher eventDispatcher, + int minTimeLeftInFrameForNonBatchedOperationMs) { + super( + reactContext, + viewManagerRegistry, + new UIViewOperationQueue( + reactContext, + new ReanimatedNativeHierarchyManager(viewManagerRegistry, reactContext), + minTimeLeftInFrameForNonBatchedOperationMs), + eventDispatcher); + } + + /** + * Invoked when there is a mutation in a node tree. + * + * @param tag react tag of the node we want to manage + * @param indicesToRemove ordered (asc) list of indicies at which view should be removed + * @param viewsToAdd ordered (asc based on mIndex property) list of tag-index pairs that represent + * a view which should be added at the specified index + * @param tagsToDelete list of tags corresponding to views that should be removed + */ + public void manageChildren( + int viewTag, + @Nullable ReadableArray moveFrom, + @Nullable ReadableArray moveTo, + @Nullable ReadableArray addChildTags, + @Nullable ReadableArray addAtIndices, + @Nullable ReadableArray removeFrom) { + super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/messageQueueThread/67/com/swmansion/reanimated/ReanimatedMessageQueueThread.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/messageQueueThread/67/com/swmansion/reanimated/ReanimatedMessageQueueThread.java new file mode 100644 index 00000000000000..fed658de13bd2d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/messageQueueThread/67/com/swmansion/reanimated/ReanimatedMessageQueueThread.java @@ -0,0 +1,12 @@ +package abi49_0_0.com.swmansion.reanimated; + +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.swmansion.reanimated.ReanimatedMessageQueueThreadBase; + +@DoNotStrip +public class ReanimatedMessageQueueThread extends ReanimatedMessageQueueThreadBase { + @Override + public void runOnQueue(Runnable runnable) { + messageQueueThread.runOnQueue(runnable); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/messageQueueThread/latest/com/swmansion/reanimated/ReanimatedMessageQueueThread.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/messageQueueThread/latest/com/swmansion/reanimated/ReanimatedMessageQueueThread.java new file mode 100644 index 00000000000000..510cdc29469ba9 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/messageQueueThread/latest/com/swmansion/reanimated/ReanimatedMessageQueueThread.java @@ -0,0 +1,12 @@ +package abi49_0_0.com.swmansion.reanimated; + +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.swmansion.reanimated.ReanimatedMessageQueueThreadBase; + +@DoNotStrip +public class ReanimatedMessageQueueThread extends ReanimatedMessageQueueThreadBase { + @Override + public boolean runOnQueue(Runnable runnable) { + return messageQueueThread.runOnQueue(runnable); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/nativeHierarchyManager/62/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/nativeHierarchyManager/62/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java new file mode 100644 index 00000000000000..548618743de412 --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/nativeHierarchyManager/62/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java @@ -0,0 +1,376 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.os.Build; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyManager; +import abi49_0_0.com.facebook.react.uimanager.RootViewManager; +import abi49_0_0.com.facebook.react.uimanager.ViewAtIndex; +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManagerRegistry; +import abi49_0_0.com.facebook.react.uimanager.layoutanimation.LayoutAnimationController; +import abi49_0_0.com.facebook.react.uimanager.layoutanimation.LayoutAnimationListener; +import abi49_0_0.com.swmansion.reanimated.ReanimatedModule; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +class ReaLayoutAnimator extends LayoutAnimationController { + private AnimationsManager mAnimationsManager = null; + private volatile boolean mInitialized = false; + private ReactApplicationContext mContext; + private WeakReference mWeakNativeViewHierarchyManager = + new WeakReference<>(null); + + ReaLayoutAnimator( + ReactApplicationContext context, NativeViewHierarchyManager nativeViewHierarchyManager) { + mContext = context; + mWeakNativeViewHierarchyManager = new WeakReference<>(nativeViewHierarchyManager); + } + + public void maybeInit() { + if (!mInitialized) { + mInitialized = true; + ReanimatedModule reanimatedModule = mContext.getNativeModule(ReanimatedModule.class); + mAnimationsManager = reanimatedModule.getNodesManager().getAnimationsManager(); + mAnimationsManager.setReanimatedNativeHierarchyManager( + (ReanimatedNativeHierarchyManager) mWeakNativeViewHierarchyManager.get()); + } + } + + public boolean shouldAnimateLayout(View viewToAnimate) { + if (!isLayoutAnimationEnabled()) { + return super.shouldAnimateLayout(viewToAnimate); + } + // if view parent is null, skip animation: view have been clipped, we don't want animation to + // resume when view is re-attached to parent, which is the standard android animation behavior. + // If there's a layout handling animation going on, it should be animated nonetheless since the + // ongoing animation needs to be updated. + if (viewToAnimate == null) { + return false; + } + return (viewToAnimate.getParent() != null); + } + + /** + * Update layout of given view, via immediate update or animation depending on the current batch + * layout animation configuration supplied during initialization. Handles create and update + * animations. + * + * @param view the view to update layout of + * @param x the new X position for the view + * @param y the new Y position for the view + * @param width the new width value for the view + * @param height the new height value for the view + */ + public void applyLayoutUpdate(View view, int x, int y, int width, int height) { + if (!isLayoutAnimationEnabled()) { + super.applyLayoutUpdate(view, x, y, width, height); + return; + } + UiThreadUtil.assertOnUiThread(); + maybeInit(); + // Determine which animation to use : if view is initially invisible, use create animation, + // otherwise use update animation. This approach is easier than maintaining a list of tags + // for recently created views. + if (view.getWidth() == 0 || view.getHeight() == 0) { + view.layout(x, y, x + width, y + height); + if (view.getId() != -1) { + mAnimationsManager.onViewCreate( + view, + (ViewGroup) view.getParent(), + new Snapshot(view, mWeakNativeViewHierarchyManager.get())); + } + } else { + Snapshot before = new Snapshot(view, mWeakNativeViewHierarchyManager.get()); + view.layout(x, y, x + width, y + height); + Snapshot after = new Snapshot(view, mWeakNativeViewHierarchyManager.get()); + mAnimationsManager.onViewUpdate(view, before, after); + } + } + + /** + * Animate a view deletion using the layout animation configuration supplied during + * initialization. + * + * @param view The view to animate. + * @param listener Called once the animation is finished, should be used to completely remove the + * view. + */ + public void deleteView(final View view, final LayoutAnimationListener listener) { + if (!isLayoutAnimationEnabled()) { + super.deleteView(view, listener); + return; + } + UiThreadUtil.assertOnUiThread(); + NativeViewHierarchyManager nativeViewHierarchyManager = mWeakNativeViewHierarchyManager.get(); + ViewManager viewManager; + try { + viewManager = nativeViewHierarchyManager.resolveViewManager(view.getId()); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + super.deleteView(view, listener); + return; + } + // we don't want layout animations in native-stack since it is currently buggy there + // so we check if it is a (grand)child of ScreenStack + if (viewManager.getName().equals("RNSScreen") + && view.getParent() != null + && view.getParent().getParent() instanceof View) { + // we check grandparent of Screen since the parent is a ScreenStackFragment + View screenParentView = (View) view.getParent().getParent(); + ViewManager screenParentViewManager; + try { + screenParentViewManager = + nativeViewHierarchyManager.resolveViewManager(screenParentView.getId()); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + super.deleteView(view, listener); + return; + } + String parentName = screenParentViewManager.getName(); + if (parentName.equals("RNSScreenStack")) { + super.deleteView(view, listener); + return; + } + } + maybeInit(); + Snapshot before = new Snapshot(view, mWeakNativeViewHierarchyManager.get()); + mAnimationsManager.onViewRemoval( + view, (ViewGroup) view.getParent(), before, () -> listener.onAnimationEnd()); + } + + public boolean isLayoutAnimationEnabled() { + maybeInit(); + return mAnimationsManager.isLayoutAnimationEnabled(); + } +} + +public class ReanimatedNativeHierarchyManager extends NativeViewHierarchyManager { + private final HashMap> toBeRemoved = new HashMap<>(); + private final HashMap cleanerCallback = new HashMap<>(); + private LayoutAnimationController mReaLayoutAnimator = null; + private HashMap> mPendingDeletionsForTag = new HashMap<>(); + private boolean initOk = true; + + public ReanimatedNativeHierarchyManager( + ViewManagerRegistry viewManagers, ReactApplicationContext reactContext) { + super(viewManagers); + + mReaLayoutAnimator = new ReaLayoutAnimator(reactContext, this); + + Class clazz = this.getClass().getSuperclass(); + if (clazz == null) { + Log.e("reanimated", "unable to resolve super class of ReanimatedNativeHierarchyManager"); + return; + } + + try { + Field layoutAnimatorField = clazz.getDeclaredField("mLayoutAnimator"); + layoutAnimatorField.setAccessible(true); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + // accessFlags is supported only by API >=23 + Field modifiersField = Field.class.getDeclaredField("accessFlags"); + modifiersField.setAccessible(true); + modifiersField.setInt( + layoutAnimatorField, layoutAnimatorField.getModifiers() & ~Modifier.FINAL); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + layoutAnimatorField.set(this, mReaLayoutAnimator); + } catch (NoSuchFieldException | IllegalAccessException e) { + initOk = false; + e.printStackTrace(); + } + + try { + Field pendingTagsField = clazz.getDeclaredField("mPendingDeletionsForTag"); + pendingTagsField.setAccessible(true); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + // accessFlags is supported only by API >=23 + Field pendingTagsFieldModifiers = Field.class.getDeclaredField("accessFlags"); + pendingTagsFieldModifiers.setAccessible(true); + pendingTagsFieldModifiers.setInt( + pendingTagsField, pendingTagsField.getModifiers() & ~Modifier.FINAL); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + pendingTagsField.set(this, mPendingDeletionsForTag); + } catch (NoSuchFieldException | IllegalAccessException e) { + initOk = false; + e.printStackTrace(); + } + + if (initOk) { + setLayoutAnimationEnabled(true); + } + } + + public ReanimatedNativeHierarchyManager( + ViewManagerRegistry viewManagers, RootViewManager manager) { + super(viewManagers, manager); + } + + private boolean isLayoutAnimationDisabled() { + return !initOk || !((ReaLayoutAnimator) mReaLayoutAnimator).isLayoutAnimationEnabled(); + } + + public synchronized void updateLayout( + int parentTag, int tag, int x, int y, int width, int height) { + super.updateLayout(parentTag, tag, x, y, width, height); + if (isLayoutAnimationDisabled()) { + return; + } + try { + View viewToUpdate = this.resolveView(tag); + ViewManager viewManager = this.resolveViewManager(tag); + String viewManagerName = viewManager.getName(); + View container = resolveView(parentTag); + if (container != null + && viewManagerName.equals("RNSScreen") + && this.mReaLayoutAnimator != null) { + this.mReaLayoutAnimator.applyLayoutUpdate( + viewToUpdate, + (int) container.getX(), + (int) container.getY(), + container.getWidth(), + container.getHeight()); + } + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + } + } + + // @Override + public synchronized void manageChildren( + int tag, + @Nullable int[] indicesToRemove, + @Nullable ViewAtIndex[] viewsToAdd, + @Nullable int[] tagsToDelete) { + int[] mock = new int[] {}; + if (isLayoutAnimationDisabled()) { + super.manageChildren(tag, indicesToRemove, viewsToAdd, tagsToDelete, mock); + return; + } + ViewGroup viewGroup; + ViewGroupManager viewGroupManager; + try { + viewGroup = (ViewGroup) resolveView(tag); + viewGroupManager = (ViewGroupManager) resolveViewManager(tag); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + super.manageChildren(tag, indicesToRemove, viewsToAdd, tagsToDelete, mock); + return; + } + + // we don't want layout animations in native-stack since it is currently buggy there + if (viewGroupManager.getName().equals("RNSScreenStack")) { + super.manageChildren(tag, indicesToRemove, viewsToAdd, tagsToDelete, mock); + return; + } + + if (toBeRemoved.containsKey(tag)) { + ArrayList childrenToBeRemoved = toBeRemoved.get(tag); + HashSet tagsToRemove = new HashSet(); + for (View childToRemove : childrenToBeRemoved) { + tagsToRemove.add(childToRemove.getId()); + } + while (viewGroupManager.getChildCount(viewGroup) != 0) { + View child = + viewGroupManager.getChildAt(viewGroup, viewGroupManager.getChildCount(viewGroup) - 1); + if (tagsToRemove.contains(child.getId())) { + viewGroupManager.removeViewAt(viewGroup, viewGroupManager.getChildCount(viewGroup) - 1); + } else { + break; + } + } + } + if (tagsToDelete != null) { + if (!toBeRemoved.containsKey(tag)) { + toBeRemoved.put(tag, new ArrayList<>()); + } + ArrayList toBeRemovedChildren = toBeRemoved.get(tag); + for (Integer childtag : tagsToDelete) { + View view; + try { + view = resolveView(childtag); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + continue; + } + toBeRemovedChildren.add(view); + cleanerCallback.put( + view.getId(), + new Runnable() { + @Override + public void run() { + toBeRemovedChildren.remove(view); + viewGroupManager.removeView(viewGroup, view); + } // It's far from optimal but let's leave it as it is for now + }); + } + } + + // mPendingDeletionsForTag is modify by React + if (mPendingDeletionsForTag != null) { + Set pendingTags = mPendingDeletionsForTag.get(tag); + if (pendingTags != null) { + pendingTags.clear(); + } + } + + super.manageChildren(tag, indicesToRemove, viewsToAdd, mock, mock); + if (toBeRemoved.containsKey(tag)) { + ArrayList childrenToBeRemoved = toBeRemoved.get(tag); + for (View child : childrenToBeRemoved) { + viewGroupManager.addView(viewGroup, child, viewGroupManager.getChildCount(viewGroup)); + } + } + ViewAtIndex[] mock2 = new ViewAtIndex[] {}; + super.manageChildren(tag, mock, mock2, tagsToDelete, mock); + } + + public void publicDropView(View view) { + dropView(view); + } + + @Override + protected synchronized void dropView(View view) { + if (isLayoutAnimationDisabled()) { + super.dropView(view); + return; + } + if (toBeRemoved.containsKey(view.getId())) { + toBeRemoved.remove(view.getId()); + } + if (cleanerCallback.containsKey(view.getId())) { + Runnable runnable = cleanerCallback.get(view.getId()); + cleanerCallback.remove(view.getId()); + runnable.run(); + } + // childrens' callbacks should be cleaned by former publicDropView calls as Animation Manager + // stripes views from bottom to top + super.dropView(view); + } +} diff --git a/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/nativeHierarchyManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/nativeHierarchyManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java new file mode 100644 index 00000000000000..a7f53bb0c5da2d --- /dev/null +++ b/android/vendored/sdk49/react-native-reanimated/android/src/reactNativeVersionPatch/nativeHierarchyManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java @@ -0,0 +1,420 @@ +package abi49_0_0.com.swmansion.reanimated.layoutReanimation; + +import android.os.Build; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; + +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyManager; +import abi49_0_0.com.facebook.react.uimanager.ViewAtIndex; +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManagerRegistry; +import abi49_0_0.com.facebook.react.uimanager.layoutanimation.LayoutAnimationController; +import abi49_0_0.com.facebook.react.uimanager.layoutanimation.LayoutAnimationListener; +import abi49_0_0.com.swmansion.reanimated.ReanimatedModule; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +class ReaLayoutAnimator extends LayoutAnimationController { + private AnimationsManager mAnimationsManager = null; + private volatile boolean mInitialized = false; + private final ReactApplicationContext mContext; + private final WeakReference mWeakNativeViewHierarchyManager; + private final ArrayList viewsToSnapshot = new ArrayList<>(); + + ReaLayoutAnimator( + ReactApplicationContext context, NativeViewHierarchyManager nativeViewHierarchyManager) { + mContext = context; + mWeakNativeViewHierarchyManager = new WeakReference<>(nativeViewHierarchyManager); + } + + public void maybeInit() { + if (!mInitialized) { + mInitialized = true; + ReanimatedModule reanimatedModule = mContext.getNativeModule(ReanimatedModule.class); + mAnimationsManager = reanimatedModule.getNodesManager().getAnimationsManager(); + mAnimationsManager.setReanimatedNativeHierarchyManager( + (ReanimatedNativeHierarchyManager) mWeakNativeViewHierarchyManager.get()); + } + } + + public boolean shouldAnimateLayout(View viewToAnimate) { + if (!isLayoutAnimationEnabled()) { + return super.shouldAnimateLayout(viewToAnimate); + } + // if view parent is null, skip animation: view have been clipped, we don't want animation to + // resume when view is re-attached to parent, which is the standard android animation behavior. + // If there's a layout handling animation going on, it should be animated nonetheless since the + // ongoing animation needs to be updated. + if (viewToAnimate == null) { + return false; + } + return (viewToAnimate.getParent() != null); + } + + @Override + public void reset() { + super.reset(); + // we have to make snapshots of the views after all of them have updated layouts + // to have correct global coordinates in the snapshots + // we do it here because React calls reset() method after all views have updated layouts + // and there is no semantically valid place to do it + for(View view : viewsToSnapshot) { + mAnimationsManager.onViewCreate( + view, + (ViewGroup) view.getParent(), + new Snapshot(view, mWeakNativeViewHierarchyManager.get())); + } + viewsToSnapshot.clear(); + } + + /** + * Update layout of given view, via immediate update or animation depending on the current batch + * layout animation configuration supplied during initialization. Handles create and update + * animations. + * + * @param view the view to update layout of + * @param x the new X position for the view + * @param y the new Y position for the view + * @param width the new width value for the view + * @param height the new height value for the view + */ + public void applyLayoutUpdate(View view, int x, int y, int width, int height) { + if (!isLayoutAnimationEnabled()) { + super.applyLayoutUpdate(view, x, y, width, height); + return; + } + UiThreadUtil.assertOnUiThread(); + maybeInit(); + // Determine which animation to use : if view is initially invisible, use create animation, + // otherwise use update animation. This approach is easier than maintaining a list of tags + // for recently created views. + if (view.getWidth() == 0 || view.getHeight() == 0) { + if (!mAnimationsManager.hasAnimationForTag(view.getId(), LayoutAnimations.Types.ENTERING)) { + super.applyLayoutUpdate(view, x, y, width, height); + mAnimationsManager.maybeRegisterSharedView(view); + return; + } + view.layout(x, y, x + width, y + height); + if (view.getId() != -1) { + viewsToSnapshot.add(view); + } + return; + } + + Snapshot before = new Snapshot(view, mWeakNativeViewHierarchyManager.get()); + view.layout(x, y, x + width, y + height); + Snapshot after = new Snapshot(view, mWeakNativeViewHierarchyManager.get()); + mAnimationsManager.onViewUpdate(view, before, after); + } + + /** + * Animate a view deletion using the layout animation configuration supplied during + * initialization. + * + * @param view The view to animate. + * @param listener Called once the animation is finished, should be used to completely remove the + * view. + */ + public void deleteView(final View view, final LayoutAnimationListener listener) { + if (!isLayoutAnimationEnabled()) { + super.deleteView(view, listener); + return; + } + UiThreadUtil.assertOnUiThread(); + NativeViewHierarchyManager nativeViewHierarchyManager = mWeakNativeViewHierarchyManager.get(); + ViewManager viewManager; + try { + viewManager = nativeViewHierarchyManager.resolveViewManager(view.getId()); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + mAnimationsManager.cancelAnimationsInSubviews(view); + super.deleteView(view, listener); + return; + } + // we don't want layout animations in native-stack since it is currently buggy there + // so we check if it is a (grand)child of ScreenStack + if (viewManager.getName().equals("RNSScreen") + && view.getParent() != null + && view.getParent().getParent() instanceof View) { + // we check grandparent of Screen since the parent is a ScreenStackFragment + View screenParentView = (View) view.getParent().getParent(); + ViewManager screenParentViewManager; + try { + screenParentViewManager = + nativeViewHierarchyManager.resolveViewManager(screenParentView.getId()); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + mAnimationsManager.cancelAnimationsInSubviews(view); + super.deleteView(view, listener); + return; + } + String parentName = screenParentViewManager.getName(); + if (parentName.equals("RNSScreenStack")) { + mAnimationsManager.cancelAnimationsInSubviews(view); + super.deleteView(view, listener); + return; + } + } + maybeInit(); + mAnimationsManager.onViewRemoval( + view, (ViewGroup) view.getParent(), listener::onAnimationEnd); + } + + public boolean isLayoutAnimationEnabled() { + maybeInit(); + return mAnimationsManager.isLayoutAnimationEnabled(); + } + + public AnimationsManager getAnimationsManager() { + return mAnimationsManager; + } +} + +public class ReanimatedNativeHierarchyManager extends NativeViewHierarchyManager { + private final HashMap> toBeRemoved = new HashMap<>(); + private final HashMap cleanerCallback = new HashMap<>(); + private final ReaLayoutAnimator mReaLayoutAnimator; + private final HashMap> mPendingDeletionsForTag = new HashMap<>(); + private boolean initOk = true; + + public ReanimatedNativeHierarchyManager( + ViewManagerRegistry viewManagers, ReactApplicationContext reactContext) { + super(viewManagers); + + mReaLayoutAnimator = new ReaLayoutAnimator(reactContext, this); + + Class clazz = this.getClass().getSuperclass(); + if (clazz == null) { + Log.e("reanimated", "unable to resolve super class of ReanimatedNativeHierarchyManager"); + return; + } + + try { + Field layoutAnimatorField = clazz.getDeclaredField("mLayoutAnimator"); + layoutAnimatorField.setAccessible(true); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + // accessFlags is supported only by API >=23 + Field modifiersField = Field.class.getDeclaredField("accessFlags"); + modifiersField.setAccessible(true); + modifiersField.setInt( + layoutAnimatorField, layoutAnimatorField.getModifiers() & ~Modifier.FINAL); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + layoutAnimatorField.set(this, mReaLayoutAnimator); + } catch (NoSuchFieldException | IllegalAccessException e) { + initOk = false; + e.printStackTrace(); + } + + try { + Field pendingTagsField = clazz.getDeclaredField("mPendingDeletionsForTag"); + pendingTagsField.setAccessible(true); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + // accessFlags is supported only by API >=23 + Field pendingTagsFieldModifiers = Field.class.getDeclaredField("accessFlags"); + pendingTagsFieldModifiers.setAccessible(true); + pendingTagsFieldModifiers.setInt( + pendingTagsField, pendingTagsField.getModifiers() & ~Modifier.FINAL); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + pendingTagsField.set(this, mPendingDeletionsForTag); + } catch (NoSuchFieldException | IllegalAccessException e) { + initOk = false; + e.printStackTrace(); + } + + if (initOk) { + setLayoutAnimationEnabled(true); + } + } + + private boolean isLayoutAnimationDisabled() { + return !initOk || !((ReaLayoutAnimator) mReaLayoutAnimator).isLayoutAnimationEnabled(); + } + + public synchronized void updateLayout( + int parentTag, int tag, int x, int y, int width, int height) { + super.updateLayout(parentTag, tag, x, y, width, height); + if (isLayoutAnimationDisabled()) { + return; + } + try { + ViewManager viewManager = resolveViewManager(tag); + String viewManagerName = viewManager.getName(); + View container = resolveView(parentTag); + if (container != null + && viewManagerName.equals("RNSScreen") + && mReaLayoutAnimator != null) { + boolean hasHeader = checkIfTopScreenHasHeader((ViewGroup) container); + if (!hasHeader || !container.isLayoutRequested()) { + mReaLayoutAnimator.getAnimationsManager().screenDidLayout(); + } + } + View view = resolveView(tag); + if (view != null && mReaLayoutAnimator != null) { + mReaLayoutAnimator.getAnimationsManager().viewDidLayout(view); + } + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + } + } + + private boolean checkIfTopScreenHasHeader(ViewGroup screenStack) { + try { + ViewGroup fragment = (ViewGroup)screenStack.getChildAt(0); + ViewGroup screen = (ViewGroup)fragment.getChildAt(0); + View headerConfig = screen.getChildAt(0); + Field field = headerConfig.getClass().getDeclaredField("mIsHidden"); + field.setAccessible(true); + return !field.getBoolean(headerConfig); + } catch (NullPointerException | NoSuchFieldException | IllegalAccessException e) { + return false; + } + } + + @Override + public synchronized void manageChildren( + int tag, + @Nullable int[] indicesToRemove, + @Nullable ViewAtIndex[] viewsToAdd, + @Nullable int[] tagsToDelete) { + if (isLayoutAnimationDisabled()) { + super.manageChildren(tag, indicesToRemove, viewsToAdd, tagsToDelete); + return; + } + ViewGroup viewGroup; + ViewGroupManager viewGroupManager; + try { + viewGroup = (ViewGroup) resolveView(tag); + viewGroupManager = (ViewGroupManager) resolveViewManager(tag); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + super.manageChildren(tag, indicesToRemove, viewsToAdd, tagsToDelete); + return; + } + + // we don't want layout animations in native-stack since it is currently buggy there + AnimationsManager animationsManager = mReaLayoutAnimator.getAnimationsManager(); + if (viewGroupManager.getName().equals("RNSScreenStack")) { + if (tagsToDelete == null) { + animationsManager.makeSnapshotOfTopScreenViews(viewGroup); + } else { + animationsManager.notifyAboutViewsRemoval(tagsToDelete); + } + if (indicesToRemove != null && mReaLayoutAnimator instanceof ReaLayoutAnimator) { + for (int index : indicesToRemove) { + View child = viewGroupManager.getChildAt(viewGroup, index); + mReaLayoutAnimator.getAnimationsManager().cancelAnimationsInSubviews(child); + } + } + super.manageChildren(tag, indicesToRemove, viewsToAdd, tagsToDelete); + return; + } + + if (toBeRemoved.containsKey(tag)) { + ArrayList childrenToBeRemoved = toBeRemoved.get(tag); + HashSet tagsToRemove = new HashSet(); + for (View childToRemove : childrenToBeRemoved) { + tagsToRemove.add(childToRemove.getId()); + } + while (viewGroupManager.getChildCount(viewGroup) != 0) { + View child = + viewGroupManager.getChildAt(viewGroup, viewGroupManager.getChildCount(viewGroup) - 1); + if (tagsToRemove.contains(child.getId())) { + viewGroupManager.removeViewAt(viewGroup, viewGroupManager.getChildCount(viewGroup) - 1); + } else { + break; + } + } + } + if (tagsToDelete != null) { + if (!toBeRemoved.containsKey(tag)) { + toBeRemoved.put(tag, new ArrayList<>()); + } + ArrayList toBeRemovedChildren = toBeRemoved.get(tag); + for (Integer childtag : tagsToDelete) { + View view; + try { + view = resolveView(childtag); + } catch (IllegalViewOperationException e) { + // (IllegalViewOperationException) == (vm == null) + e.printStackTrace(); + continue; + } + toBeRemovedChildren.add(view); + // It's far from optimal but let's leave it as it is for now + cleanerCallback.put( + view.getId(), + () -> { + toBeRemovedChildren.remove(view); + viewGroupManager.removeView(viewGroup, view); + }); + } + } + + // mPendingDeletionsForTag is modify by React + if (mPendingDeletionsForTag != null) { + Set pendingTags = mPendingDeletionsForTag.get(tag); + if (pendingTags != null) { + pendingTags.clear(); + } + } + animationsManager.notifyAboutViewsRemoval(tagsToDelete); + super.manageChildren(tag, indicesToRemove, viewsToAdd, null); + if (toBeRemoved.containsKey(tag)) { + ArrayList childrenToBeRemoved = toBeRemoved.get(tag); + for (View child : childrenToBeRemoved) { + viewGroupManager.addView(viewGroup, child, viewGroupManager.getChildCount(viewGroup)); + } + } + super.manageChildren(tag, null, null, tagsToDelete); + } + + public void publicDropView(View view) { + dropView(view); + } + + @Override + protected synchronized void dropView(View view) { + if (isLayoutAnimationDisabled()) { + super.dropView(view); + return; + } + if (toBeRemoved.containsKey(view.getId())) { + toBeRemoved.remove(view.getId()); + } + if (cleanerCallback.containsKey(view.getId())) { + Runnable runnable = cleanerCallback.get(view.getId()); + cleanerCallback.remove(view.getId()); + runnable.run(); + } + // childrens' callbacks should be cleaned by former publicDropView calls as Animation Manager + // stripes views from bottom to top + super.dropView(view); + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/build.gradle b/android/vendored/sdk49/react-native-screens/android/build.gradle new file mode 100644 index 00000000000000..e9ba75de3a1c8e --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/build.gradle @@ -0,0 +1,141 @@ +buildscript { + ext { + rnsDefaultTargetSdkVersion = 31 + rnsDefaultCompileSdkVersion = 31 + rnsDefaultMinSdkVersion = 21 + rnsDefaultKotlinVersion = '1.6.21' + } + ext.safeExtGet = {prop, fallback -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath('com.android.tools.build:gradle:4.2.2') + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', rnsDefaultKotlinVersion)}" + classpath "com.diffplug.spotless:spotless-plugin-gradle:5.15.0" + } +} + +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + +// spotless is only accessible within react-native-screens repo +if (project == rootProject) { + apply from: 'spotless.gradle' +} + +if (isNewArchitectureEnabled()) { + apply plugin: "com.facebook.react" +} +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +android { + compileSdkVersion safeExtGet('compileSdkVersion', rnsDefaultCompileSdkVersion) + def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION + if (agpVersion.tokenize('.')[0].toInteger() >= 7) { + namespace "abi49_0_0.com.swmansion.rnscreens" + } + + // Used to override the NDK path/version on internal CI or by allowing + // users to customize the NDK path/version from their root project (e.g. for M1 support) + if (rootProject.hasProperty("ndkPath")) { + ndkPath rootProject.ext.ndkPath + } + if (rootProject.hasProperty("ndkVersion")) { + ndkVersion rootProject.ext.ndkVersion + } + + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', rnsDefaultMinSdkVersion) + targetSdkVersion safeExtGet('targetSdkVersion', rnsDefaultTargetSdkVersion) + versionCode 1 + versionName "1.0" + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + ndk { + abiFilters (*reactNativeArchitectures()) + } + } + lintOptions { + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + packagingOptions { + // For some reason gradle only complains about the duplicated version of libreact_render libraries + // while there are more libraries copied in intermediates folder of the lib build directory, we exclude + // only the ones that make the build fail (ideally we should only include librnscreens_modules but we + // are only allowed to specify exclude patterns) + exclude "**/libreact_render*.so" + } + sourceSets.main { + ext.androidResDir = "src/main/res" + java { + if (isNewArchitectureEnabled()) { + srcDirs += [ + "src/fabric/java", + ] + } else { + srcDirs += [ + "src/paper/java", + "build/generated/source/codegen/java" + ] + } + + } + res { + if (safeExtGet('compileSdkVersion', rnsDefaultCompileSdkVersion) >= 33) { + srcDirs = ["${androidResDir}/base", "${androidResDir}/v33"] + } else { + srcDirs = ["${androidResDir}/base"] + } + } + } +} + +repositories { + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + // Matches the RN Hello World template + // https://github.com/facebook/versioned-react-native/packages/react-native/blob/1e8f3b11027fe0a7514b4fc97d0798d3c64bc895/local-cli/templates/HelloWorld/android/build.gradle#L21 + url "$projectDir/../node_modules/versioned-react-native/packages/react-native/android" + } + mavenCentral() + mavenLocal() + google() +} + +dependencies { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.fragment:fragment:1.2.1' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + implementation 'com.google.android.material:material:1.1.0' + implementation "androidx.core:core-ktx:1.5.0" +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/fabric/java/abi49_0_0/com/swmansion/rnscreens/FabricEnabledViewGroup.kt b/android/vendored/sdk49/react-native-screens/android/src/fabric/java/abi49_0_0/com/swmansion/rnscreens/FabricEnabledViewGroup.kt new file mode 100644 index 00000000000000..6603b4e17141d8 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/fabric/java/abi49_0_0/com/swmansion/rnscreens/FabricEnabledViewGroup.kt @@ -0,0 +1,49 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.view.ViewGroup +import androidx.annotation.UiThread +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.ReadableMap +import abi49_0_0.com.facebook.react.bridge.WritableMap +import abi49_0_0.com.facebook.react.bridge.WritableNativeMap +import abi49_0_0.com.facebook.react.uimanager.FabricViewStateManager +import abi49_0_0.com.facebook.react.uimanager.PixelUtil +import kotlin.math.abs + +abstract class FabricEnabledViewGroup constructor(context: ReactContext?) : ViewGroup(context), FabricViewStateManager.HasFabricViewStateManager { + private val mFabricViewStateManager: FabricViewStateManager = FabricViewStateManager() + + override fun getFabricViewStateManager(): FabricViewStateManager { + return mFabricViewStateManager + } + + protected fun updateScreenSizeFabric(width: Int, height: Int) { + updateState(width, height) + } + + @UiThread + fun updateState(width: Int, height: Int) { + val realWidth: Float = PixelUtil.toDIPFromPixel(width.toFloat()) + val realHeight: Float = PixelUtil.toDIPFromPixel(height.toFloat()) + + // Check incoming state values. If they're already the correct value, return early to prevent + // infinite UpdateState/SetState loop. + val currentState: ReadableMap? = mFabricViewStateManager.getStateData() + if (currentState != null) { + val delta = 0.9f + val stateFrameHeight: Float = if (currentState.hasKey("frameHeight")) currentState.getDouble("frameHeight").toFloat() else 0f + val stateFrameWidth: Float = if (currentState.hasKey("frameWidth")) currentState.getDouble("frameWidth").toFloat() else 0f + if (abs(stateFrameWidth - realWidth) < delta && + abs(stateFrameHeight - realHeight) < delta + ) { + return + } + } + mFabricViewStateManager.setState { + val map: WritableMap = WritableNativeMap() + map.putDouble("frameWidth", realWidth.toDouble()) + map.putDouble("frameHeight", realHeight.toDouble()) + map + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/react-native-screens/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..1d60eb3b613af5 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/CustomSearchView.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/CustomSearchView.kt new file mode 100644 index 00000000000000..da4069ec585ad7 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/CustomSearchView.kt @@ -0,0 +1,77 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.content.Context +import androidx.activity.OnBackPressedCallback +import androidx.appcompat.widget.SearchView +import androidx.fragment.app.Fragment + +class CustomSearchView(context: Context, fragment: Fragment) : SearchView(context) { + /* + CustomSearchView uses some variables from SearchView. They are listed below with links to documentation + isIconified - https://developer.android.com/reference/android/widget/SearchView#setIconified(boolean) + maxWidth - https://developer.android.com/reference/android/widget/SearchView#setMaxWidth(int) + setOnSearchClickListener - https://developer.android.com/reference/android/widget/SearchView#setOnSearchClickListener(android.view.View.OnClickListener) + setOnCloseListener - https://developer.android.com/reference/android/widget/SearchView#setOnCloseListener(android.widget.SearchView.OnCloseListener) + */ + private var mCustomOnCloseListener: OnCloseListener? = null + private var mCustomOnSearchClickedListener: OnClickListener? = null + + private var mOnBackPressedCallback: OnBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + isIconified = true + } + } + + private val backPressOverrider = FragmentBackPressOverrider(fragment, mOnBackPressedCallback) + + var overrideBackAction: Boolean + set(value) { + backPressOverrider.overrideBackAction = value + } + get() = backPressOverrider.overrideBackAction + + fun focus() { + isIconified = false + requestFocusFromTouch() + } + + fun clearText() = setQuery("", false) + + fun setText(text: String) = setQuery(text, false) + + override fun setOnCloseListener(listener: OnCloseListener?) { + mCustomOnCloseListener = listener + } + + override fun setOnSearchClickListener(listener: OnClickListener?) { + mCustomOnSearchClickedListener = listener + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (!isIconified) { + backPressOverrider.maybeAddBackCallback() + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + backPressOverrider.removeBackCallbackIfAdded() + } + + init { + super.setOnSearchClickListener { v -> + mCustomOnSearchClickedListener?.onClick(v) + backPressOverrider.maybeAddBackCallback() + } + + super.setOnCloseListener { + val result = mCustomOnCloseListener?.onClose() ?: false + backPressOverrider.removeBackCallbackIfAdded() + result + } + + maxWidth = Integer.MAX_VALUE + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/CustomToolbar.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/CustomToolbar.kt new file mode 100644 index 00000000000000..5d6645e0e831ea --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/CustomToolbar.kt @@ -0,0 +1,7 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.content.Context +import androidx.appcompat.widget.Toolbar + +// This class is used to store config closer to search bar +open class CustomToolbar(context: Context, val config: ScreenStackHeaderConfig) : Toolbar(context) diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/FragmentBackPressOverrider.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/FragmentBackPressOverrider.kt new file mode 100644 index 00000000000000..9607082a859030 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/FragmentBackPressOverrider.kt @@ -0,0 +1,29 @@ +package abi49_0_0.com.swmansion.rnscreens + +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment + +class FragmentBackPressOverrider( + private val fragment: Fragment, + private val mOnBackPressedCallback: OnBackPressedCallback +) { + private var mIsBackCallbackAdded: Boolean = false + var overrideBackAction: Boolean = true + + fun maybeAddBackCallback() { + if (!mIsBackCallbackAdded && overrideBackAction) { + fragment.activity?.onBackPressedDispatcher?.addCallback( + fragment, + mOnBackPressedCallback + ) + mIsBackCallbackAdded = true + } + } + + fun removeBackCallbackIfAdded() { + if (mIsBackCallbackAdded) { + mOnBackPressedCallback.remove() + mIsBackCallbackAdded = false + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/LifecycleHelper.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/LifecycleHelper.kt new file mode 100644 index 00000000000000..b033a4b6414f45 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/LifecycleHelper.kt @@ -0,0 +1,60 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.view.View +import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver + +class LifecycleHelper { + private val mViewToLifecycleMap: MutableMap = HashMap() + private val mRegisterOnLayoutChange: View.OnLayoutChangeListener = object : View.OnLayoutChangeListener { + override fun onLayoutChange( + view: View, + i: Int, + i1: Int, + i2: Int, + i3: Int, + i4: Int, + i5: Int, + i6: Int, + i7: Int + ) { + registerViewWithLifecycleOwner(view) + view.removeOnLayoutChangeListener(this) + } + } + + private fun registerViewWithLifecycleOwner(view: View) { + val parent = findNearestScreenFragmentAncestor(view) + if (parent != null && view is LifecycleObserver) { + val lifecycle = parent.lifecycle + lifecycle.addObserver((view as LifecycleObserver)) + mViewToLifecycleMap[view] = lifecycle + } + } + + fun register(view: T) where T : View, T : LifecycleObserver? { + // we need to wait until view is mounted in the hierarchy as this method is called only at the + // moment of the view creation. In order to register lifecycle observer we need to find ancestor + // of type Screen and this can only happen when the view is properly attached. We rely on + // Android's onLayout callback being triggered when the view gets added to the hierarchy and + // only then we attempt to locate lifecycle owner ancestor. + view.addOnLayoutChangeListener(mRegisterOnLayoutChange) + } + + fun unregister(view: T) where T : View, T : LifecycleObserver? { + mViewToLifecycleMap[view]?.removeObserver(view) + } + + companion object { + fun findNearestScreenFragmentAncestor(view: View): Fragment? { + var parent = view.parent + while (parent != null && parent !is Screen) { + parent = parent.parent + } + return if (parent != null) { + (parent as Screen).fragment + } else null + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/RNScreensPackage.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/RNScreensPackage.kt new file mode 100644 index 00000000000000..596e64d460e9b5 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/RNScreensPackage.kt @@ -0,0 +1,21 @@ +package abi49_0_0.com.swmansion.rnscreens + +import abi49_0_0.com.facebook.react.ReactPackage +import abi49_0_0.com.facebook.react.bridge.NativeModule +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.uimanager.ViewManager + +class RNScreensPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List = + emptyList() + + override fun createViewManagers(reactContext: ReactApplicationContext) = + listOf>( + ScreenContainerViewManager(), + ScreenViewManager(), + ScreenStackViewManager(), + ScreenStackHeaderConfigViewManager(), + ScreenStackHeaderSubviewManager(), + SearchBarManager() + ) +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/Screen.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/Screen.kt new file mode 100644 index 00000000000000..8dba10070b45b3 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/Screen.kt @@ -0,0 +1,258 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo +import android.graphics.Paint +import android.os.Parcelable +import android.util.SparseArray +import android.view.ViewGroup +import android.view.WindowManager +import android.webkit.WebView +import abi49_0_0.com.facebook.react.bridge.GuardedRunnable +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule + +@SuppressLint("ViewConstructor") +class Screen constructor(context: ReactContext?) : FabricEnabledViewGroup(context) { + + var fragment: ScreenFragment? = null + var container: ScreenContainer<*>? = null + var activityState: ActivityState? = null + private set + private var mTransitioning = false + var stackPresentation = StackPresentation.PUSH + var replaceAnimation = ReplaceAnimation.POP + var stackAnimation = StackAnimation.DEFAULT + var isGestureEnabled = true + var screenOrientation: Int? = null + private set + private var mStatusBarStyle: String? = null + private var mStatusBarHidden: Boolean? = null + private var mStatusBarTranslucent: Boolean? = null + private var mStatusBarColor: Int? = null + private var mNavigationBarColor: Int? = null + private var mNavigationBarHidden: Boolean? = null + var isStatusBarAnimated: Boolean? = null + private var mNativeBackButtonDismissalEnabled = true + + init { + // we set layout params as WindowManager.LayoutParams to workaround the issue with TextInputs + // not displaying modal menus (e.g., copy/paste or selection). The missing menus are due to the + // fact that TextView implementation is expected to be attached to window when layout happens. + // Then, at the moment of layout it checks whether window type is in a reasonable range to tell + // whether it should enable selection controls (see Editor.java#prepareCursorControllers). + // With screens, however, the text input component can be laid out before it is attached, in + // that case TextView tries to get window type property from the oldest existing parent, which + // in this case is a Screen class, as it is the root of the screen that is about to be attached. + // Setting params this way is not the most elegant way to solve this problem but workarounds it + // for the time being + layoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION) + } + + override fun dispatchSaveInstanceState(container: SparseArray) { + // do nothing, react native will keep the view hierarchy so no need to serialize/deserialize + // view's states. The side effect of restoring is that TextInput components would trigger + // set-text events which may confuse text input handling. + } + + override fun dispatchRestoreInstanceState(container: SparseArray) { + // ignore restoring instance state too as we are not saving anything anyways. + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + if (changed) { + val width = r - l + val height = b - t + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + updateScreenSizeFabric(width, height) + } else { + updateScreenSizePaper(width, height) + } + } + } + + private fun updateScreenSizePaper(width: Int, height: Int) { + val reactContext = context as ReactContext + reactContext.runOnNativeModulesQueueThread( + object : GuardedRunnable(reactContext) { + override fun runGuarded() { + reactContext + .getNativeModule(UIManagerModule::class.java) + ?.updateNodeSize(id, width, height) + } + }) + } + + val headerConfig: ScreenStackHeaderConfig? + get() = getChildAt(0) as? ScreenStackHeaderConfig + + /** + * While transitioning this property allows to optimize rendering behavior on Android and provide + * a correct blending options for the animated screen. It is turned on automatically by the + * container when transitioning is detected and turned off immediately after + */ + fun setTransitioning(transitioning: Boolean) { + if (mTransitioning == transitioning) { + return + } + mTransitioning = transitioning + val isWebViewInScreen = hasWebView(this) + if (isWebViewInScreen && layerType != LAYER_TYPE_HARDWARE) { + return + } + super.setLayerType( + if (transitioning && !isWebViewInScreen) LAYER_TYPE_HARDWARE else LAYER_TYPE_NONE, + null + ) + } + + private fun hasWebView(viewGroup: ViewGroup): Boolean { + for (i in 0 until viewGroup.childCount) { + val child = viewGroup.getChildAt(i) + if (child is WebView) { + return true + } else if (child is ViewGroup) { + if (hasWebView(child)) { + return true + } + } + } + return false + } + + override fun setLayerType(layerType: Int, paint: Paint?) { + // ignore - layer type is controlled by `transitioning` prop + } + + fun setActivityState(activityState: ActivityState) { + if (activityState == this.activityState) { + return + } + this.activityState = activityState + container?.notifyChildUpdate() + } + + fun setScreenOrientation(screenOrientation: String?) { + if (screenOrientation == null) { + this.screenOrientation = null + return + } + ScreenWindowTraits.applyDidSetOrientation() + this.screenOrientation = when (screenOrientation) { + "all" -> ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR + "portrait" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT + "portrait_up" -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + "portrait_down" -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT + "landscape" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE + "landscape_left" -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE + "landscape_right" -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + else -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + } + + fragment?.let { ScreenWindowTraits.setOrientation(this, it.tryGetActivity()) } + } + + // Accepts one of 4 accessibility flags + // developer.android.com/reference/android/view/View#attr_android:importantForAccessibility + fun changeAccessibilityMode(mode: Int) { + this.importantForAccessibility = mode + this.headerConfig?.toolbar?.importantForAccessibility = mode + } + + var statusBarStyle: String? + get() = mStatusBarStyle + set(statusBarStyle) { + if (statusBarStyle != null) { + ScreenWindowTraits.applyDidSetStatusBarAppearance() + } + mStatusBarStyle = statusBarStyle + fragment?.let { ScreenWindowTraits.setStyle(this, it.tryGetActivity(), it.tryGetContext()) } + } + + var isStatusBarHidden: Boolean? + get() = mStatusBarHidden + set(statusBarHidden) { + if (statusBarHidden != null) { + ScreenWindowTraits.applyDidSetStatusBarAppearance() + } + mStatusBarHidden = statusBarHidden + fragment?.let { ScreenWindowTraits.setHidden(this, it.tryGetActivity()) } + } + + var isStatusBarTranslucent: Boolean? + get() = mStatusBarTranslucent + set(statusBarTranslucent) { + if (statusBarTranslucent != null) { + ScreenWindowTraits.applyDidSetStatusBarAppearance() + } + mStatusBarTranslucent = statusBarTranslucent + fragment?.let { + ScreenWindowTraits.setTranslucent( + this, + it.tryGetActivity(), + it.tryGetContext() + ) + } + } + + var statusBarColor: Int? + get() = mStatusBarColor + set(statusBarColor) { + if (statusBarColor != null) { + ScreenWindowTraits.applyDidSetStatusBarAppearance() + } + mStatusBarColor = statusBarColor + fragment?.let { ScreenWindowTraits.setColor(this, it.tryGetActivity(), it.tryGetContext()) } + } + + var navigationBarColor: Int? + get() = mNavigationBarColor + set(navigationBarColor) { + if (navigationBarColor != null) { + ScreenWindowTraits.applyDidSetNavigationBarAppearance() + } + mNavigationBarColor = navigationBarColor + fragment?.let { ScreenWindowTraits.setNavigationBarColor(this, it.tryGetActivity()) } + } + + var isNavigationBarHidden: Boolean? + get() = mNavigationBarHidden + set(navigationBarHidden) { + if (navigationBarHidden != null) { + ScreenWindowTraits.applyDidSetNavigationBarAppearance() + } + mNavigationBarHidden = navigationBarHidden + fragment?.let { + ScreenWindowTraits.setNavigationBarHidden( + this, + it.tryGetActivity(), + ) + } + } + + var nativeBackButtonDismissalEnabled: Boolean + get() = mNativeBackButtonDismissalEnabled + set(enableNativeBackButtonDismissal) { + mNativeBackButtonDismissalEnabled = enableNativeBackButtonDismissal + } + + enum class StackPresentation { + PUSH, MODAL, TRANSPARENT_MODAL + } + + enum class StackAnimation { + DEFAULT, NONE, FADE, SLIDE_FROM_BOTTOM, SLIDE_FROM_RIGHT, SLIDE_FROM_LEFT, FADE_FROM_BOTTOM + } + + enum class ReplaceAnimation { + PUSH, POP + } + + enum class ActivityState { + INACTIVE, TRANSITIONING_OR_BELOW_TOP, ON_TOP + } + + enum class WindowTraits { + ORIENTATION, COLOR, STYLE, TRANSLUCENT, HIDDEN, ANIMATED, NAVIGATION_BAR_COLOR, NAVIGATION_BAR_HIDDEN + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenContainer.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenContainer.kt new file mode 100644 index 00000000000000..57fa3009477695 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenContainer.kt @@ -0,0 +1,373 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.content.Context +import android.content.ContextWrapper +import android.view.View +import android.view.ViewGroup +import android.view.ViewParent +import android.view.inputmethod.InputMethodManager +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import abi49_0_0.com.facebook.react.ReactRootView +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.modules.core.ChoreographerCompat +import abi49_0_0.com.facebook.react.modules.core.ReactChoreographer +import abi49_0_0.com.swmansion.rnscreens.Screen.ActivityState + +open class ScreenContainer(context: Context?) : ViewGroup(context) { + @JvmField + protected val mScreenFragments = ArrayList() + @JvmField + protected var mFragmentManager: FragmentManager? = null + private var mIsAttached = false + private var mNeedUpdate = false + private var mLayoutEnqueued = false + private val mLayoutCallback: ChoreographerCompat.FrameCallback = object : ChoreographerCompat.FrameCallback() { + override fun doFrame(frameTimeNanos: Long) { + mLayoutEnqueued = false + measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ) + layout(left, top, right, bottom) + } + } + private var mParentScreenFragment: ScreenFragment? = null + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + var i = 0 + val size = childCount + while (i < size) { + getChildAt(i).layout(0, 0, width, height) + i++ + } + } + + override fun removeView(view: View) { + // The below block is a workaround for an issue with keyboard handling within fragments. Despite + // Android handles input focus on the fragments that leave the screen, the keyboard stays open + // in a number of cases. The issue can be best reproduced on Android 5 devices, before some + // changes in Android's InputMethodManager have been introduced (specifically around dismissing + // the keyboard in onDetachedFromWindow). However, we also noticed the keyboard issue happen + // intermittently on recent versions of Android as well. The issue hasn't been previously + // noticed as in React Native <= 0.61 there was a logic that'd trigger keyboard dismiss upon a + // blur event (the blur even gets dispatched properly, the keyboard just stays open despite + // that) – note the change in RN core here: + // https://github.com/facebook/react-native/commit/e9b4928311513d3cbbd9d875827694eab6cfa932 + // The workaround is to force-hide keyboard when the screen that has focus is dismissed (we + // detect that in removeView as super.removeView causes the input view to un focus while keeping + // the keyboard open). + if (view === focusedChild) { + (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager) + .hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS) + } + super.removeView(view) + } + + override fun requestLayout() { + super.requestLayout() + @Suppress("SENSELESS_COMPARISON") // mLayoutCallback can be null here since this method can be called in init + if (!mLayoutEnqueued && mLayoutCallback != null) { + mLayoutEnqueued = true + // we use NATIVE_ANIMATED_MODULE choreographer queue because it allows us to catch the current + // looper loop instead of enqueueing the update in the next loop causing a one frame delay. + ReactChoreographer.getInstance() + .postFrameCallback( + ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, mLayoutCallback + ) + } + } + + val isNested: Boolean + get() = mParentScreenFragment != null + + fun notifyChildUpdate() { + performUpdatesNow() + } + + protected open fun adapt(screen: Screen): T { + @Suppress("UNCHECKED_CAST") + return ScreenFragment(screen) as T + } + + fun addScreen(screen: Screen, index: Int) { + val fragment = adapt(screen) + screen.fragment = fragment + mScreenFragments.add(index, fragment) + screen.container = this + onScreenChanged() + } + + open fun removeScreenAt(index: Int) { + mScreenFragments[index].screen.container = null + mScreenFragments.removeAt(index) + onScreenChanged() + } + + open fun removeAllScreens() { + for (screenFragment in mScreenFragments) { + screenFragment.screen.container = null + } + mScreenFragments.clear() + onScreenChanged() + } + + val screenCount: Int + get() = mScreenFragments.size + + fun getScreenAt(index: Int): Screen = mScreenFragments[index].screen + + open val topScreen: Screen? + get() = mScreenFragments.firstOrNull { getActivityState(it) === ActivityState.ON_TOP }?.screen + + private fun setFragmentManager(fm: FragmentManager) { + mFragmentManager = fm + performUpdatesNow() + } + + private fun findFragmentManagerForReactRootView(rootView: ReactRootView): FragmentManager { + var context = rootView.context + + // ReactRootView is expected to be initialized with the main React Activity as a context but + // in case of Expo the activity is wrapped in ContextWrapper and we need to unwrap it + while (context !is FragmentActivity && context is ContextWrapper) { + context = context.baseContext + } + + check(context is FragmentActivity) { + "In order to use RNScreens components your app's activity need to extend ReactActivity" + } + + // In case React Native is loaded on a Fragment (not directly in activity) we need to find + // fragment manager whose fragment's view is ReactRootView. As of now, we detect such case by + // checking whether any fragments are attached to activity which hosts ReactRootView. + // See: https://github.com/software-mansion/react-native-screens/issues/1506 on why the cases + // must be treated separately. + return if (context.supportFragmentManager.fragments.isEmpty()) { + // We are in standard React Native application w/o custom native navigation based on fragments. + context.supportFragmentManager + } else { + // We are in some custom setup & we want to use the closest fragment manager in hierarchy. + // `findFragment` method throws IllegalStateException when it fails to resolve appropriate + // fragment. It might happen when e.g. React Native is loaded directly in Activity + // but some custom fragments are still used. Such use case seems highly unlikely + // so, as for now we fallback to activity's FragmentManager in hope for the best. + try { + FragmentManager.findFragment(rootView).childFragmentManager + } catch (ex: IllegalStateException) { + context.supportFragmentManager + } + } + } + + private fun setupFragmentManager() { + var parent: ViewParent = this + // We traverse view hierarchy up until we find screen parent or a root view + while (!(parent is ReactRootView || parent is Screen) && + parent.parent != null + ) { + parent = parent.parent + } + // If parent is of type Screen it means we are inside a nested fragment structure. + // Otherwise we expect to connect directly with root view and get root fragment manager + if (parent is Screen) { + checkNotNull( + parent.fragment?.let { screenFragment -> + mParentScreenFragment = screenFragment + screenFragment.registerChildScreenContainer(this) + setFragmentManager(screenFragment.childFragmentManager) + } + ) { "Parent Screen does not have its Fragment attached" } + } else { + // we expect top level view to be of type ReactRootView, this isn't really necessary but in + // order to find root view we test if parent is null. This could potentially happen also when + // the view is detached from the hierarchy and that test would not correctly indicate the root + // view. So in order to make sure we indeed reached the root we test if it is of a correct type. + // This allows us to provide a more descriptive error message for the aforementioned case. + check(parent is ReactRootView) { "ScreenContainer is not attached under ReactRootView" } + setFragmentManager(findFragmentManagerForReactRootView(parent)) + } + } + + protected fun createTransaction(): FragmentTransaction { + return requireNotNull(mFragmentManager) { "mFragmentManager is null when creating transaction" } + .beginTransaction() + .setReorderingAllowed(true) + } + + private fun attachScreen(transaction: FragmentTransaction, screenFragment: ScreenFragment) { + transaction.add(id, screenFragment) + } + + private fun detachScreen(transaction: FragmentTransaction, screenFragment: ScreenFragment) { + transaction.remove(screenFragment) + } + + private fun getActivityState(screenFragment: ScreenFragment): ActivityState? = + screenFragment.screen.activityState + + open fun hasScreen(screenFragment: ScreenFragment?): Boolean = + mScreenFragments.contains(screenFragment) + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + mIsAttached = true + setupFragmentManager() + } + + /** Removes fragments from fragment manager that are attached to this container */ + private fun removeMyFragments(fragmentManager: FragmentManager) { + val transaction = fragmentManager.beginTransaction() + var hasFragments = false + for (fragment in fragmentManager.fragments) { + if (fragment is ScreenFragment && fragment.screen.container === this) { + transaction.remove(fragment) + hasFragments = true + } + } + + if (hasFragments) { + transaction.commitNowAllowingStateLoss() + } + } + + override fun onDetachedFromWindow() { + // if there are pending transactions and this view is about to get detached we need to perform + // them here as otherwise fragment manager will crash because it won't be able to find container + // view. We also need to make sure all the fragments attached to the given container are removed + // from fragment manager as in some cases fragment manager may be reused and in such case it'd + // attempt to reattach previously registered fragments that are not removed + mFragmentManager?.let { + if (!it.isDestroyed) { + removeMyFragments(it) + it.executePendingTransactions() + } + } + + mParentScreenFragment?.unregisterChildScreenContainer(this) + mParentScreenFragment = null + + super.onDetachedFromWindow() + mIsAttached = false + // When fragment container view is detached we force all its children to be removed. + // It is because children screens are controlled by their fragments, which can often have a + // delayed lifecycle (due to transitions). As a result due to ongoing transitions the fragment + // may choose not to remove the view despite the parent container being completely detached + // from the view hierarchy until the transition is over. In such a case when the container gets + // re-attached while the transition is ongoing, the child view would still be there and we'd + // attempt to re-attach it to with a misconfigured fragment. This would result in a crash. To + // avoid it we clear all the children here as we attach all the child fragments when the + // container is reattached anyways. We don't use `removeAllViews` since it does not check if the + // children are not already detached, which may lead to calling `onDetachedFromWindow` on them + // twice. + // We also get the size earlier, because we will be removing child views in `for` loop. + for (i in childCount - 1 downTo 0) { + removeViewAt(i) + } + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + for (i in 0 until childCount) { + getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec) + } + } + + private fun onScreenChanged() { + // we perform update in `onBeforeLayout` of `ScreensShadowNode` by adding an UIBlock + // which is called after updating children of the ScreenContainer. + // We do it there because `onUpdate` logic requires all changes of children to be already + // made in order to provide proper animation for fragment transition for ScreenStack + // and this in turn makes nested ScreenContainers detach too early and disappear + // before transition if also not dispatched after children updates. + // The exception to this rule is `updateImmediately` which is triggered by actions + // not connected to React view hierarchy changes, but rather internal events + mNeedUpdate = true + (context as? ReactContext)?.runOnUiQueueThread { + // We schedule the update here because LayoutAnimations of `react-native-reanimated` + // sometimes attach/detach screens after the layout block of `ScreensShadowNode` has + // already run, and we want to update the container then too. In the other cases, + // this code will do nothing since it will run after the UIBlock when `mNeedUpdate` + // will already be false. + performUpdates() + } + } + + protected fun performUpdatesNow() { + // we want to update immediately when the fragment manager is set or native back button + // dismiss is dispatched or Screen's activityState changes since it is not connected to React + // view hierarchy changes and will not trigger `onBeforeLayout` method of `ScreensShadowNode` + mNeedUpdate = true + performUpdates() + } + + fun performUpdates() { + if (!mNeedUpdate || !mIsAttached || mFragmentManager == null || mFragmentManager?.isDestroyed == true) { + return + } + mNeedUpdate = false + onUpdate() + notifyContainerUpdate() + } + + open fun onUpdate() { + createTransaction().let { + // detach screens that are no longer active + val orphaned: MutableSet = HashSet( + requireNotNull(mFragmentManager) { + "mFragmentManager is null when performing update in ScreenContainer" + }.fragments + ) + for (screenFragment in mScreenFragments) { + if (getActivityState(screenFragment) === ActivityState.INACTIVE && + screenFragment.isAdded + ) { + detachScreen(it, screenFragment) + } + orphaned.remove(screenFragment) + } + if (orphaned.isNotEmpty()) { + val orphanedAry = orphaned.toTypedArray() + for (fragment in orphanedAry) { + if (fragment is ScreenFragment) { + if (fragment.screen.container == null) { + detachScreen(it, fragment) + } + } + } + } + + // if there is an "onTop" screen it means the transition has ended + val transitioning = topScreen == null + + // attach newly activated screens + var addedBefore = false + val pendingFront: ArrayList = ArrayList() + + for (screenFragment in mScreenFragments) { + val activityState = getActivityState(screenFragment) + if (activityState !== ActivityState.INACTIVE && !screenFragment.isAdded) { + addedBefore = true + attachScreen(it, screenFragment) + } else if (activityState !== ActivityState.INACTIVE && addedBefore) { + // we detach the screen and then reattach it later to make it appear on front + detachScreen(it, screenFragment) + pendingFront.add(screenFragment) + } + screenFragment.screen.setTransitioning(transitioning) + } + + for (screenFragment in pendingFront) { + attachScreen(it, screenFragment) + } + + it.commitNowAllowingStateLoss() + } + } + + protected open fun notifyContainerUpdate() { + topScreen?.fragment?.onContainerUpdate() + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenContainerViewManager.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenContainerViewManager.kt new file mode 100644 index 00000000000000..963f4ae7af9b6f --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenContainerViewManager.kt @@ -0,0 +1,40 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.view.View +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.LayoutShadowNode +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager + +@ReactModule(name = ScreenContainerViewManager.REACT_CLASS) +class ScreenContainerViewManager : ViewGroupManager>() { + override fun getName(): String = REACT_CLASS + + override fun createViewInstance(reactContext: ThemedReactContext): ScreenContainer = ScreenContainer(reactContext) + + override fun addView(parent: ScreenContainer<*>, child: View, index: Int) { + require(child is Screen) { "Attempt attach child that is not of type RNScreens" } + parent.addScreen(child, index) + } + + override fun removeViewAt(parent: ScreenContainer<*>, index: Int) { + parent.removeScreenAt(index) + } + + override fun removeAllViews(parent: ScreenContainer<*>) { + parent.removeAllScreens() + } + + override fun getChildCount(parent: ScreenContainer<*>): Int = parent.screenCount + + override fun getChildAt(parent: ScreenContainer<*>, index: Int): View = parent.getScreenAt(index) + + override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode = ScreensShadowNode(context) + + override fun needsCustomLayoutForChildren(): Boolean = true + + companion object { + const val REACT_CLASS = "RNSScreenContainer" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenFragment.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenFragment.kt new file mode 100644 index 00000000000000..af48b6e2202c5f --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenFragment.kt @@ -0,0 +1,323 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewParent +import android.widget.FrameLayout +import androidx.fragment.app.Fragment +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher +import abi49_0_0.com.swmansion.rnscreens.events.HeaderBackButtonClickedEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenAppearEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenDisappearEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenDismissedEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenTransitionProgressEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenWillAppearEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenWillDisappearEvent +import kotlin.math.max +import kotlin.math.min + +open class ScreenFragment : Fragment { + enum class ScreenLifecycleEvent { + Appear, WillAppear, Disappear, WillDisappear + } + + // if we call empty constructor, there is no screen to be assigned so not sure why it is suggested + @Suppress("JoinDeclarationAndAssignment") + lateinit var screen: Screen + private val mChildScreenContainers: MutableList> = ArrayList() + private var shouldUpdateOnResume = false + // if we don't set it, it will be 0.0f at the beginning so the progress will not be sent + // due to progress value being already 0.0f + private var mProgress = -1f + + // those 2 vars are needed since sometimes the events would be dispatched twice in child containers + // (should only happen if parent has `NONE` animation) and we don't need too complicated logic. + // We just check if, after the event was dispatched, its "counter-event" has been also dispatched before sending the same event again. + // We do it for 'willAppear' -> 'willDisappear' and 'appear' -> 'disappear' + private var canDispatchWillAppear = true + private var canDispatchAppear = true + + // we want to know if we are currently transitioning in order not to fire lifecycle events + // in nested fragments. See more explanation in dispatchViewAnimationEvent + private var isTransitioning = false + + constructor() { + throw IllegalStateException( + "Screen fragments should never be restored. Follow instructions from https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067 to properly configure your main activity." + ) + } + + @SuppressLint("ValidFragment") + constructor(screenView: Screen) : super() { + screen = screenView + } + + override fun onResume() { + super.onResume() + if (shouldUpdateOnResume) { + shouldUpdateOnResume = false + ScreenWindowTraits.trySetWindowTraits(screen, tryGetActivity(), tryGetContext()) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + screen.layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT + ) + val wrapper = context?.let { ScreensFrameLayout(it) }?.apply { + addView(recycleView(screen)) + } + return wrapper + } + + private class ScreensFrameLayout( + context: Context, + ) : FrameLayout(context) { + /** + * This method implements a workaround for RN's autoFocus functionality. Because of the way + * autoFocus is implemented it dismisses soft keyboard in fragment transition + * due to change of visibility of the view at the start of the transition. Here we override the + * call to `clearFocus` when the visibility of view is `INVISIBLE` since `clearFocus` triggers the + * hiding of the keyboard in `ReactEditText.java`. + */ + override fun clearFocus() { + if (visibility != INVISIBLE) { + super.clearFocus() + } + } + } + + open fun onContainerUpdate() { + updateWindowTraits() + } + + private fun updateWindowTraits() { + val activity: Activity? = activity + if (activity == null) { + shouldUpdateOnResume = true + return + } + ScreenWindowTraits.trySetWindowTraits(screen, activity, tryGetContext()) + } + + fun tryGetActivity(): Activity? { + activity?.let { return it } + val context = screen.context + if (context is ReactContext && context.currentActivity != null) { + return context.currentActivity + } + var parent: ViewParent? = screen.container + while (parent != null) { + if (parent is Screen) { + val fragment = parent.fragment + fragment?.activity?.let { return it } + } + parent = parent.parent + } + return null + } + + fun tryGetContext(): ReactContext? { + if (context is ReactContext) { + return context as ReactContext + } + if (screen.context is ReactContext) { + return screen.context as ReactContext + } + var parent: ViewParent? = screen.container + while (parent != null) { + if (parent is Screen) { + if (parent.context is ReactContext) { + return parent.context as ReactContext + } + } + parent = parent.parent + } + return null + } + + val childScreenContainers: List> + get() = mChildScreenContainers + + private fun canDispatchEvent(event: ScreenLifecycleEvent): Boolean = when (event) { + ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear + ScreenLifecycleEvent.Appear -> canDispatchAppear + ScreenLifecycleEvent.WillDisappear -> !canDispatchWillAppear + ScreenLifecycleEvent.Disappear -> !canDispatchAppear + } + + private fun setLastEventDispatched(event: ScreenLifecycleEvent) { + when (event) { + ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear = false + ScreenLifecycleEvent.Appear -> canDispatchAppear = false + ScreenLifecycleEvent.WillDisappear -> canDispatchWillAppear = true + ScreenLifecycleEvent.Disappear -> canDispatchAppear = true + } + } + + private fun dispatchOnWillAppear() { + dispatchEvent(ScreenLifecycleEvent.WillAppear, this) + dispatchTransitionProgress(0.0f, false) + } + + private fun dispatchOnAppear() { + dispatchEvent(ScreenLifecycleEvent.Appear, this) + dispatchTransitionProgress(1.0f, false) + } + + private fun dispatchOnWillDisappear() { + dispatchEvent(ScreenLifecycleEvent.WillDisappear, this) + dispatchTransitionProgress(0.0f, true) + } + + private fun dispatchOnDisappear() { + dispatchEvent(ScreenLifecycleEvent.Disappear, this) + dispatchTransitionProgress(1.0f, true) + } + + private fun dispatchEvent(event: ScreenLifecycleEvent, fragment: ScreenFragment) { + if (fragment is ScreenStackFragment && fragment.canDispatchEvent(event)) { + fragment.screen.let { + fragment.setLastEventDispatched(event) + val lifecycleEvent: Event<*> = when (event) { + ScreenLifecycleEvent.WillAppear -> ScreenWillAppearEvent(it.id) + ScreenLifecycleEvent.Appear -> ScreenAppearEvent(it.id) + ScreenLifecycleEvent.WillDisappear -> ScreenWillDisappearEvent(it.id) + ScreenLifecycleEvent.Disappear -> ScreenDisappearEvent(it.id) + } + val screenContext = screen.context as ReactContext + val eventDispatcher: EventDispatcher? = + UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id) + eventDispatcher?.dispatchEvent(lifecycleEvent) + fragment.dispatchEventInChildContainers(event) + } + } + } + + private fun dispatchEventInChildContainers(event: ScreenLifecycleEvent) { + mChildScreenContainers.filter { it.screenCount > 0 }.forEach { + it.topScreen?.fragment?.let { fragment -> dispatchEvent(event, fragment) } + } + } + + fun dispatchHeaderBackButtonClickedEvent() { + val screenContext = screen.context as ReactContext + UIManagerHelper + .getEventDispatcherForReactTag(screenContext, screen.id) + ?.dispatchEvent(HeaderBackButtonClickedEvent(screen.id)) + } + + fun dispatchTransitionProgress(alpha: Float, closing: Boolean) { + if (this is ScreenStackFragment) { + if (mProgress != alpha) { + mProgress = max(0.0f, min(1.0f, alpha)) + /* We want value of 0 and 1 to be always dispatched so we base coalescing key on the progress: + - progress is 0 -> key 1 + - progress is 1 -> key 2 + - progress is between 0 and 1 -> key 3 + */ + val coalescingKey = (if (mProgress == 0.0f) 1 else if (mProgress == 1.0f) 2 else 3).toShort() + val container: ScreenContainer<*>? = screen.container + val goingForward = if (container is ScreenStack) container.goingForward else false + val screenContext = screen.context as ReactContext + UIManagerHelper + .getEventDispatcherForReactTag(screenContext, screen.id) + ?.dispatchEvent( + ScreenTransitionProgressEvent( + screen.id, mProgress, closing, goingForward, coalescingKey + ) + ) + } + } + } + + fun registerChildScreenContainer(screenContainer: ScreenContainer<*>) { + mChildScreenContainers.add(screenContainer) + } + + fun unregisterChildScreenContainer(screenContainer: ScreenContainer<*>) { + mChildScreenContainers.remove(screenContainer) + } + + fun onViewAnimationStart() { + dispatchViewAnimationEvent(false) + } + + open fun onViewAnimationEnd() { + dispatchViewAnimationEvent(true) + } + + private fun dispatchViewAnimationEvent(animationEnd: Boolean) { + isTransitioning = !animationEnd + // if parent fragment is transitioning, we do not want the events dispatched from the child, + // since we subscribe to parent's animation start/end and dispatch events in child from there + // check for `isTransitioning` should be enough since the child's animation should take only + // 20ms due to always being `StackAnimation.NONE` when nested stack being pushed + val parent = parentFragment + if (parent == null || (parent is ScreenFragment && !parent.isTransitioning)) { + // onViewAnimationStart/End is triggered from View#onAnimationStart/End method of the fragment's root + // view. We override an appropriate method of the StackFragment's + // root view in order to achieve this. + if (isResumed) { + // Android dispatches the animation start event for the fragment that is being added first + // however we want the one being dismissed first to match iOS. It also makes more sense from + // a navigation point of view to have the disappear event first. + // Since there are no explicit relationships between the fragment being added / removed the + // practical way to fix this is delaying dispatching the appear events at the end of the + // frame. + UiThreadUtil.runOnUiThread { + if (animationEnd) dispatchOnAppear() else dispatchOnWillAppear() + } + } else { + if (animationEnd) dispatchOnDisappear() else dispatchOnWillDisappear() + } + } + } + + override fun onDestroy() { + super.onDestroy() + val container = screen.container + if (container == null || !container.hasScreen(this)) { + // we only send dismissed even when the screen has been removed from its container + val screenContext = screen.context + if (screenContext is ReactContext) { + UIManagerHelper + .getEventDispatcherForReactTag(screenContext, screen.id) + ?.dispatchEvent(ScreenDismissedEvent(screen.id)) + } + } + mChildScreenContainers.clear() + } + + companion object { + @JvmStatic + protected fun recycleView(view: View): View { + // screen fragments reuse view instances instead of creating new ones. In order to reuse a given + // view it needs to be detached from the view hierarchy to allow the fragment to attach it back. + val parent = view.parent + if (parent != null) { + (parent as ViewGroup).endViewTransition(view) + parent.removeView(view) + } + + // view detached from fragment manager get their visibility changed to GONE after their state is + // dumped. Since we don't restore the state but want to reuse the view we need to change + // visibility back to VISIBLE in order for the fragment manager to animate in the view. + view.visibility = View.VISIBLE + return view + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStack.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStack.kt new file mode 100644 index 00000000000000..c14e0c36b81aa8 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStack.kt @@ -0,0 +1,335 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.content.Context +import android.graphics.Canvas +import android.view.View +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper +import abi49_0_0.com.swmansion.rnscreens.Screen.StackAnimation +import abi49_0_0.com.swmansion.rnscreens.events.StackFinishTransitioningEvent +import java.util.Collections +import kotlin.collections.ArrayList +import kotlin.collections.HashSet + +class ScreenStack(context: Context?) : ScreenContainer(context) { + private val mStack = ArrayList() + private val mDismissed: MutableSet = HashSet() + private val drawingOpPool: MutableList = ArrayList() + private var drawingOps: MutableList = ArrayList() + private var mTopScreen: ScreenStackFragment? = null + private var mRemovalTransitionStarted = false + private var isDetachingCurrentScreen = false + private var reverseLastTwoChildren = false + private var previousChildrenCount = 0 + var goingForward = false + + fun dismiss(screenFragment: ScreenStackFragment) { + mDismissed.add(screenFragment) + performUpdatesNow() + } + + override val topScreen: Screen? + get() = mTopScreen?.screen + + val rootScreen: Screen + get() { + for (i in 0 until screenCount) { + val screen = getScreenAt(i) + if (!mDismissed.contains(screen.fragment)) { + return screen + } + } + throw IllegalStateException("Stack has no root screen set") + } + + override fun adapt(screen: Screen) = ScreenStackFragment(screen) + + override fun startViewTransition(view: View) { + super.startViewTransition(view) + mRemovalTransitionStarted = true + } + + override fun endViewTransition(view: View) { + super.endViewTransition(view) + if (mRemovalTransitionStarted) { + mRemovalTransitionStarted = false + dispatchOnFinishTransitioning() + } + } + + fun onViewAppearTransitionEnd() { + if (!mRemovalTransitionStarted) { + dispatchOnFinishTransitioning() + } + } + + private fun dispatchOnFinishTransitioning() { + UIManagerHelper + .getEventDispatcherForReactTag((context as ReactContext), id) + ?.dispatchEvent(StackFinishTransitioningEvent(id)) + } + + override fun removeScreenAt(index: Int) { + mDismissed.remove(getScreenAt(index).fragment) + super.removeScreenAt(index) + } + + override fun removeAllScreens() { + mDismissed.clear() + super.removeAllScreens() + } + + override fun hasScreen(screenFragment: ScreenFragment?): Boolean = + super.hasScreen(screenFragment) && !mDismissed.contains(screenFragment) + + override fun onUpdate() { + // When going back from a nested stack with a single screen on it, we may hit an edge case + // when all screens are dismissed and no screen is to be displayed on top. We need to gracefully + // handle the case of newTop being NULL, which happens in several places below + var newTop: ScreenStackFragment? = null // newTop is nullable, see the above comment ^ + var visibleBottom: ScreenStackFragment? = null // this is only set if newTop has TRANSPARENT_MODAL presentation mode + isDetachingCurrentScreen = false // we reset it so the previous value is not used by mistake + for (i in mScreenFragments.indices.reversed()) { + val screen = mScreenFragments[i] + if (!mDismissed.contains(screen)) { + if (newTop == null) { + newTop = screen + } else { + visibleBottom = screen + } + if (!isTransparent(screen)) { + break + } + } + } + var shouldUseOpenAnimation = true + var stackAnimation: StackAnimation? = null + if (!mStack.contains(newTop)) { + // if new top screen wasn't on stack we do "open animation" so long it is not the very first + // screen on stack + if (mTopScreen != null && newTop != null) { + // there was some other screen attached before + // if the previous top screen does not exist anymore and the new top was not on the stack + // before, probably replace or reset was called, so we play the "close animation". + // Otherwise it's open animation + val containsTopScreen = mTopScreen?.let { mScreenFragments.contains(it) } == true + val isPushReplace = newTop.screen.replaceAnimation === Screen.ReplaceAnimation.PUSH + shouldUseOpenAnimation = containsTopScreen || isPushReplace + // if the replace animation is `push`, the new top screen provides the animation, otherwise the previous one + stackAnimation = if (shouldUseOpenAnimation) newTop.screen.stackAnimation else mTopScreen?.screen?.stackAnimation + } else if (mTopScreen == null && newTop != null) { + // mTopScreen was not present before so newTop is the first screen added to a stack + // and we don't want the animation when it is entering + stackAnimation = StackAnimation.NONE + goingForward = true + } + } else if (mTopScreen != null && mTopScreen != newTop) { + // otherwise if we are performing top screen change we do "close animation" + shouldUseOpenAnimation = false + stackAnimation = mTopScreen?.screen?.stackAnimation + } + + createTransaction().let { + // animation logic start + if (stackAnimation != null) { + if (shouldUseOpenAnimation) { + when (stackAnimation) { + StackAnimation.DEFAULT -> it.setCustomAnimations(R.anim.rns_default_enter_in, R.anim.rns_default_enter_out) + StackAnimation.NONE -> it.setCustomAnimations(R.anim.rns_no_animation_20, R.anim.rns_no_animation_20) + StackAnimation.FADE -> it.setCustomAnimations(R.anim.rns_fade_in, R.anim.rns_fade_out) + StackAnimation.SLIDE_FROM_RIGHT -> it.setCustomAnimations(R.anim.rns_slide_in_from_right, R.anim.rns_slide_out_to_left) + StackAnimation.SLIDE_FROM_LEFT -> it.setCustomAnimations(R.anim.rns_slide_in_from_left, R.anim.rns_slide_out_to_right) + StackAnimation.SLIDE_FROM_BOTTOM -> it.setCustomAnimations( + R.anim.rns_slide_in_from_bottom, R.anim.rns_no_animation_medium + ) + StackAnimation.FADE_FROM_BOTTOM -> it.setCustomAnimations(R.anim.rns_fade_from_bottom, R.anim.rns_no_animation_350) + } + } else { + when (stackAnimation) { + StackAnimation.DEFAULT -> it.setCustomAnimations(R.anim.rns_default_exit_in, R.anim.rns_default_exit_out) + StackAnimation.NONE -> it.setCustomAnimations(R.anim.rns_no_animation_20, R.anim.rns_no_animation_20) + StackAnimation.FADE -> it.setCustomAnimations(R.anim.rns_fade_in, R.anim.rns_fade_out) + StackAnimation.SLIDE_FROM_RIGHT -> it.setCustomAnimations(R.anim.rns_slide_in_from_left, R.anim.rns_slide_out_to_right) + StackAnimation.SLIDE_FROM_LEFT -> it.setCustomAnimations(R.anim.rns_slide_in_from_right, R.anim.rns_slide_out_to_left) + StackAnimation.SLIDE_FROM_BOTTOM -> it.setCustomAnimations( + R.anim.rns_no_animation_medium, R.anim.rns_slide_out_to_bottom + ) + StackAnimation.FADE_FROM_BOTTOM -> it.setCustomAnimations(R.anim.rns_no_animation_250, R.anim.rns_fade_to_bottom) + } + } + } + + // animation logic end + goingForward = shouldUseOpenAnimation + + if (shouldUseOpenAnimation && + newTop != null && needsDrawReordering(newTop) && + visibleBottom == null + ) { + // When using an open animation in which two screens overlap (eg. fade_from_bottom or + // slide_from_bottom), we want to draw the previous screen under the new one, + // which is apparently not the default option. Android always draws the disappearing view + // on top of the appearing one. We then reverse the order of the views so the new screen + // appears on top of the previous one. You can read more about in the comment + // for the code we use to change that behavior: + // https://github.com/airbnb/native-navigation/blob/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinatorLayout.java#L18 + isDetachingCurrentScreen = true + } + + // remove all screens previously on stack + for (screen in mStack) { + if (!mScreenFragments.contains(screen) || mDismissed.contains(screen)) { + it.remove(screen) + } + } + for (screen in mScreenFragments) { + // Stop detaching screens when reaching visible bottom. All screens above bottom should be + // visible. + if (screen === visibleBottom) { + break + } + // detach all screens that should not be visible + if (screen !== newTop && !mDismissed.contains(screen)) { + it.remove(screen) + } + } + + // attach screens that just became visible + if (visibleBottom != null && !visibleBottom.isAdded) { + val top = newTop + var beneathVisibleBottom = true + for (screen in mScreenFragments) { + // ignore all screens beneath the visible bottom + if (beneathVisibleBottom) { + beneathVisibleBottom = if (screen === visibleBottom) { + false + } else continue + } + // when first visible screen found, make all screens after that visible + it.add(id, screen).runOnCommit { top?.screen?.bringToFront() } + } + } else if (newTop != null && !newTop.isAdded) { + it.add(id, newTop) + } + mTopScreen = newTop + mStack.clear() + mStack.addAll(mScreenFragments) + + turnOffA11yUnderTransparentScreen(visibleBottom) + + it.commitNowAllowingStateLoss() + } + } + + // only top visible screen should be accessible + private fun turnOffA11yUnderTransparentScreen(visibleBottom: ScreenStackFragment?) { + if (mScreenFragments.size > 1 && visibleBottom != null) { + mTopScreen?.let { + if (isTransparent(it)) { + val screenFragmentsBeneathTop = mScreenFragments.slice(0 until mScreenFragments.size - 1).asReversed() + // go from the top of the stack excluding the top screen + for (screenFragment in screenFragmentsBeneathTop) { + screenFragment.screen.changeAccessibilityMode(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) + + // don't change a11y below non-transparent screens + if (screenFragment == visibleBottom) { + break + } + } + } + } + } + + topScreen?.changeAccessibilityMode(IMPORTANT_FOR_ACCESSIBILITY_AUTO) + } + + override fun notifyContainerUpdate() { + mStack.forEach { it.onContainerUpdate() } + } + + // below methods are taken from + // https://github.com/airbnb/native-navigation/blob/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinatorLayout.java#L43 + // and are used to swap the order of drawing views when navigating forward with the transitions + // that are making transitioning fragments appear one on another. See more info in the comment to + // the linked class. + override fun removeView(view: View) { + // we set this property to reverse the order of drawing views + // when we want to push new fragment on top of the previous one and their animations collide. + // More information in: + // https://github.com/airbnb/native-navigation/blob/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinatorLayout.java#L17 + if (isDetachingCurrentScreen) { + isDetachingCurrentScreen = false + reverseLastTwoChildren = true + } + super.removeView(view) + } + + private fun drawAndRelease() { + // We make a copy of the drawingOps and use it to dispatch draws in order to be sure + // that we do not modify the original list. There are cases when `op.draw` can call + // `drawChild` which would modify the list through which we are iterating. See more: + // https://github.com/software-mansion/react-native-screens/pull/1406 + val drawingOpsCopy = drawingOps + drawingOps = ArrayList() + for (op in drawingOpsCopy) { + op.draw() + drawingOpPool.add(op) + } + } + + override fun dispatchDraw(canvas: Canvas) { + super.dispatchDraw(canvas) + + // check the view removal is completed (by comparing the previous children count) + if (drawingOps.size < previousChildrenCount) { + reverseLastTwoChildren = false + } + previousChildrenCount = drawingOps.size + if (reverseLastTwoChildren && drawingOps.size >= 2) { + Collections.swap(drawingOps, drawingOps.size - 1, drawingOps.size - 2) + } + drawAndRelease() + } + + override fun drawChild(canvas: Canvas, child: View, drawingTime: Long): Boolean { + drawingOps.add( + obtainDrawingOp().apply { + this.canvas = canvas + this.child = child + this.drawingTime = drawingTime + } + ) + return true + } + + private fun performDraw(op: DrawingOp) { + // Canvas parameter can not be null here https://developer.android.com/reference/android/view/ViewGroup#drawChild(android.graphics.Canvas,%20android.view.View,%20long) + // So if we are passing null here, we would crash anyway + super.drawChild(op.canvas!!, op.child, op.drawingTime) + } + + private fun obtainDrawingOp(): DrawingOp = + if (drawingOpPool.isEmpty()) DrawingOp() else drawingOpPool.removeLast() + + private inner class DrawingOp { + var canvas: Canvas? = null + var child: View? = null + var drawingTime: Long = 0 + + fun draw() { + performDraw(this) + canvas = null + child = null + drawingTime = 0 + } + } + + companion object { + private fun isTransparent(fragment: ScreenStackFragment): Boolean = + fragment.screen.stackPresentation === Screen.StackPresentation.TRANSPARENT_MODAL + + private fun needsDrawReordering(fragment: ScreenStackFragment): Boolean = + fragment.screen.stackAnimation === StackAnimation.SLIDE_FROM_BOTTOM || + fragment.screen.stackAnimation === StackAnimation.FADE_FROM_BOTTOM + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackFragment.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackFragment.kt new file mode 100644 index 00000000000000..5c1d3b3512022a --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -0,0 +1,257 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.view.animation.Animation +import android.view.animation.AnimationSet +import android.view.animation.Transformation +import android.widget.LinearLayout +import androidx.appcompat.widget.Toolbar +import androidx.coordinatorlayout.widget.CoordinatorLayout +import abi49_0_0.com.facebook.react.uimanager.PixelUtil +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior + +class ScreenStackFragment : ScreenFragment { + private var mAppBarLayout: AppBarLayout? = null + private var mToolbar: Toolbar? = null + private var mShadowHidden = false + private var mIsTranslucent = false + + var searchView: CustomSearchView? = null + var onSearchViewCreate: ((searchView: CustomSearchView) -> Unit)? = null + + @SuppressLint("ValidFragment") + constructor(screenView: Screen) : super(screenView) + + constructor() { + throw IllegalStateException( + "ScreenStack fragments should never be restored. Follow instructions from https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067 to properly configure your main activity." + ) + } + + fun removeToolbar() { + mAppBarLayout?.let { + mToolbar?.let { toolbar -> + if (toolbar.parent === it) { + it.removeView(toolbar) + } + } + } + mToolbar = null + } + + fun setToolbar(toolbar: Toolbar) { + mAppBarLayout?.addView(toolbar) + toolbar.layoutParams = AppBarLayout.LayoutParams( + AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT + ).apply { scrollFlags = 0 } + mToolbar = toolbar + } + + fun setToolbarShadowHidden(hidden: Boolean) { + if (mShadowHidden != hidden) { + mAppBarLayout?.targetElevation = if (hidden) 0f else PixelUtil.toPixelFromDIP(4f) + mShadowHidden = hidden + } + } + + fun setToolbarTranslucent(translucent: Boolean) { + if (mIsTranslucent != translucent) { + val params = screen.layoutParams + (params as CoordinatorLayout.LayoutParams).behavior = + if (translucent) null else ScrollingViewBehavior() + mIsTranslucent = translucent + } + } + + override fun onContainerUpdate() { + screen.headerConfig?.onUpdate() + } + + override fun onViewAnimationEnd() { + super.onViewAnimationEnd() + notifyViewAppearTransitionEnd() + } + + private fun notifyViewAppearTransitionEnd() { + val screenStack = view?.parent + if (screenStack is ScreenStack) { + screenStack.onViewAppearTransitionEnd() + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view: ScreensCoordinatorLayout? = + context?.let { ScreensCoordinatorLayout(it, this) } + + screen.layoutParams = CoordinatorLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT + ).apply { behavior = if (mIsTranslucent) null else ScrollingViewBehavior() } + + view?.addView(recycleView(screen)) + + mAppBarLayout = context?.let { AppBarLayout(it) }?.apply { + // By default AppBarLayout will have a background color set but since we cover the whole layout + // with toolbar (that can be semi-transparent) the bar layout background color does not pay a + // role. On top of that it breaks screens animations when alfa offscreen compositing is off + // (which is the default) + setBackgroundColor(Color.TRANSPARENT) + layoutParams = AppBarLayout.LayoutParams( + AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT + ) + } + + view?.addView(mAppBarLayout) + if (mShadowHidden) { + mAppBarLayout?.targetElevation = 0f + } + mToolbar?.let { mAppBarLayout?.addView(recycleView(it)) } + setHasOptionsMenu(true) + return view + } + + override fun onPrepareOptionsMenu(menu: Menu) { + updateToolbarMenu(menu) + return super.onPrepareOptionsMenu(menu) + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + updateToolbarMenu(menu) + return super.onCreateOptionsMenu(menu, inflater) + } + + private fun shouldShowSearchBar(): Boolean { + val config = screen.headerConfig + val numberOfSubViews = config?.configSubviewsCount ?: 0 + if (config != null && numberOfSubViews > 0) { + for (i in 0 until numberOfSubViews) { + val subView = config.getConfigSubview(i) + if (subView.type == ScreenStackHeaderSubview.Type.SEARCH_BAR) { + return true + } + } + } + return false + } + + private fun updateToolbarMenu(menu: Menu) { + menu.clear() + if (shouldShowSearchBar()) { + val currentContext = context + if (searchView == null && currentContext != null) { + val newSearchView = CustomSearchView(currentContext, this) + searchView = newSearchView + onSearchViewCreate?.invoke(newSearchView) + } + menu.add("").apply { + setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) + actionView = searchView + } + } + } + + fun canNavigateBack(): Boolean { + val container: ScreenContainer<*>? = screen.container + check(container is ScreenStack) { "ScreenStackFragment added into a non-stack container" } + return if (container.rootScreen == screen) { + // this screen is the root of the container, if it is nested we can check parent container + // if it is also a root or not + val parentFragment = parentFragment + if (parentFragment is ScreenStackFragment) { + parentFragment.canNavigateBack() + } else { + false + } + } else { + true + } + } + + fun dismiss() { + val container: ScreenContainer<*>? = screen.container + check(container is ScreenStack) { "ScreenStackFragment added into a non-stack container" } + container.dismiss(this) + } + + private class ScreensCoordinatorLayout( + context: Context, + private val mFragment: ScreenFragment + ) : CoordinatorLayout(context) { + private val mAnimationListener: Animation.AnimationListener = + object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + mFragment.onViewAnimationStart() + } + + override fun onAnimationEnd(animation: Animation) { + mFragment.onViewAnimationEnd() + } + + override fun onAnimationRepeat(animation: Animation) {} + } + + override fun startAnimation(animation: Animation) { + // For some reason View##onAnimationEnd doesn't get called for + // exit transitions so we explicitly attach animation listener. + // We also have some animations that are an AnimationSet, so we don't wrap them + // in another set since it causes some visual glitches when going forward. + // We also set the listener only when going forward, since when going back, + // there is already a listener for dismiss action added, which would be overridden + // and also this is not necessary when going back since the lifecycle methods + // are correctly dispatched then. + // We also add fakeAnimation to the set of animations, which sends the progress of animation + val fakeAnimation = ScreensAnimation(mFragment).apply { duration = animation.duration } + + if (animation is AnimationSet && !mFragment.isRemoving) { + animation.apply { + addAnimation(fakeAnimation) + setAnimationListener(mAnimationListener) + }.also { + super.startAnimation(it) + } + } else { + AnimationSet(true).apply { + addAnimation(animation) + addAnimation(fakeAnimation) + setAnimationListener(mAnimationListener) + }.also { + super.startAnimation(it) + } + } + } + + /** + * This method implements a workaround for RN's autoFocus functionality. Because of the way + * autoFocus is implemented it dismisses soft keyboard in fragment transition + * due to change of visibility of the view at the start of the transition. Here we override the + * call to `clearFocus` when the visibility of view is `INVISIBLE` since `clearFocus` triggers the + * hiding of the keyboard in `ReactEditText.java`. + */ + override fun clearFocus() { + if (visibility != INVISIBLE) { + super.clearFocus() + } + } + } + + private class ScreensAnimation(private val mFragment: ScreenFragment) : Animation() { + override fun applyTransformation(interpolatedTime: Float, t: Transformation) { + super.applyTransformation(interpolatedTime, t) + // interpolated time should be the progress of the current transition + mFragment.dispatchTransitionProgress(interpolatedTime, !mFragment.isResumed) + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt new file mode 100644 index 00000000000000..579617da93f5fc --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt @@ -0,0 +1,396 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.content.Context +import android.graphics.PorterDuff +import android.os.Build +import android.text.TextUtils +import android.util.TypedValue +import android.view.Gravity +import android.view.View.OnClickListener +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.Fragment +import abi49_0_0.com.facebook.react.ReactApplication +import abi49_0_0.com.facebook.react.bridge.JSApplicationIllegalArgumentException +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper +import abi49_0_0.com.facebook.react.views.text.ReactTypefaceUtils +import abi49_0_0.com.swmansion.rnscreens.events.HeaderAttachedEvent +import abi49_0_0.com.swmansion.rnscreens.events.HeaderDetachedEvent + +class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { + private val mConfigSubviews = ArrayList(3) + val toolbar: CustomToolbar + private var headerTopInset: Int? = null + private var mTitle: String? = null + private var mTitleColor = 0 + private var mTitleFontFamily: String? = null + private var mDirection: String? = null + private var mTitleFontSize = 0f + private var mTitleFontWeight = 0 + private var mBackgroundColor: Int? = null + private var mIsHidden = false + private var mIsBackButtonHidden = false + private var mIsShadowHidden = false + private var mDestroyed = false + private var mBackButtonInCustomView = false + private var mIsTopInsetEnabled = true + private var mIsTranslucent = false + private var mTintColor = 0 + private var mIsAttachedToWindow = false + private val mDefaultStartInset: Int + private val mDefaultStartInsetWithNavigation: Int + private val mBackClickListener = OnClickListener { + screenFragment?.let { + val stack = screenStack + if (stack != null && stack.rootScreen == it.screen) { + val parentFragment = it.parentFragment + if (parentFragment is ScreenStackFragment) { + if (parentFragment.screen.nativeBackButtonDismissalEnabled) { + parentFragment.dismiss() + } else { + parentFragment.dispatchHeaderBackButtonClickedEvent() + } + } + } else { + if (it.screen.nativeBackButtonDismissalEnabled) { + it.dismiss() + } else { + it.dispatchHeaderBackButtonClickedEvent() + } + } + } + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + // no-op + } + + fun destroy() { + mDestroyed = true + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + mIsAttachedToWindow = true + UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id) + ?.dispatchEvent(HeaderAttachedEvent(id)) + // we want to save the top inset before the status bar can be hidden, which would resolve in + // inset being 0 + if (headerTopInset == null) { + headerTopInset = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + rootWindowInsets.systemWindowInsetTop + else + // Hacky fallback for old android. Before Marshmallow, the status bar height was always 25 + (25 * resources.displayMetrics.density).toInt() + } + onUpdate() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + mIsAttachedToWindow = false + UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id) + ?.dispatchEvent(HeaderDetachedEvent(id)) + } + + private val screen: Screen? + get() = parent as? Screen + private val screenStack: ScreenStack? + get() = screen?.container as? ScreenStack + val screenFragment: ScreenStackFragment? + get() { + val screen = parent + if (screen is Screen) { + val fragment: Fragment? = screen.fragment + if (fragment is ScreenStackFragment) { + return fragment + } + } + return null + } + + fun onUpdate() { + val stack = screenStack + val isTop = stack == null || stack.topScreen == parent + + if (!mIsAttachedToWindow || !isTop || mDestroyed) { + return + } + + val activity = screenFragment?.activity as AppCompatActivity? ?: return + if (mDirection != null) { + if (mDirection == "rtl") { + toolbar.layoutDirection = LAYOUT_DIRECTION_RTL + } else if (mDirection == "ltr") { + toolbar.layoutDirection = LAYOUT_DIRECTION_LTR + } + } + + // orientation and status bar management + screen?.let { + // we set the traits here too, not only when the prop for Screen is passed + // because sometimes we don't have the Fragment and Activity available then yet, e.g. on the + // first setting of props. Similar thing is done for Screens of ScreenContainers, but in + // `onContainerUpdate` of their Fragment + val reactContext = if (context is ReactContext) { + context as ReactContext + } else { + it.fragment?.tryGetContext() + } + ScreenWindowTraits.trySetWindowTraits(it, activity, reactContext) + } + + if (mIsHidden) { + if (toolbar.parent != null) { + screenFragment?.removeToolbar() + } + return + } + + if (toolbar.parent == null) { + screenFragment?.setToolbar(toolbar) + } + + if (mIsTopInsetEnabled) { + headerTopInset.let { + toolbar.setPadding(0, it ?: 0, 0, 0) + } + } else { + if (toolbar.paddingTop > 0) { + toolbar.setPadding(0, 0, 0, 0) + } + } + + activity.setSupportActionBar(toolbar) + // non-null toolbar is set in the line above and it is used here + val actionBar = requireNotNull(activity.supportActionBar) + + // Reset toolbar insets. By default we set symmetric inset for start and end to match iOS + // implementation where both right and left icons are offset from the edge by default. We also + // reset startWithNavigation inset which corresponds to the distance between navigation icon and + // title. If title isn't set we clear that value few lines below to give more space to custom + // center-mounted views. + toolbar.contentInsetStartWithNavigation = mDefaultStartInsetWithNavigation + toolbar.setContentInsetsRelative(mDefaultStartInset, mDefaultStartInset) + + // hide back button + actionBar.setDisplayHomeAsUpEnabled( + screenFragment?.canNavigateBack() == true && !mIsBackButtonHidden + ) + + // when setSupportActionBar is called a toolbar wrapper gets initialized that overwrites + // navigation click listener. The default behavior set in the wrapper is to call into + // menu options handlers, but we prefer the back handling logic to stay here instead. + toolbar.setNavigationOnClickListener(mBackClickListener) + + // shadow + screenFragment?.setToolbarShadowHidden(mIsShadowHidden) + + // translucent + screenFragment?.setToolbarTranslucent(mIsTranslucent) + + // title + actionBar.title = mTitle + if (TextUtils.isEmpty(mTitle)) { + // if title is empty we set start navigation inset to 0 to give more space to custom rendered + // views. When it is set to default it'd take up additional distance from the back button + // which would impact the position of custom header views rendered at the center. + toolbar.contentInsetStartWithNavigation = 0 + } + + val titleTextView = titleTextView + if (mTitleColor != 0) { + toolbar.setTitleTextColor(mTitleColor) + } + + if (titleTextView != null) { + if (mTitleFontFamily != null || mTitleFontWeight > 0) { + val titleTypeface = ReactTypefaceUtils.applyStyles( + null, 0, mTitleFontWeight, mTitleFontFamily, context.assets + ) + titleTextView.typeface = titleTypeface + } + if (mTitleFontSize > 0) { + titleTextView.textSize = mTitleFontSize + } + } + + // background + mBackgroundColor?.let { toolbar.setBackgroundColor(it) } + + // color + if (mTintColor != 0) { + toolbar.navigationIcon?.setColorFilter(mTintColor, PorterDuff.Mode.SRC_ATOP) + } + + // subviews + for (i in toolbar.childCount - 1 downTo 0) { + if (toolbar.getChildAt(i) is ScreenStackHeaderSubview) { + toolbar.removeViewAt(i) + } + } + + var i = 0 + val size = mConfigSubviews.size + while (i < size) { + val view = mConfigSubviews[i] + val type = view.type + if (type === ScreenStackHeaderSubview.Type.BACK) { + // we special case BACK button header config type as we don't add it as a view into toolbar + // but instead just copy the drawable from imageview that's added as a first child to it. + val firstChild = view.getChildAt(0) as? ImageView + ?: throw JSApplicationIllegalArgumentException( + "Back button header config view should have Image as first child" + ) + actionBar.setHomeAsUpIndicator(firstChild.drawable) + i++ + continue + } + val params = Toolbar.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT) + when (type) { + ScreenStackHeaderSubview.Type.LEFT -> { + // when there is a left item we need to disable navigation icon by default + // we also hide title as there is no other way to display left side items + if (!mBackButtonInCustomView) { + toolbar.navigationIcon = null + } + toolbar.title = null + params.gravity = Gravity.START + } + ScreenStackHeaderSubview.Type.RIGHT -> params.gravity = Gravity.END + ScreenStackHeaderSubview.Type.CENTER -> { + params.width = LayoutParams.MATCH_PARENT + params.gravity = Gravity.CENTER_HORIZONTAL + toolbar.title = null + } + else -> {} + } + view.layoutParams = params + toolbar.addView(view) + i++ + } + } + + private fun maybeUpdate() { + if (parent != null && !mDestroyed) { + onUpdate() + } + } + + fun getConfigSubview(index: Int): ScreenStackHeaderSubview = mConfigSubviews[index] + + val configSubviewsCount: Int + get() = mConfigSubviews.size + + fun removeConfigSubview(index: Int) { + mConfigSubviews.removeAt(index) + maybeUpdate() + } + + fun removeAllConfigSubviews() { + mConfigSubviews.clear() + maybeUpdate() + } + + fun addConfigSubview(child: ScreenStackHeaderSubview, index: Int) { + mConfigSubviews.add(index, child) + maybeUpdate() + } + + private val titleTextView: TextView? + get() { + for (i in 0 until toolbar.childCount) { + val view = toolbar.getChildAt(i) + if (view is TextView) { + if (view.text == toolbar.title) { + return view + } + } + } + return null + } + + fun setTitle(title: String?) { + mTitle = title + } + + fun setTitleFontFamily(titleFontFamily: String?) { + mTitleFontFamily = titleFontFamily + } + + fun setTitleFontWeight(fontWeightString: String?) { + mTitleFontWeight = ReactTypefaceUtils.parseFontWeight(fontWeightString) + } + + fun setTitleFontSize(titleFontSize: Float) { + mTitleFontSize = titleFontSize + } + + fun setTitleColor(color: Int) { + mTitleColor = color + } + + fun setTintColor(color: Int) { + mTintColor = color + } + + fun setTopInsetEnabled(topInsetEnabled: Boolean) { + mIsTopInsetEnabled = topInsetEnabled + } + + fun setBackgroundColor(color: Int?) { + mBackgroundColor = color + } + + fun setHideShadow(hideShadow: Boolean) { + mIsShadowHidden = hideShadow + } + + fun setHideBackButton(hideBackButton: Boolean) { + mIsBackButtonHidden = hideBackButton + } + + fun setHidden(hidden: Boolean) { + mIsHidden = hidden + } + + fun setTranslucent(translucent: Boolean) { + mIsTranslucent = translucent + } + + fun setBackButtonInCustomView(backButtonInCustomView: Boolean) { + mBackButtonInCustomView = backButtonInCustomView + } + + fun setDirection(direction: String?) { + mDirection = direction + } + + private class DebugMenuToolbar(context: Context, config: ScreenStackHeaderConfig) : CustomToolbar(context, config) { + override fun showOverflowMenu(): Boolean { + (context.applicationContext as ReactApplication) + .reactNativeHost + .reactInstanceManager + .showDevOptionsDialog() + return true + } + } + + init { + visibility = GONE + toolbar = if (BuildConfig.DEBUG) DebugMenuToolbar(context, this) else CustomToolbar(context, this) + mDefaultStartInset = toolbar.contentInsetStart + mDefaultStartInsetWithNavigation = toolbar.contentInsetStartWithNavigation + + // set primary color as background by default + val tv = TypedValue() + if (context.theme.resolveAttribute(R.attr.colorPrimary, tv, true)) { + toolbar.setBackgroundColor(tv.data) + } + toolbar.clipChildren = false + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt new file mode 100644 index 00000000000000..5b65dc90531c6c --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt @@ -0,0 +1,204 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.util.Log +import android.view.View +import abi49_0_0.com.facebook.react.bridge.JSApplicationCausedNativeException +import abi49_0_0.com.facebook.react.common.MapBuilder +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenStackHeaderConfigManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenStackHeaderConfigManagerInterface +import abi49_0_0.com.swmansion.rnscreens.events.HeaderAttachedEvent +import abi49_0_0.com.swmansion.rnscreens.events.HeaderDetachedEvent +import javax.annotation.Nonnull + +@ReactModule(name = ScreenStackHeaderConfigViewManager.REACT_CLASS) +class ScreenStackHeaderConfigViewManager : ViewGroupManager(), RNSScreenStackHeaderConfigManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = RNSScreenStackHeaderConfigManagerDelegate(this) + } + + override fun getName(): String = REACT_CLASS + + override fun createViewInstance(reactContext: ThemedReactContext) = ScreenStackHeaderConfig(reactContext) + + override fun addView(parent: ScreenStackHeaderConfig, child: View, index: Int) { + if (child !is ScreenStackHeaderSubview) { + throw JSApplicationCausedNativeException( + "Config children should be of type " + ScreenStackHeaderSubviewManager.REACT_CLASS + ) + } + parent.addConfigSubview(child, index) + } + + override fun onDropViewInstance(@Nonnull view: ScreenStackHeaderConfig) { + view.destroy() + } + + override fun removeAllViews(parent: ScreenStackHeaderConfig) { + parent.removeAllConfigSubviews() + } + + override fun removeViewAt(parent: ScreenStackHeaderConfig, index: Int) { + parent.removeConfigSubview(index) + } + + override fun getChildCount(parent: ScreenStackHeaderConfig): Int = parent.configSubviewsCount + + override fun getChildAt(parent: ScreenStackHeaderConfig, index: Int): View = parent.getConfigSubview(index) + + override fun needsCustomLayoutForChildren() = true + + override fun onAfterUpdateTransaction(parent: ScreenStackHeaderConfig) { + super.onAfterUpdateTransaction(parent) + parent.onUpdate() + } + + @ReactProp(name = "title") + override fun setTitle(config: ScreenStackHeaderConfig, title: String?) { + config.setTitle(title) + } + + @ReactProp(name = "titleFontFamily") + override fun setTitleFontFamily(config: ScreenStackHeaderConfig, titleFontFamily: String?) { + config.setTitleFontFamily(titleFontFamily) + } + + @ReactProp(name = "titleFontSize") + override fun setTitleFontSize(config: ScreenStackHeaderConfig, titleFontSize: Int) { + config.setTitleFontSize(titleFontSize.toFloat()) + } + + @ReactProp(name = "titleFontWeight") + override fun setTitleFontWeight(config: ScreenStackHeaderConfig, titleFontWeight: String?) { + config.setTitleFontWeight(titleFontWeight) + } + + @ReactProp(name = "titleColor", customType = "Color") + override fun setTitleColor(config: ScreenStackHeaderConfig, titleColor: Int?) { + if (titleColor != null) { + config.setTitleColor(titleColor) + } + } + + @ReactProp(name = "backgroundColor", customType = "Color") + override fun setBackgroundColor(config: ScreenStackHeaderConfig, backgroundColor: Int?) { + config.setBackgroundColor(backgroundColor) + } + + @ReactProp(name = "hideShadow") + override fun setHideShadow(config: ScreenStackHeaderConfig, hideShadow: Boolean) { + config.setHideShadow(hideShadow) + } + + @ReactProp(name = "hideBackButton") + override fun setHideBackButton(config: ScreenStackHeaderConfig, hideBackButton: Boolean) { + config.setHideBackButton(hideBackButton) + } + + @ReactProp(name = "topInsetEnabled") + override fun setTopInsetEnabled(config: ScreenStackHeaderConfig, topInsetEnabled: Boolean) { + config.setTopInsetEnabled(topInsetEnabled) + } + + @ReactProp(name = "color", customType = "Color") + override fun setColor(config: ScreenStackHeaderConfig, color: Int?) { + config.setTintColor(color ?: 0) + } + + @ReactProp(name = "hidden") + override fun setHidden(config: ScreenStackHeaderConfig, hidden: Boolean) { + config.setHidden(hidden) + } + + @ReactProp(name = "translucent") + override fun setTranslucent(config: ScreenStackHeaderConfig, translucent: Boolean) { + config.setTranslucent(translucent) + } + + @ReactProp(name = "backButtonInCustomView") + override fun setBackButtonInCustomView( + config: ScreenStackHeaderConfig, + backButtonInCustomView: Boolean + ) { + config.setBackButtonInCustomView(backButtonInCustomView) + } + + @ReactProp(name = "direction") + override fun setDirection(config: ScreenStackHeaderConfig, direction: String?) { + config.setDirection(direction) + } + + override fun getExportedCustomDirectEventTypeConstants(): Map? { + return MapBuilder.of( + HeaderAttachedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onAttached"), + HeaderDetachedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onDetached"), + ) + } + + protected override fun getDelegate(): ViewManagerDelegate = mDelegate + + companion object { + const val REACT_CLASS = "RNSScreenStackHeaderConfig" + } + + // TODO: Find better way to handle platform specific props + private fun logNotAvailable(propName: String) { + Log.w("RN SCREENS", "$propName prop is not available on Android") + } + + override fun setBackTitle(view: ScreenStackHeaderConfig?, value: String?) { + logNotAvailable("backTitle") + } + + override fun setBackTitleFontFamily(view: ScreenStackHeaderConfig?, value: String?) { + logNotAvailable("backTitleFontFamily") + } + + override fun setBackTitleFontSize(view: ScreenStackHeaderConfig?, value: Int) { + logNotAvailable("backTitleFontSize") + } + + override fun setBackTitleVisible(view: ScreenStackHeaderConfig?, value: Boolean) { + logNotAvailable("backTitleVisible") + } + + override fun setLargeTitle(view: ScreenStackHeaderConfig?, value: Boolean) { + logNotAvailable("largeTitle") + } + + override fun setLargeTitleFontFamily(view: ScreenStackHeaderConfig?, value: String?) { + logNotAvailable("largeTitleFontFamily") + } + + override fun setLargeTitleFontSize(view: ScreenStackHeaderConfig?, value: Int) { + logNotAvailable("largeTitleFontSize") + } + + override fun setLargeTitleFontWeight(view: ScreenStackHeaderConfig?, value: String?) { + logNotAvailable("largeTitleFontWeight") + } + + override fun setLargeTitleBackgroundColor(view: ScreenStackHeaderConfig?, value: Int?) { + logNotAvailable("largeTitleBackgroundColor") + } + + override fun setLargeTitleHideShadow(view: ScreenStackHeaderConfig?, value: Boolean) { + logNotAvailable("largeTitleHideShadow") + } + + override fun setLargeTitleColor(view: ScreenStackHeaderConfig?, value: Int?) { + logNotAvailable("largeTitleColor") + } + + override fun setDisableBackButtonMenu(view: ScreenStackHeaderConfig?, value: Boolean) { + logNotAvailable("disableBackButtonMenu") + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt new file mode 100644 index 00000000000000..d1d86c60344c24 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt @@ -0,0 +1,38 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.annotation.SuppressLint +import android.view.View +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup + +@SuppressLint("ViewConstructor") +class ScreenStackHeaderSubview(context: ReactContext?) : ReactViewGroup(context) { + private var mReactWidth = 0 + private var mReactHeight = 0 + var type = Type.RIGHT + + val config: ScreenStackHeaderConfig? + get() = (parent as? CustomToolbar)?.config + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && + MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY + ) { + // dimensions provided by react + mReactWidth = MeasureSpec.getSize(widthMeasureSpec) + mReactHeight = MeasureSpec.getSize(heightMeasureSpec) + val parent = parent + if (parent != null) { + forceLayout() + (parent as View).requestLayout() + } + } + setMeasuredDimension(mReactWidth, mReactHeight) + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) = Unit + + enum class Type { + LEFT, CENTER, RIGHT, BACK, SEARCH_BAR + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt new file mode 100644 index 00000000000000..7be62a8d075d0d --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt @@ -0,0 +1,41 @@ +package abi49_0_0.com.swmansion.rnscreens + +import abi49_0_0.com.facebook.react.bridge.JSApplicationIllegalArgumentException +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenStackHeaderSubviewManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenStackHeaderSubviewManagerInterface + +@ReactModule(name = ScreenStackHeaderSubviewManager.REACT_CLASS) +class ScreenStackHeaderSubviewManager : ViewGroupManager(), RNSScreenStackHeaderSubviewManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = RNSScreenStackHeaderSubviewManagerDelegate(this) + } + + override fun getName() = REACT_CLASS + + override fun createViewInstance(context: ThemedReactContext) = ScreenStackHeaderSubview(context) + + @ReactProp(name = "type") + override fun setType(view: ScreenStackHeaderSubview, type: String?) { + view.type = when (type) { + "left" -> ScreenStackHeaderSubview.Type.LEFT + "center" -> ScreenStackHeaderSubview.Type.CENTER + "right" -> ScreenStackHeaderSubview.Type.RIGHT + "back" -> ScreenStackHeaderSubview.Type.BACK + "searchBar" -> ScreenStackHeaderSubview.Type.SEARCH_BAR + else -> throw JSApplicationIllegalArgumentException("Unknown type $type") + } + } + + protected override fun getDelegate(): ViewManagerDelegate = mDelegate + + companion object { + const val REACT_CLASS = "RNSScreenStackHeaderSubview" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackViewManager.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackViewManager.kt new file mode 100644 index 00000000000000..badd5cc6eb9ec9 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenStackViewManager.kt @@ -0,0 +1,75 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.view.View +import android.view.ViewGroup +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.LayoutShadowNode +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenStackManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenStackManagerInterface +import abi49_0_0.com.swmansion.rnscreens.events.StackFinishTransitioningEvent + +@ReactModule(name = ScreenStackViewManager.REACT_CLASS) +class ScreenStackViewManager : ViewGroupManager(), RNSScreenStackManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = RNSScreenStackManagerDelegate(this) + } + + override fun getName() = REACT_CLASS + + override fun createViewInstance(reactContext: ThemedReactContext) = ScreenStack(reactContext) + + override fun addView(parent: ScreenStack, child: View, index: Int) { + require(child is Screen) { "Attempt attach child that is not of type RNScreen" } + parent.addScreen(child, index) + } + + override fun removeViewAt(parent: ScreenStack, index: Int) { + prepareOutTransition(parent.getScreenAt(index)) + parent.removeScreenAt(index) + } + + private fun prepareOutTransition(screen: Screen?) { + startTransitionRecursive(screen) + } + + private fun startTransitionRecursive(parent: ViewGroup?) { + parent?.let { + for (i in 0 until it.childCount) { + val child = it.getChildAt(i) + child?.let { view -> it.startViewTransition(view) } + if (child is ScreenStackHeaderConfig) { + // we want to start transition on children of the toolbar too, + // which is not a child of ScreenStackHeaderConfig + startTransitionRecursive(child.toolbar) + } + if (child is ViewGroup) { + startTransitionRecursive(child) + } + } + } + } + + override fun getChildCount(parent: ScreenStack) = parent.screenCount + + override fun getChildAt(parent: ScreenStack, index: Int): View = parent.getScreenAt(index) + + override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode = ScreensShadowNode(context) + + override fun needsCustomLayoutForChildren() = true + + protected override fun getDelegate(): ViewManagerDelegate = mDelegate + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap = mutableMapOf( + StackFinishTransitioningEvent.EVENT_NAME to mutableMapOf("registrationName" to "onFinishTransitioning") + ) + + companion object { + const val REACT_CLASS = "RNSScreenStack" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenViewManager.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenViewManager.kt new file mode 100644 index 00000000000000..4d43ea4fd520fd --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenViewManager.kt @@ -0,0 +1,193 @@ +package abi49_0_0.com.swmansion.rnscreens + +import abi49_0_0.com.facebook.react.bridge.JSApplicationIllegalArgumentException +import abi49_0_0.com.facebook.react.bridge.ReadableMap +import abi49_0_0.com.facebook.react.common.MapBuilder +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenManagerDelegate +import abi49_0_0.com.facebook.react.viewmanagers.RNSScreenManagerInterface +import abi49_0_0.com.swmansion.rnscreens.events.HeaderBackButtonClickedEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenAppearEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenDisappearEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenDismissedEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenTransitionProgressEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenWillAppearEvent +import abi49_0_0.com.swmansion.rnscreens.events.ScreenWillDisappearEvent + +@ReactModule(name = ScreenViewManager.REACT_CLASS) +class ScreenViewManager : ViewGroupManager(), RNSScreenManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = RNSScreenManagerDelegate(this) + } + + override fun getName() = REACT_CLASS + + override fun createViewInstance(reactContext: ThemedReactContext) = Screen(reactContext) + + override fun setActivityState(view: Screen, activityState: Float) { + setActivityState(view, activityState.toInt()) + } + + @ReactProp(name = "activityState") + fun setActivityState(view: Screen, activityState: Int) { + if (activityState == -1) { + // Null will be provided when activityState is set as an animated value and we change + // it from JS to be a plain value (non animated). + // In case when null is received, we want to ignore such value and not make + // any updates as the actual non-null value will follow immediately. + return + } + when (activityState) { + 0 -> view.setActivityState(Screen.ActivityState.INACTIVE) + 1 -> view.setActivityState(Screen.ActivityState.TRANSITIONING_OR_BELOW_TOP) + 2 -> view.setActivityState(Screen.ActivityState.ON_TOP) + } + } + + @ReactProp(name = "stackPresentation") + override fun setStackPresentation(view: Screen, presentation: String?) { + view.stackPresentation = when (presentation) { + "push" -> Screen.StackPresentation.PUSH + "modal", "containedModal", "fullScreenModal", "formSheet" -> + Screen.StackPresentation.MODAL + "transparentModal", "containedTransparentModal" -> + Screen.StackPresentation.TRANSPARENT_MODAL + else -> throw JSApplicationIllegalArgumentException("Unknown presentation type $presentation") + } + } + + @ReactProp(name = "stackAnimation") + override fun setStackAnimation(view: Screen, animation: String?) { + view.stackAnimation = when (animation) { + null, "default", "flip", "simple_push" -> Screen.StackAnimation.DEFAULT + "none" -> Screen.StackAnimation.NONE + "fade" -> Screen.StackAnimation.FADE + "slide_from_right" -> Screen.StackAnimation.SLIDE_FROM_RIGHT + "slide_from_left" -> Screen.StackAnimation.SLIDE_FROM_LEFT + "slide_from_bottom" -> Screen.StackAnimation.SLIDE_FROM_BOTTOM + "fade_from_bottom" -> Screen.StackAnimation.FADE_FROM_BOTTOM + else -> throw JSApplicationIllegalArgumentException("Unknown animation type $animation") + } + } + + @ReactProp(name = "gestureEnabled", defaultBoolean = true) + override fun setGestureEnabled(view: Screen, gestureEnabled: Boolean) { + view.isGestureEnabled = gestureEnabled + } + + @ReactProp(name = "replaceAnimation") + override fun setReplaceAnimation(view: Screen, animation: String?) { + view.replaceAnimation = when (animation) { + null, "pop" -> Screen.ReplaceAnimation.POP + "push" -> Screen.ReplaceAnimation.PUSH + else -> throw JSApplicationIllegalArgumentException("Unknown replace animation type $animation") + } + } + + @ReactProp(name = "screenOrientation") + override fun setScreenOrientation(view: Screen, screenOrientation: String?) { + view.setScreenOrientation(screenOrientation) + } + + @ReactProp(name = "statusBarAnimation") + override fun setStatusBarAnimation(view: Screen, statusBarAnimation: String?) { + val animated = statusBarAnimation != null && "none" != statusBarAnimation + view.isStatusBarAnimated = animated + } + + @ReactProp(name = "statusBarColor", customType = "Color") + override fun setStatusBarColor(view: Screen, statusBarColor: Int?) { + view.statusBarColor = statusBarColor + } + + @ReactProp(name = "statusBarStyle") + override fun setStatusBarStyle(view: Screen, statusBarStyle: String?) { + view.statusBarStyle = statusBarStyle + } + + @ReactProp(name = "statusBarTranslucent") + override fun setStatusBarTranslucent(view: Screen, statusBarTranslucent: Boolean) { + view.isStatusBarTranslucent = statusBarTranslucent + } + + @ReactProp(name = "statusBarHidden") + override fun setStatusBarHidden(view: Screen, statusBarHidden: Boolean) { + view.isStatusBarHidden = statusBarHidden + } + + @ReactProp(name = "navigationBarColor", customType = "Color") + override fun setNavigationBarColor(view: Screen, navigationBarColor: Int?) { + view.navigationBarColor = navigationBarColor + } + + @ReactProp(name = "navigationBarHidden") + override fun setNavigationBarHidden(view: Screen, navigationBarHidden: Boolean) { + view.isNavigationBarHidden = navigationBarHidden + } + + @ReactProp(name = "nativeBackButtonDismissalEnabled") + override fun setNativeBackButtonDismissalEnabled( + view: Screen, + nativeBackButtonDismissalEnabled: Boolean + ) { + view.nativeBackButtonDismissalEnabled = nativeBackButtonDismissalEnabled + } + + // these props are not available on Android, however we must override their setters + override fun setFullScreenSwipeEnabled(view: Screen?, value: Boolean) = Unit + + override fun setTransitionDuration(view: Screen?, value: Int) = Unit + + override fun setHideKeyboardOnSwipe(view: Screen?, value: Boolean) = Unit + + override fun setCustomAnimationOnSwipe(view: Screen?, value: Boolean) = Unit + + override fun setGestureResponseDistance(view: Screen?, value: ReadableMap?) = Unit + + override fun setHomeIndicatorHidden(view: Screen?, value: Boolean) = Unit + + override fun setPreventNativeDismiss(view: Screen?, value: Boolean) = Unit + + override fun setSwipeDirection(view: Screen?, value: String?) = Unit + + override fun setSheetAllowedDetents(view: Screen, value: String?) = Unit + + override fun setSheetLargestUndimmedDetent(view: Screen, value: String?) = Unit + + override fun setSheetGrabberVisible(view: Screen?, value: Boolean) = Unit + + override fun setSheetCornerRadius(view: Screen?, value: Float) = Unit + + override fun setSheetExpandsWhenScrolledToEdge(view: Screen?, value: Boolean) = Unit + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap { + return MapBuilder.of( + ScreenDismissedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onDismissed"), + ScreenWillAppearEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onWillAppear"), + ScreenAppearEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onAppear"), + ScreenWillDisappearEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onWillDisappear"), + ScreenDisappearEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onDisappear"), + HeaderBackButtonClickedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onHeaderBackButtonClicked"), + ScreenTransitionProgressEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onTransitionProgress") + ) + } + + protected override fun getDelegate(): ViewManagerDelegate = mDelegate + + companion object { + const val REACT_CLASS = "RNSScreen" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenWindowTraits.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenWindowTraits.kt new file mode 100644 index 00000000000000..5aa63b6fc46a39 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreenWindowTraits.kt @@ -0,0 +1,276 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.animation.ArgbEvaluator +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.annotation.TargetApi +import android.app.Activity +import android.content.pm.ActivityInfo +import android.graphics.Color +import android.os.Build +import android.view.ViewParent +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat +import abi49_0_0.com.facebook.react.bridge.GuardedRunnable +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.swmansion.rnscreens.Screen.WindowTraits + +object ScreenWindowTraits { + // Methods concerning statusBar management were taken from `react-native`'s status bar module: + // https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java + private var mDidSetOrientation = false + private var mDidSetStatusBarAppearance = false + private var mDidSetNavigationBarAppearance = false + private var mDefaultStatusBarColor: Int? = null + + internal fun applyDidSetOrientation() { + mDidSetOrientation = true + } + + internal fun applyDidSetStatusBarAppearance() { + mDidSetStatusBarAppearance = true + } + + internal fun applyDidSetNavigationBarAppearance() { + mDidSetNavigationBarAppearance = true + } + + internal fun setOrientation(screen: Screen, activity: Activity?) { + if (activity == null) { + return + } + val screenForOrientation = findScreenForTrait(screen, WindowTraits.ORIENTATION) + val orientation = screenForOrientation?.screenOrientation ?: ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + activity.requestedOrientation = orientation + } + + @SuppressLint("ObsoleteSdkInt") // to be removed when support for < 0.64 is dropped + internal fun setColor(screen: Screen, activity: Activity?, context: ReactContext?) { + if (activity == null || context == null) { + return + } + if (mDefaultStatusBarColor == null) { + mDefaultStatusBarColor = activity.window.statusBarColor + } + val screenForColor = findScreenForTrait(screen, WindowTraits.COLOR) + val screenForAnimated = findScreenForTrait(screen, WindowTraits.ANIMATED) + val color = screenForColor?.statusBarColor ?: mDefaultStatusBarColor + val animated = screenForAnimated?.isStatusBarAnimated ?: false + + UiThreadUtil.runOnUiThread( + object : GuardedRunnable(context) { + override fun runGuarded() { + val window = activity.window + val curColor: Int = window.statusBarColor + val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), curColor, color) + colorAnimation.addUpdateListener { animator -> + window.statusBarColor = animator.animatedValue as Int + } + if (animated) { + colorAnimation.setDuration(300).startDelay = 0 + } else { + colorAnimation.setDuration(0).startDelay = 300 + } + colorAnimation.start() + } + }) + } + + internal fun setStyle(screen: Screen, activity: Activity?, context: ReactContext?) { + if (activity == null || context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return + } + val screenForStyle = findScreenForTrait(screen, WindowTraits.STYLE) + val style = screenForStyle?.statusBarStyle ?: "light" + + UiThreadUtil.runOnUiThread { + val decorView = activity.window.decorView + val window = activity.window + val controller = WindowInsetsControllerCompat(window, decorView) + + controller.isAppearanceLightStatusBars = style == "dark" + } + } + + internal fun setTranslucent( + screen: Screen, + activity: Activity?, + context: ReactContext? + ) { + if (activity == null || context == null) { + return + } + val screenForTranslucent = findScreenForTrait(screen, WindowTraits.TRANSLUCENT) + val translucent = screenForTranslucent?.isStatusBarTranslucent ?: false + UiThreadUtil.runOnUiThread( + object : GuardedRunnable(context) { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + override fun runGuarded() { + // If the status bar is translucent hook into the window insets calculations + // and consume all the top insets so no padding will be added under the status bar. + val decorView = activity.window.decorView + if (translucent) { + ViewCompat.setOnApplyWindowInsetsListener(decorView) { v, insets -> + val defaultInsets = ViewCompat.onApplyWindowInsets(v, insets) + defaultInsets.replaceSystemWindowInsets( + defaultInsets.systemWindowInsetLeft, + 0, + defaultInsets.systemWindowInsetRight, + defaultInsets.systemWindowInsetBottom + ) + } + } else { + ViewCompat.setOnApplyWindowInsetsListener(decorView, null) + } + ViewCompat.requestApplyInsets(decorView) + } + }) + } + + internal fun setHidden(screen: Screen, activity: Activity?) { + if (activity == null) { + return + } + val screenForHidden = findScreenForTrait(screen, WindowTraits.HIDDEN) + val hidden = screenForHidden?.isStatusBarHidden ?: false + val window = activity.window + val controller = WindowInsetsControllerCompat(window, window.decorView) + + UiThreadUtil.runOnUiThread { + if (hidden) { + controller.hide(WindowInsetsCompat.Type.statusBars()) + } else { + controller.show(WindowInsetsCompat.Type.statusBars()) + } + } + } + + // Methods concerning navigationBar management were taken from `react-native-navigation`'s repo: + // https://github.com/wix/react-native-navigation/blob/9bb70d81700692141a2c505c081c2d86c7f9c66e/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt + internal fun setNavigationBarColor(screen: Screen, activity: Activity?) { + if (activity == null) { + return + } + + val window = activity.window + + val screenForNavBarColor = findScreenForTrait(screen, WindowTraits.NAVIGATION_BAR_COLOR) + val color = screenForNavBarColor?.navigationBarColor ?: window.navigationBarColor + + UiThreadUtil.runOnUiThread { + WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightNavigationBars = + isColorLight(color) + } + window.navigationBarColor = color + } + + internal fun setNavigationBarHidden(screen: Screen, activity: Activity?) { + if (activity == null) { + return + } + + val window = activity.window + + val screenForNavBarHidden = findScreenForTrait(screen, WindowTraits.NAVIGATION_BAR_HIDDEN) + val hidden = screenForNavBarHidden?.isNavigationBarHidden ?: false + + WindowCompat.setDecorFitsSystemWindows(window, hidden) + if (hidden) { + WindowInsetsControllerCompat(window, window.decorView).let { controller -> + controller.hide(WindowInsetsCompat.Type.navigationBars()) + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + } else { + WindowInsetsControllerCompat( + window, + window.decorView + ).show(WindowInsetsCompat.Type.navigationBars()) + } + } + + internal fun trySetWindowTraits(screen: Screen, activity: Activity?, context: ReactContext?) { + if (mDidSetOrientation) { + setOrientation(screen, activity) + } + if (mDidSetStatusBarAppearance) { + setColor(screen, activity, context) + setStyle(screen, activity, context) + setTranslucent(screen, activity, context) + setHidden(screen, activity) + } + if (mDidSetNavigationBarAppearance) { + setNavigationBarColor(screen, activity) + setNavigationBarHidden(screen, activity) + } + } + + private fun findScreenForTrait(screen: Screen, trait: WindowTraits): Screen? { + val childWithTrait = childScreenWithTraitSet(screen, trait) + if (childWithTrait != null) { + return childWithTrait + } + return if (checkTraitForScreen(screen, trait)) { + screen + } else { + // if there is no child with trait set and this screen has no trait set, we look for a parent + // that has the trait set + findParentWithTraitSet(screen, trait) + } + } + + private fun findParentWithTraitSet(screen: Screen, trait: WindowTraits): Screen? { + var parent: ViewParent? = screen.container + while (parent != null) { + if (parent is Screen) { + if (checkTraitForScreen(parent, trait)) { + return parent + } + } + parent = parent.parent + } + return null + } + + private fun childScreenWithTraitSet( + screen: Screen?, + trait: WindowTraits + ): Screen? { + screen?.fragment?.let { + for (sc in it.childScreenContainers) { + // we check only the top screen for the trait + val topScreen = sc.topScreen + val child = childScreenWithTraitSet(topScreen, trait) + if (child != null) { + return child + } + if (topScreen != null && checkTraitForScreen(topScreen, trait)) { + return topScreen + } + } + } + return null + } + + private fun checkTraitForScreen(screen: Screen, trait: WindowTraits): Boolean { + return when (trait) { + WindowTraits.ORIENTATION -> screen.screenOrientation != null + WindowTraits.COLOR -> screen.statusBarColor != null + WindowTraits.STYLE -> screen.statusBarStyle != null + WindowTraits.TRANSLUCENT -> screen.isStatusBarTranslucent != null + WindowTraits.HIDDEN -> screen.isStatusBarHidden != null + WindowTraits.ANIMATED -> screen.isStatusBarAnimated != null + WindowTraits.NAVIGATION_BAR_COLOR -> screen.navigationBarColor != null + WindowTraits.NAVIGATION_BAR_HIDDEN -> screen.isNavigationBarHidden != null + } + } + + private fun isColorLight(color: Int): Boolean { + val darkness: Double = + 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255 + return darkness < 0.5 + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreensShadowNode.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreensShadowNode.kt new file mode 100644 index 00000000000000..141c981ef1cc89 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/ScreensShadowNode.kt @@ -0,0 +1,19 @@ +package abi49_0_0.com.swmansion.rnscreens + +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.LayoutShadowNode +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyManager +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyOptimizer +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule + +internal class ScreensShadowNode(private var mContext: ReactContext) : LayoutShadowNode() { + override fun onBeforeLayout(nativeViewHierarchyOptimizer: NativeViewHierarchyOptimizer) { + super.onBeforeLayout(nativeViewHierarchyOptimizer) + (mContext.getNativeModule(UIManagerModule::class.java))?.addUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager -> + val view = nativeViewHierarchyManager.resolveView(reactTag) + if (view is ScreenContainer<*>) { + view.performUpdates() + } + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchBarManager.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchBarManager.kt new file mode 100644 index 00000000000000..438b72801c5cd6 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchBarManager.kt @@ -0,0 +1,131 @@ +package abi49_0_0.com.swmansion.rnscreens + +import abi49_0_0.com.facebook.react.bridge.JSApplicationIllegalArgumentException +import abi49_0_0.com.facebook.react.bridge.ReadableArray +import abi49_0_0.com.facebook.react.common.MapBuilder +import abi49_0_0.com.facebook.react.module.annotations.ReactModule +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarBlurEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarChangeTextEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarCloseEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarFocusEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarOpenEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarSearchButtonPressEvent + +@ReactModule(name = SearchBarManager.REACT_CLASS) +class SearchBarManager : ViewGroupManager() { + override fun getName(): String { + return REACT_CLASS + } + + override fun createViewInstance(context: ThemedReactContext): SearchBarView { + return SearchBarView(context) + } + + override fun onAfterUpdateTransaction(view: SearchBarView) { + super.onAfterUpdateTransaction(view) + view.onUpdate() + } + + @ReactProp(name = "autoCapitalize") + fun setAutoCapitalize(view: SearchBarView, autoCapitalize: String?) { + view.autoCapitalize = when (autoCapitalize) { + null, "none" -> SearchBarView.SearchBarAutoCapitalize.NONE + "words" -> SearchBarView.SearchBarAutoCapitalize.WORDS + "sentences" -> SearchBarView.SearchBarAutoCapitalize.SENTENCES + "characters" -> SearchBarView.SearchBarAutoCapitalize.CHARACTERS + else -> throw JSApplicationIllegalArgumentException( + "Forbidden auto capitalize value passed" + ) + } + } + + @ReactProp(name = "autoFocus") + fun setAutoFocus(view: SearchBarView, autoFocus: Boolean?) { + view.autoFocus = autoFocus ?: false + } + + @ReactProp(name = "barTintColor", customType = "Color") + fun setTintColor(view: SearchBarView, color: Int?) { + view.tintColor = color + } + + @ReactProp(name = "disableBackButtonOverride") + fun setDisableBackButtonOverride(view: SearchBarView, disableBackButtonOverride: Boolean?) { + view.shouldOverrideBackButton = disableBackButtonOverride != true + } + + @ReactProp(name = "inputType") + fun setInputType(view: SearchBarView, inputType: String?) { + view.inputType = when (inputType) { + null, "text" -> SearchBarView.SearchBarInputTypes.TEXT + "phone" -> SearchBarView.SearchBarInputTypes.PHONE + "number" -> SearchBarView.SearchBarInputTypes.NUMBER + "email" -> SearchBarView.SearchBarInputTypes.EMAIL + else -> throw JSApplicationIllegalArgumentException( + "Forbidden input type value" + ) + } + } + + @ReactProp(name = "placeholder") + fun setPlaceholder(view: SearchBarView, placeholder: String?) { + if (placeholder != null) { + view.placeholder = placeholder + } + } + + @ReactProp(name = "textColor", customType = "Color") + fun setTextColor(view: SearchBarView, color: Int?) { + view.textColor = color + } + + @ReactProp(name = "headerIconColor", customType = "Color") + fun setHeaderIconColor(view: SearchBarView, color: Int?) { + view.headerIconColor = color + } + + @ReactProp(name = "hintTextColor", customType = "Color") + fun setHintTextColor(view: SearchBarView, color: Int?) { + view.hintTextColor = color + } + + @ReactProp(name = "shouldShowHintSearchIcon") + fun setShouldShowHintSearchIcon(view: SearchBarView, shouldShowHintSearchIcon: Boolean?) { + view.shouldShowHintSearchIcon = shouldShowHintSearchIcon ?: true + } + + override fun receiveCommand(root: SearchBarView, commandId: String?, args: ReadableArray?) { + when (commandId) { + "focus" -> root.handleFocusJsRequest() + "blur" -> root.handleBlurJsRequest() + "clearText" -> root.handleClearTextJsRequest() + "toggleCancelButton" -> root.handleToggleCancelButtonJsRequest(false) // just a dummy argument + "setText" -> root.handleSetTextJsRequest(args?.getString(0)) + else -> throw JSApplicationIllegalArgumentException("Unsupported native command received: $commandId") + } + } + + override fun getExportedCustomDirectEventTypeConstants(): Map? { + return MapBuilder.of( + SearchBarBlurEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onBlur"), + SearchBarChangeTextEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onChangeText"), + SearchBarCloseEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onClose"), + SearchBarFocusEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onFocus"), + SearchBarOpenEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onOpen"), + SearchBarSearchButtonPressEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onSearchButtonPress"), + ) + } + + companion object { + const val REACT_CLASS = "RNSSearchBar" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchBarView.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchBarView.kt new file mode 100644 index 00000000000000..924a54f6a8c71d --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchBarView.kt @@ -0,0 +1,176 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.annotation.SuppressLint +import android.text.InputType +import androidx.appcompat.widget.SearchView +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarBlurEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarChangeTextEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarCloseEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarFocusEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarOpenEvent +import abi49_0_0.com.swmansion.rnscreens.events.SearchBarSearchButtonPressEvent + +@SuppressLint("ViewConstructor") +class SearchBarView(reactContext: ReactContext?) : ReactViewGroup(reactContext) { + var inputType: SearchBarInputTypes = SearchBarInputTypes.TEXT + var autoCapitalize: SearchBarAutoCapitalize = SearchBarAutoCapitalize.NONE + var textColor: Int? = null + var tintColor: Int? = null + var headerIconColor: Int? = null + var hintTextColor: Int? = null + var placeholder: String = "" + var shouldOverrideBackButton: Boolean = true + var autoFocus: Boolean = false + var shouldShowHintSearchIcon: Boolean = true + + private var mSearchViewFormatter: SearchViewFormatter? = null + + private var mAreListenersSet: Boolean = false + + private val screenStackFragment: ScreenStackFragment? + get() { + val currentParent = parent + if (currentParent is ScreenStackHeaderSubview) { + return currentParent.config?.screenFragment + } + return null + } + + fun onUpdate() { + setSearchViewProps() + } + + private fun setSearchViewProps() { + val searchView = screenStackFragment?.searchView + if (searchView != null) { + if (!mAreListenersSet) { + setSearchViewListeners(searchView) + mAreListenersSet = true + } + + searchView.inputType = inputType.toAndroidInputType(autoCapitalize) + mSearchViewFormatter?.setTextColor(textColor) + mSearchViewFormatter?.setTintColor(tintColor) + mSearchViewFormatter?.setHeaderIconColor(headerIconColor) + mSearchViewFormatter?.setHintTextColor(hintTextColor) + mSearchViewFormatter?.setPlaceholder(placeholder, shouldShowHintSearchIcon) + searchView.overrideBackAction = shouldOverrideBackButton + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + screenStackFragment?.onSearchViewCreate = { newSearchView -> + if (mSearchViewFormatter == null) mSearchViewFormatter = + SearchViewFormatter(newSearchView) + setSearchViewProps() + if (autoFocus) { + screenStackFragment?.searchView?.focus() + } + } + } + + private fun setSearchViewListeners(searchView: SearchView) { + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextChange(newText: String?): Boolean { + handleTextChange(newText) + return true + } + + override fun onQueryTextSubmit(query: String?): Boolean { + handleTextSubmit(query) + return true + } + }) + searchView.setOnQueryTextFocusChangeListener { _, hasFocus -> + handleFocusChange(hasFocus) + } + searchView.setOnCloseListener { + handleClose() + false + } + searchView.setOnSearchClickListener { + handleOpen() + } + } + + private fun handleTextChange(newText: String?) { + sendEvent(SearchBarChangeTextEvent(id, newText)) + } + + private fun handleFocusChange(hasFocus: Boolean) { + sendEvent(if (hasFocus) SearchBarFocusEvent(id) else SearchBarBlurEvent(id)) + } + + private fun handleClose() { + sendEvent(SearchBarCloseEvent(id)) + } + + private fun handleOpen() { + sendEvent(SearchBarOpenEvent(id)) + } + + private fun handleTextSubmit(newText: String?) { + sendEvent(SearchBarSearchButtonPressEvent(id, newText)) + } + + private fun sendEvent(event: Event<*>) { + val eventDispatcher: EventDispatcher? = + UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id) + eventDispatcher?.dispatchEvent(event) + } + + fun handleClearTextJsRequest() { + screenStackFragment?.searchView?.clearText() + } + + fun handleFocusJsRequest() { + screenStackFragment?.searchView?.focus() + } + + fun handleBlurJsRequest() { + screenStackFragment?.searchView?.clearFocus() + } + + fun handleToggleCancelButtonJsRequest(flag: Boolean) = Unit + + fun handleSetTextJsRequest(text: String?) { + text?.let { screenStackFragment?.searchView?.setText(it) } + } + + enum class SearchBarAutoCapitalize { + NONE, WORDS, SENTENCES, CHARACTERS + } + + enum class SearchBarInputTypes { + TEXT { + override fun toAndroidInputType(capitalize: SearchBarAutoCapitalize) = + when (capitalize) { + SearchBarAutoCapitalize.NONE -> InputType.TYPE_CLASS_TEXT + SearchBarAutoCapitalize.WORDS -> InputType.TYPE_TEXT_FLAG_CAP_WORDS + SearchBarAutoCapitalize.SENTENCES -> InputType.TYPE_TEXT_FLAG_CAP_SENTENCES + SearchBarAutoCapitalize.CHARACTERS -> InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS + } + }, + PHONE { + override fun toAndroidInputType(capitalize: SearchBarAutoCapitalize) = + InputType.TYPE_CLASS_PHONE + }, + NUMBER { + override fun toAndroidInputType(capitalize: SearchBarAutoCapitalize) = + InputType.TYPE_CLASS_NUMBER + }, + EMAIL { + override fun toAndroidInputType(capitalize: SearchBarAutoCapitalize) = + InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS + }; + + abstract fun toAndroidInputType(capitalize: SearchBarAutoCapitalize): Int + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchViewFormatter.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchViewFormatter.kt new file mode 100644 index 00000000000000..07a148be96bee9 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/SearchViewFormatter.kt @@ -0,0 +1,67 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.graphics.drawable.Drawable +import android.view.View +import android.widget.EditText +import android.widget.ImageView +import androidx.appcompat.R +import androidx.appcompat.widget.SearchView + +class SearchViewFormatter(var searchView: SearchView) { + private var mDefaultTextColor: Int? = null + private var mDefaultTintBackground: Drawable? = null + + private val searchEditText + get() = searchView.findViewById(R.id.search_src_text) as? EditText + private val searchTextPlate + get() = searchView.findViewById(R.id.search_plate) + private val searchIcon + get() = searchView.findViewById(R.id.search_button) + private val searchCloseIcon + get() = searchView.findViewById(R.id.search_close_btn) + + fun setTextColor(textColor: Int?) { + val currentDefaultTextColor = mDefaultTextColor + if (textColor != null) { + if (mDefaultTextColor == null) { + mDefaultTextColor = searchEditText?.textColors?.defaultColor + } + searchEditText?.setTextColor(textColor) + } else if (currentDefaultTextColor != null) { + searchEditText?.setTextColor(currentDefaultTextColor) + } + } + + fun setTintColor(tintColor: Int?) { + val currentDefaultTintColor = mDefaultTintBackground + if (tintColor != null) { + if (mDefaultTintBackground == null) { + mDefaultTintBackground = searchTextPlate.background + } + searchTextPlate.setBackgroundColor(tintColor) + } else if (currentDefaultTintColor != null) { + searchTextPlate.background = currentDefaultTintColor + } + } + + fun setHeaderIconColor(headerIconColor: Int?) { + headerIconColor?.let { + searchIcon.setColorFilter(it) + searchCloseIcon.setColorFilter(it) + } + } + + fun setHintTextColor(hintTextColor: Int?) { + hintTextColor?.let { + searchEditText?.setHintTextColor(it) + } + } + + fun setPlaceholder(placeholder: String, shouldShowHintSearchIcon: Boolean) { + if (shouldShowHintSearchIcon) { + searchView.queryHint = placeholder + } else { + searchEditText?.hint = placeholder + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderAttachedEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderAttachedEvent.kt new file mode 100644 index 00000000000000..1f4f73fd91e4b0 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderAttachedEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class HeaderAttachedEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topAttached" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderBackButtonClickedEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderBackButtonClickedEvent.kt new file mode 100644 index 00000000000000..a39633e5d751b8 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderBackButtonClickedEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class HeaderBackButtonClickedEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topHeaderBackButtonClickedEvent" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderDetachedEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderDetachedEvent.kt new file mode 100644 index 00000000000000..378d3438353465 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/HeaderDetachedEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class HeaderDetachedEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topDetached" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenAppearEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenAppearEvent.kt new file mode 100644 index 00000000000000..8b109ca2be5517 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenAppearEvent.kt @@ -0,0 +1,20 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class ScreenAppearEvent(viewId: Int) : Event(viewId) { + override fun getEventName() = EVENT_NAME + + // All events for a given view can be coalesced. + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topAppear" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenDisappearEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenDisappearEvent.kt new file mode 100644 index 00000000000000..fc0dd6ce263154 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenDisappearEvent.kt @@ -0,0 +1,20 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class ScreenDisappearEvent(viewId: Int) : Event(viewId) { + override fun getEventName() = EVENT_NAME + + // All events for a given view can be coalesced. + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topDisappear" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenDismissedEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenDismissedEvent.kt new file mode 100644 index 00000000000000..955227d3a4b962 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenDismissedEvent.kt @@ -0,0 +1,23 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class ScreenDismissedEvent(viewId: Int) : Event(viewId) { + override fun getEventName() = EVENT_NAME + + // All events for a given view can be coalesced. + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + val args = Arguments.createMap() + // on Android we always dismiss one screen at a time + args.putInt("dismissCount", 1) + rctEventEmitter.receiveEvent(viewTag, eventName, args) + } + + companion object { + const val EVENT_NAME = "topDismissed" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenTransitionProgressEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenTransitionProgressEvent.kt new file mode 100644 index 00000000000000..7b11d60abb7f10 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenTransitionProgressEvent.kt @@ -0,0 +1,33 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class ScreenTransitionProgressEvent( + viewId: Int, + private val mProgress: Float, + private val mClosing: Boolean, + private val mGoingForward: Boolean, + private val mCoalescingKey: Short +) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + return mCoalescingKey + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + val map = Arguments.createMap() + map.putDouble("progress", mProgress.toDouble()) + map.putInt("closing", if (mClosing) 1 else 0) + map.putInt("goingForward", if (mGoingForward) 1 else 0) + rctEventEmitter.receiveEvent(viewTag, eventName, map) + } + + companion object { + const val EVENT_NAME = "topTransitionProgress" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenWillAppearEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenWillAppearEvent.kt new file mode 100644 index 00000000000000..e0580c31590148 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenWillAppearEvent.kt @@ -0,0 +1,20 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class ScreenWillAppearEvent(viewId: Int) : Event(viewId) { + override fun getEventName() = EVENT_NAME + + // All events for a given view can be coalesced. + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topWillAppear" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenWillDisappearEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenWillDisappearEvent.kt new file mode 100644 index 00000000000000..a76413dedb6cbe --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/ScreenWillDisappearEvent.kt @@ -0,0 +1,20 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class ScreenWillDisappearEvent(viewId: Int) : Event(viewId) { + override fun getEventName() = EVENT_NAME + + // All events for a given view can be coalesced. + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topWillDisappear" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarBlurEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarBlurEvent.kt new file mode 100644 index 00000000000000..c313952d77de1e --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarBlurEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class SearchBarBlurEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topBlur" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarChangeTextEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarChangeTextEvent.kt new file mode 100644 index 00000000000000..2a691ebb0d4e95 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarChangeTextEvent.kt @@ -0,0 +1,29 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class SearchBarChangeTextEvent( + viewId: Int, + private val text: String?, +) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + val map = Arguments.createMap() + map.putString("text", text) + rctEventEmitter.receiveEvent(viewTag, eventName, map) + } + + companion object { + const val EVENT_NAME = "topChangeText" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarCloseEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarCloseEvent.kt new file mode 100644 index 00000000000000..ad7136bfa1dc2e --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarCloseEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class SearchBarCloseEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topClose" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarFocusEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarFocusEvent.kt new file mode 100644 index 00000000000000..3c6dc7630d1936 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarFocusEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class SearchBarFocusEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topFocus" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarOpenEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarOpenEvent.kt new file mode 100644 index 00000000000000..e712d857ede474 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarOpenEvent.kt @@ -0,0 +1,24 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class SearchBarOpenEvent(viewId: Int) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topOpen" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarSearchButtonPressEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarSearchButtonPressEvent.kt new file mode 100644 index 00000000000000..c5330c51b07cd1 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/SearchBarSearchButtonPressEvent.kt @@ -0,0 +1,26 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class SearchBarSearchButtonPressEvent(viewId: Int, private val text: String?) : Event(viewId) { + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getCoalescingKey(): Short { + // All events for a given view can be coalesced. + return 0 + } + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + val map = Arguments.createMap() + map.putString("text", text) + rctEventEmitter.receiveEvent(viewTag, eventName, map) + } + + companion object { + const val EVENT_NAME = "topSearchButtonPress" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/StackFinishTransitioningEvent.kt b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/StackFinishTransitioningEvent.kt new file mode 100644 index 00000000000000..3b6112c73b7e7d --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/java/abi49_0_0/com/swmansion/rnscreens/events/StackFinishTransitioningEvent.kt @@ -0,0 +1,20 @@ +package abi49_0_0.com.swmansion.rnscreens.events + +import abi49_0_0.com.facebook.react.bridge.Arguments +import abi49_0_0.com.facebook.react.uimanager.events.Event +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter + +class StackFinishTransitioningEvent(viewId: Int) : Event(viewId) { + override fun getEventName() = EVENT_NAME + + // All events for a given view can be coalesced. + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) { + rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap()) + } + + companion object { + const val EVENT_NAME = "topFinishTransitioning" + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/jni/CMakeLists.txt b/android/vendored/sdk49/react-native-screens/android/src/main/jni/CMakeLists.txt new file mode 100644 index 00000000000000..3b388b4d994826 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/jni/CMakeLists.txt @@ -0,0 +1,72 @@ +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(LIB_LITERAL rnscreens) +set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL}) + +set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) +set(LIB_COMMON_DIR ${LIB_ANDROID_DIR}/../common/cpp) +set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni) +set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL}) + +add_compile_options( + -fexceptions + -frtti + -std=c++17 + -Wall + -Wpedantic + -Wno-gnu-zero-variadic-macro-arguments +) + +file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp) +file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp) + +add_library( + ${LIB_TARGET_NAME} + SHARED + ${LIB_CUSTOM_SRCS} + ${LIB_CODEGEN_SRCS} +) + +target_include_directories( + ${LIB_TARGET_NAME} + PUBLIC + . + ${LIB_COMMON_DIR} + ${LIB_ANDROID_GENERATED_JNI_DIR} + ${LIB_ANDROID_GENERATED_COMPONENTS_DIR} +) + +target_link_libraries( + ${LIB_TARGET_NAME} + fbjni + folly_runtime + glog + jsi + react_codegen_rncore + react_debug + react_nativemodule_core + react_render_core + react_render_debug + react_render_graphics + react_render_mapbuffer + rrc_view + turbomodulejsijni + yoga +) + +target_compile_options( + ${LIB_TARGET_NAME} + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++17 + -Wall +) + +target_include_directories( + ${CMAKE_PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/jni/rnscreens.cpp b/android/vendored/sdk49/react-native-screens/android/src/main/jni/rnscreens.cpp new file mode 100644 index 00000000000000..ce5c15084e2e8e --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/jni/rnscreens.cpp @@ -0,0 +1,16 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * @generated by codegen project: GenerateModuleJniCpp.js + */ +#include "rnscreens.h" + +namespace facebook { +namespace react { + + +std::shared_ptr rnscreens_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + return nullptr; +} + +} // namespace react +} // namespace facebook diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/jni/rnscreens.h b/android/vendored/sdk49/react-native-screens/android/src/main/jni/rnscreens.h new file mode 100644 index 00000000000000..2d755a0092ad77 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/jni/rnscreens.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +/** + * Note this import and that it is not present in autogenerated header file + * under android/build/generated/source/codegen/jni/rnscreens.h + * + * It is added here to make our custom symbols visible in autogenerated file with + * code responsible for registering component descriptor providers. See that rncli.cpp, + * located under /android/app/build/generated/rncli/src/main/jni/rncli.cpp, + * includes autogenerated rnscreens.h header by default. We change this behaviour + * by appropriate include path configuration so that this header file gets included. + * + * See: https://github.com/software-mansion/react-native-screens/pull/1585 + */ +#include + +namespace facebook { +namespace react { + +JSI_EXPORT +std::shared_ptr rnscreens_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace react +} // namespace facebook diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_enter_in.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_enter_in.xml new file mode 100644 index 00000000000000..4398c7efc09a29 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_enter_in.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_enter_out.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_enter_out.xml new file mode 100644 index 00000000000000..84c91759fe65f0 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_enter_out.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_exit_in.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_exit_in.xml new file mode 100644 index 00000000000000..6d6fa02acd19e0 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_exit_in.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_exit_out.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_exit_out.xml new file mode 100644 index 00000000000000..b20a184f8baebc --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_default_exit_out.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_from_bottom.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_from_bottom.xml new file mode 100644 index 00000000000000..c7a8abc07570e0 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_from_bottom.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_in.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_in.xml new file mode 100644 index 00000000000000..c78ea619df636f --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_in.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_out.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_out.xml new file mode 100644 index 00000000000000..334e63f34ebed0 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_out.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_to_bottom.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_to_bottom.xml new file mode 100644 index 00000000000000..23345211ffcf99 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_fade_to_bottom.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_20.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_20.xml new file mode 100644 index 00000000000000..5cc0d2385b1e26 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_20.xml @@ -0,0 +1,6 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_250.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_250.xml new file mode 100644 index 00000000000000..bd082a3e18e91f --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_250.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_350.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_350.xml new file mode 100644 index 00000000000000..003dcd1f17d3f5 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_350.xml @@ -0,0 +1,6 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_medium.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_medium.xml new file mode 100644 index 00000000000000..560eda670d2b8a --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_no_animation_medium.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_bottom.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_bottom.xml new file mode 100644 index 00000000000000..052fe150edea61 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_bottom.xml @@ -0,0 +1,7 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_left.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_left.xml new file mode 100644 index 00000000000000..939110f5437edf --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_left.xml @@ -0,0 +1,5 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_right.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_right.xml new file mode 100644 index 00000000000000..428eb9b71862ee --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_in_from_right.xml @@ -0,0 +1,5 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_bottom.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_bottom.xml new file mode 100644 index 00000000000000..6b75d2562fe629 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_bottom.xml @@ -0,0 +1,7 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_left.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_left.xml new file mode 100644 index 00000000000000..400a202c3bd6d8 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_left.xml @@ -0,0 +1,5 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_right.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_right.xml new file mode 100644 index 00000000000000..a00332bcdb1717 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_slide_out_to_right.xml @@ -0,0 +1,5 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_standard_accelerate_interpolator.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_standard_accelerate_interpolator.xml new file mode 100644 index 00000000000000..60c57e59d6b2ec --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/base/anim/rns_standard_accelerate_interpolator.xml @@ -0,0 +1,6 @@ + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_enter_in.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_enter_in.xml new file mode 100644 index 00000000000000..654c80bfbe663c --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_enter_in.xml @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_enter_out.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_enter_out.xml new file mode 100644 index 00000000000000..965d47f6c339a7 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_enter_out.xml @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_exit_in.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_exit_in.xml new file mode 100644 index 00000000000000..949ebb776d7c15 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_exit_in.xml @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_exit_out.xml b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_exit_out.xml new file mode 100644 index 00000000000000..ba4d84d6cdfda8 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/main/res/v33/anim-v33/rns_default_exit_out.xml @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java new file mode 100644 index 00000000000000..11292ae7b2a546 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java @@ -0,0 +1,111 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ColorPropConverter; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSScreenManagerDelegate & RNSScreenManagerInterface> extends BaseViewManagerDelegate { + public RNSScreenManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "sheetAllowedDetents": + mViewManager.setSheetAllowedDetents(view, (String) value); + break; + case "sheetLargestUndimmedDetent": + mViewManager.setSheetLargestUndimmedDetent(view, (String) value); + break; + case "sheetGrabberVisible": + mViewManager.setSheetGrabberVisible(view, value == null ? false : (boolean) value); + break; + case "sheetCornerRadius": + mViewManager.setSheetCornerRadius(view, value == null ? -1f : ((Double) value).floatValue()); + break; + case "sheetExpandsWhenScrolledToEdge": + mViewManager.setSheetExpandsWhenScrolledToEdge(view, value == null ? false : (boolean) value); + break; + case "customAnimationOnSwipe": + mViewManager.setCustomAnimationOnSwipe(view, value == null ? false : (boolean) value); + break; + case "fullScreenSwipeEnabled": + mViewManager.setFullScreenSwipeEnabled(view, value == null ? false : (boolean) value); + break; + case "homeIndicatorHidden": + mViewManager.setHomeIndicatorHidden(view, value == null ? false : (boolean) value); + break; + case "preventNativeDismiss": + mViewManager.setPreventNativeDismiss(view, value == null ? false : (boolean) value); + break; + case "gestureEnabled": + mViewManager.setGestureEnabled(view, value == null ? true : (boolean) value); + break; + case "statusBarColor": + mViewManager.setStatusBarColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "statusBarHidden": + mViewManager.setStatusBarHidden(view, value == null ? false : (boolean) value); + break; + case "screenOrientation": + mViewManager.setScreenOrientation(view, value == null ? null : (String) value); + break; + case "statusBarAnimation": + mViewManager.setStatusBarAnimation(view, value == null ? null : (String) value); + break; + case "statusBarStyle": + mViewManager.setStatusBarStyle(view, value == null ? null : (String) value); + break; + case "statusBarTranslucent": + mViewManager.setStatusBarTranslucent(view, value == null ? false : (boolean) value); + break; + case "gestureResponseDistance": + mViewManager.setGestureResponseDistance(view, (ReadableMap) value); + break; + case "stackPresentation": + mViewManager.setStackPresentation(view, (String) value); + break; + case "stackAnimation": + mViewManager.setStackAnimation(view, (String) value); + break; + case "transitionDuration": + mViewManager.setTransitionDuration(view, value == null ? 350 : ((Double) value).intValue()); + break; + case "replaceAnimation": + mViewManager.setReplaceAnimation(view, (String) value); + break; + case "swipeDirection": + mViewManager.setSwipeDirection(view, (String) value); + break; + case "hideKeyboardOnSwipe": + mViewManager.setHideKeyboardOnSwipe(view, value == null ? false : (boolean) value); + break; + case "activityState": + mViewManager.setActivityState(view, value == null ? -1f : ((Double) value).floatValue()); + break; + case "navigationBarColor": + mViewManager.setNavigationBarColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "navigationBarHidden": + mViewManager.setNavigationBarHidden(view, value == null ? false : (boolean) value); + break; + case "nativeBackButtonDismissalEnabled": + mViewManager.setNativeBackButtonDismissalEnabled(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java new file mode 100644 index 00000000000000..b7db21e105918e --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java @@ -0,0 +1,44 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSScreenManagerInterface { + void setSheetAllowedDetents(T view, @Nullable String value); + void setSheetLargestUndimmedDetent(T view, @Nullable String value); + void setSheetGrabberVisible(T view, boolean value); + void setSheetCornerRadius(T view, float value); + void setSheetExpandsWhenScrolledToEdge(T view, boolean value); + void setCustomAnimationOnSwipe(T view, boolean value); + void setFullScreenSwipeEnabled(T view, boolean value); + void setHomeIndicatorHidden(T view, boolean value); + void setPreventNativeDismiss(T view, boolean value); + void setGestureEnabled(T view, boolean value); + void setStatusBarColor(T view, @Nullable Integer value); + void setStatusBarHidden(T view, boolean value); + void setScreenOrientation(T view, @Nullable String value); + void setStatusBarAnimation(T view, @Nullable String value); + void setStatusBarStyle(T view, @Nullable String value); + void setStatusBarTranslucent(T view, boolean value); + void setGestureResponseDistance(T view, @Nullable ReadableMap value); + void setStackPresentation(T view, @Nullable String value); + void setStackAnimation(T view, @Nullable String value); + void setTransitionDuration(T view, int value); + void setReplaceAnimation(T view, @Nullable String value); + void setSwipeDirection(T view, @Nullable String value); + void setHideKeyboardOnSwipe(T view, boolean value); + void setActivityState(T view, float value); + void setNavigationBarColor(T view, @Nullable Integer value); + void setNavigationBarHidden(T view, boolean value); + void setNativeBackButtonDismissalEnabled(T view, boolean value); +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java new file mode 100644 index 00000000000000..933ee0abd14d7b --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java @@ -0,0 +1,107 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ColorPropConverter; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSScreenStackHeaderConfigManagerDelegate & RNSScreenStackHeaderConfigManagerInterface> extends BaseViewManagerDelegate { + public RNSScreenStackHeaderConfigManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "backgroundColor": + mViewManager.setBackgroundColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "backTitle": + mViewManager.setBackTitle(view, value == null ? null : (String) value); + break; + case "backTitleFontFamily": + mViewManager.setBackTitleFontFamily(view, value == null ? null : (String) value); + break; + case "backTitleFontSize": + mViewManager.setBackTitleFontSize(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "backTitleVisible": + mViewManager.setBackTitleVisible(view, value == null ? true : (boolean) value); + break; + case "color": + mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "direction": + mViewManager.setDirection(view, (String) value); + break; + case "hidden": + mViewManager.setHidden(view, value == null ? false : (boolean) value); + break; + case "hideShadow": + mViewManager.setHideShadow(view, value == null ? false : (boolean) value); + break; + case "largeTitle": + mViewManager.setLargeTitle(view, value == null ? false : (boolean) value); + break; + case "largeTitleFontFamily": + mViewManager.setLargeTitleFontFamily(view, value == null ? null : (String) value); + break; + case "largeTitleFontSize": + mViewManager.setLargeTitleFontSize(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "largeTitleFontWeight": + mViewManager.setLargeTitleFontWeight(view, value == null ? null : (String) value); + break; + case "largeTitleBackgroundColor": + mViewManager.setLargeTitleBackgroundColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "largeTitleHideShadow": + mViewManager.setLargeTitleHideShadow(view, value == null ? false : (boolean) value); + break; + case "largeTitleColor": + mViewManager.setLargeTitleColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "translucent": + mViewManager.setTranslucent(view, value == null ? false : (boolean) value); + break; + case "title": + mViewManager.setTitle(view, value == null ? null : (String) value); + break; + case "titleFontFamily": + mViewManager.setTitleFontFamily(view, value == null ? null : (String) value); + break; + case "titleFontSize": + mViewManager.setTitleFontSize(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "titleFontWeight": + mViewManager.setTitleFontWeight(view, value == null ? null : (String) value); + break; + case "titleColor": + mViewManager.setTitleColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "disableBackButtonMenu": + mViewManager.setDisableBackButtonMenu(view, value == null ? false : (boolean) value); + break; + case "hideBackButton": + mViewManager.setHideBackButton(view, value == null ? false : (boolean) value); + break; + case "backButtonInCustomView": + mViewManager.setBackButtonInCustomView(view, value == null ? false : (boolean) value); + break; + case "topInsetEnabled": + mViewManager.setTopInsetEnabled(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java new file mode 100644 index 00000000000000..b15e5c4f4ec444 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java @@ -0,0 +1,42 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface RNSScreenStackHeaderConfigManagerInterface { + void setBackgroundColor(T view, @Nullable Integer value); + void setBackTitle(T view, @Nullable String value); + void setBackTitleFontFamily(T view, @Nullable String value); + void setBackTitleFontSize(T view, int value); + void setBackTitleVisible(T view, boolean value); + void setColor(T view, @Nullable Integer value); + void setDirection(T view, @Nullable String value); + void setHidden(T view, boolean value); + void setHideShadow(T view, boolean value); + void setLargeTitle(T view, boolean value); + void setLargeTitleFontFamily(T view, @Nullable String value); + void setLargeTitleFontSize(T view, int value); + void setLargeTitleFontWeight(T view, @Nullable String value); + void setLargeTitleBackgroundColor(T view, @Nullable Integer value); + void setLargeTitleHideShadow(T view, boolean value); + void setLargeTitleColor(T view, @Nullable Integer value); + void setTranslucent(T view, boolean value); + void setTitle(T view, @Nullable String value); + void setTitleFontFamily(T view, @Nullable String value); + void setTitleFontSize(T view, int value); + void setTitleFontWeight(T view, @Nullable String value); + void setTitleColor(T view, @Nullable Integer value); + void setDisableBackButtonMenu(T view, boolean value); + void setHideBackButton(T view, boolean value); + void setBackButtonInCustomView(T view, boolean value); + void setTopInsetEnabled(T view, boolean value); +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java new file mode 100644 index 00000000000000..1b752d1d3f27e0 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java @@ -0,0 +1,31 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSScreenStackHeaderSubviewManagerDelegate & RNSScreenStackHeaderSubviewManagerInterface> extends BaseViewManagerDelegate { + public RNSScreenStackHeaderSubviewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "type": + mViewManager.setType(view, (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java new file mode 100644 index 00000000000000..370617ece3262c --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java @@ -0,0 +1,17 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface RNSScreenStackHeaderSubviewManagerInterface { + void setType(T view, @Nullable String value); +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackManagerDelegate.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackManagerDelegate.java new file mode 100644 index 00000000000000..094d0072e22db1 --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackManagerDelegate.java @@ -0,0 +1,25 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSScreenStackManagerDelegate & RNSScreenStackManagerInterface> extends BaseViewManagerDelegate { + public RNSScreenStackManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + super.setProperty(view, propName, value); + } +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java new file mode 100644 index 00000000000000..f4bc55287ae04e --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java @@ -0,0 +1,16 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; + +public interface RNSScreenStackManagerInterface { + // No props +} diff --git a/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/swmansion/rnscreens/FabricEnabledViewGroup.kt b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/swmansion/rnscreens/FabricEnabledViewGroup.kt new file mode 100644 index 00000000000000..faf772aef8e92f --- /dev/null +++ b/android/vendored/sdk49/react-native-screens/android/src/paper/java/abi49_0_0/com/swmansion/rnscreens/FabricEnabledViewGroup.kt @@ -0,0 +1,10 @@ +package abi49_0_0.com.swmansion.rnscreens + +import android.view.ViewGroup +import abi49_0_0.com.facebook.react.bridge.ReactContext + +abstract class FabricEnabledViewGroup constructor(context: ReactContext?) : ViewGroup(context) { + protected fun updateScreenSizeFabric(width: Int, height: Int) { + // do nothing + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/build.gradle b/android/vendored/sdk49/react-native-svg/android/build.gradle new file mode 100644 index 00000000000000..fbe5d6e8e22642 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/build.gradle @@ -0,0 +1,105 @@ +buildscript { + // The Android Gradle plugin is only required when opening the android folder stand-alone. + // This avoids unnecessary downloads and potential conflicts when the library is included as a + // module dependency in an application project. + if (project == rootProject) { + repositories { + mavenCentral() + google() + } + + dependencies { + classpath("com.android.tools.build:gradle:7.4.2") + classpath "com.diffplug.spotless:spotless-plugin-gradle:6.17.0" + } + } +} + +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + +if (isNewArchitectureEnabled()) { + apply plugin: "com.facebook.react" +} + +if (project == rootProject) { + apply from: 'spotless.gradle' +} + +apply plugin: 'com.android.library' + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +android { + compileSdkVersion safeExtGet('compileSdkVersion', 28) + def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION + if (agpVersion.tokenize('.')[0].toInteger() >= 7) { + namespace "abi49_0_0.com.horcrux.svg" + } + // Used to override the NDK path/version on internal CI or by allowing + // users to customize the NDK path/version from their root project (e.g. for M1 support) + if (rootProject.hasProperty("ndkPath")) { + ndkPath rootProject.ext.ndkPath + } + if (rootProject.hasProperty("ndkVersion")) { + ndkVersion rootProject.ext.ndkVersion + } + + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', 16) + //noinspection OldTargetApi + targetSdkVersion safeExtGet('targetSdkVersion', 28) + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + + consumerProguardFiles 'proguard-rules.pro' + } + lintOptions { + abortOnError false + } + + sourceSets.main { + java { + if (!isNewArchitectureEnabled()) { + srcDirs += [ + "src/paper/java", + "build/generated/source/codegen/java" + ] + } + } + } +} + +repositories { + mavenCentral() + mavenLocal() + google() + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "$rootDir/../node_modules/versioned-react-native/packages/react-native/android" + } +} + +dependencies { + implementation 'host.exp:reactandroid-abi49_0_0:1.0.0' + compileOnly 'com.facebook.fresco:fresco:+' + compileOnly 'com.facebook.fresco:imagepipeline-okhttp3:+' + compileOnly 'com.facebook.fresco:ui-common:+' + compileOnly 'javax.inject:javax.inject:+' + compileOnly 'com.facebook.fbjni:fbjni:+' + compileOnly 'com.facebook.yoga:proguard-annotations:+' + compileOnly 'com.facebook.soloader:soloader:+' + compileOnly 'com.facebook.fresco:fbcore:+' + compileOnly 'com.facebook.infer.annotation:infer-annotation:+' + compileOnly 'androidx.annotation:annotation:+' + compileOnly 'com.google.code.findbugs:jsr305:+' + compileOnly 'androidx.appcompat:appcompat:+' + compileOnly 'androidx.swiperefreshlayout:swiperefreshlayout:+' + +} diff --git a/android/vendored/sdk49/react-native-svg/android/proguard-rules.pro b/android/vendored/sdk49/react-native-svg/android/proguard-rules.pro new file mode 100644 index 00000000000000..19f9ddebfcaa0b --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/proguard-rules.pro @@ -0,0 +1 @@ +-keep public class com.horcrux.svg.** {*;} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/AndroidManifest.xml b/android/vendored/sdk49/react-native-svg/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..1d8f3c9fa04c96 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/Brush.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/Brush.java new file mode 100644 index 00000000000000..94839c4b25bfd2 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/Brush.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.common.ReactConstants; + +class Brush { + private final BrushType mType; + private final SVGLength[] mPoints; + private ReadableArray mColors; + private final boolean mUseObjectBoundingBox; + + // TODO implement pattern units + @SuppressWarnings({"unused"}) + private boolean mUseContentObjectBoundingBoxUnits; + + private Matrix mMatrix; + private Rect mUserSpaceBoundingBox; + private PatternView mPattern; + + Brush(BrushType type, SVGLength[] points, BrushUnits units) { + mType = type; + mPoints = points; + mUseObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX; + } + + void setContentUnits(BrushUnits units) { + mUseContentObjectBoundingBoxUnits = units == BrushUnits.OBJECT_BOUNDING_BOX; + } + + void setPattern(PatternView pattern) { + mPattern = pattern; + } + + enum BrushType { + LINEAR_GRADIENT, + RADIAL_GRADIENT, + PATTERN + } + + enum BrushUnits { + OBJECT_BOUNDING_BOX, + USER_SPACE_ON_USE + } + + private static void parseGradientStops( + ReadableArray value, int stopsCount, float[] stops, int[] stopsColors, float opacity) { + for (int i = 0; i < stopsCount; i++) { + int stopIndex = i * 2; + stops[i] = (float) value.getDouble(stopIndex); + int color = value.getInt(stopIndex + 1); + int alpha = color >>> 24; + int combined = Math.round((float) alpha * opacity); + stopsColors[i] = combined << 24 | (color & 0x00ffffff); + } + } + + void setUserSpaceBoundingBox(Rect userSpaceBoundingBox) { + mUserSpaceBoundingBox = userSpaceBoundingBox; + } + + void setGradientColors(ReadableArray colors) { + mColors = colors; + } + + void setGradientTransform(Matrix matrix) { + mMatrix = matrix; + } + + private RectF getPaintRect(RectF pathBoundingBox) { + RectF rect = mUseObjectBoundingBox ? pathBoundingBox : new RectF(mUserSpaceBoundingBox); + float width = rect.width(); + float height = rect.height(); + float x = 0f; + float y = 0f; + + if (mUseObjectBoundingBox) { + x = rect.left; + y = rect.top; + } + + return new RectF(x, y, x + width, y + height); + } + + private double getVal(SVGLength length, double relative, float scale, float textSize) { + return PropHelper.fromRelative( + length, + relative, + 0, + mUseObjectBoundingBox && length.unit == SVGLength.UnitType.NUMBER ? relative : scale, + textSize); + } + + void setupPaint(Paint paint, RectF pathBoundingBox, float scale, float opacity) { + RectF rect = getPaintRect(pathBoundingBox); + float width = rect.width(); + float height = rect.height(); + float offsetX = rect.left; + float offsetY = rect.top; + + float textSize = paint.getTextSize(); + if (mType == BrushType.PATTERN) { + double x = getVal(mPoints[0], width, scale, textSize); + double y = getVal(mPoints[1], height, scale, textSize); + double w = getVal(mPoints[2], width, scale, textSize); + double h = getVal(mPoints[3], height, scale, textSize); + + if (!(w > 1 && h > 1)) { + return; + } + + Bitmap bitmap = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + RectF vbRect = mPattern.getViewBox(); + if (vbRect != null && vbRect.width() > 0 && vbRect.height() > 0) { + RectF eRect = new RectF((float) x, (float) y, (float) w, (float) h); + Matrix mViewBoxMatrix = + ViewBox.getTransform(vbRect, eRect, mPattern.mAlign, mPattern.mMeetOrSlice); + canvas.concat(mViewBoxMatrix); + } + + if (mUseContentObjectBoundingBoxUnits) { + canvas.scale(width / scale, height / scale); + } + + mPattern.draw(canvas, new Paint(), opacity); + + Matrix patternMatrix = new Matrix(); + if (mMatrix != null) { + patternMatrix.preConcat(mMatrix); + } + + BitmapShader bitmapShader = + new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); + bitmapShader.setLocalMatrix(patternMatrix); + paint.setShader(bitmapShader); + return; + } + + int size = mColors.size(); + if (size == 0) { + FLog.w(ReactConstants.TAG, "Gradient contains no stops"); + return; + } + int stopsCount = size / 2; + int[] stopsColors = new int[stopsCount]; + float[] stops = new float[stopsCount]; + parseGradientStops(mColors, stopsCount, stops, stopsColors, opacity); + + if (stops.length == 1) { + // Gradient with only one stop will make LinearGradient/RadialGradient + // throw. It may happen when source SVG contains only one stop or + // two stops at the same spot (see lib/extract/extractGradient.js). + // Although it's mistake SVGs like this can be produced by vector + // editors or other tools, so let's handle that gracefully. + stopsColors = new int[] {stopsColors[0], stopsColors[0]}; + stops = new float[] {stops[0], stops[0]}; + FLog.w(ReactConstants.TAG, "Gradient contains only one stop"); + } + + if (mType == BrushType.LINEAR_GRADIENT) { + double x1 = getVal(mPoints[0], width, scale, textSize) + offsetX; + double y1 = getVal(mPoints[1], height, scale, textSize) + offsetY; + double x2 = getVal(mPoints[2], width, scale, textSize) + offsetX; + double y2 = getVal(mPoints[3], height, scale, textSize) + offsetY; + + Shader linearGradient = + new LinearGradient( + (float) x1, + (float) y1, + (float) x2, + (float) y2, + stopsColors, + stops, + Shader.TileMode.CLAMP); + + if (mMatrix != null) { + Matrix m = new Matrix(); + m.preConcat(mMatrix); + linearGradient.setLocalMatrix(m); + } + + paint.setShader(linearGradient); + } else if (mType == BrushType.RADIAL_GRADIENT) { + double rx = getVal(mPoints[2], width, scale, textSize); + double ry = getVal(mPoints[3], height, scale, textSize); + + double ratio = ry / rx; + + double cx = getVal(mPoints[4], width, scale, textSize) + offsetX; + double cy = getVal(mPoints[5], height / ratio, scale, textSize) + offsetY / ratio; + + // TODO: support focus point. + // double fx = PropHelper.fromRelative(mPoints[0], width, offsetX, scale); + // double fy = PropHelper.fromRelative(mPoints[1], height, offsetY, scale) / (ry / rx); + + Shader radialGradient = + new RadialGradient( + (float) cx, (float) cy, (float) rx, stopsColors, stops, Shader.TileMode.CLAMP); + + Matrix radialMatrix = new Matrix(); + radialMatrix.preScale(1f, (float) ratio); + + if (mMatrix != null) { + radialMatrix.preConcat(mMatrix); + } + + radialGradient.setLocalMatrix(radialMatrix); + paint.setShader(radialGradient); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/CircleView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/CircleView.java new file mode 100644 index 00000000000000..38aed601c74a25 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/CircleView.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import java.util.ArrayList; + +@SuppressLint("ViewConstructor") +class CircleView extends RenderableView { + private SVGLength mCx; + private SVGLength mCy; + private SVGLength mR; + + public CircleView(ReactContext reactContext) { + super(reactContext); + } + + public void setCx(Dynamic cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCx(String cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCx(Double cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCy(Dynamic cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setCy(String cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setCy(Double cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setR(Dynamic r) { + mR = SVGLength.from(r); + invalidate(); + } + + public void setR(String r) { + mR = SVGLength.from(r); + invalidate(); + } + + public void setR(Double r) { + mR = SVGLength.from(r); + invalidate(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + Path path = new Path(); + + double cx = relativeOnWidth(mCx); + double cy = relativeOnHeight(mCy); + double r = relativeOnOther(mR); + + path.addCircle((float) cx, (float) cy, (float) r, Path.Direction.CW); + + elements = new ArrayList<>(); + elements.add( + new PathElement( + ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(cx, cy - r)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx, cy - r), new Point(cx + r, cy)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx + r, cy), new Point(cx, cy + r)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx, cy + r), new Point(cx - r, cy)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx - r, cy), new Point(cx, cy - r)})); + + return path; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ClipPathView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ClipPathView.java new file mode 100644 index 00000000000000..c741479c59ca66 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ClipPathView.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.common.ReactConstants; + +@SuppressLint("ViewConstructor") +class ClipPathView extends GroupView { + + public ClipPathView(ReactContext reactContext) { + super(reactContext); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + FLog.w( + ReactConstants.TAG, + "RNSVG: ClipPath can't be drawn, it should be defined as a child component for `Defs` "); + } + + @Override + void saveDefinition() { + getSvgView().defineClipPath(this, mName); + } + + @Override + boolean isResponsible() { + return false; + } + + @Override + int hitTest(float[] src) { + return -1; + } + + @Override + void mergeProperties(RenderableView target) {} + + @Override + void resetProperties() {} +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/DefinitionView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/DefinitionView.java new file mode 100644 index 00000000000000..9a88074eb58a2f --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/DefinitionView.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class DefinitionView extends VirtualView { + + DefinitionView(ReactContext reactContext) { + super(reactContext); + } + + @SuppressWarnings("EmptyMethod") + void draw(Canvas canvas, Paint paint, float opacity) {} + + @Override + boolean isResponsible() { + return false; + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + return null; + } + + @Override + int hitTest(float[] src) { + return -1; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/DefsView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/DefsView.java new file mode 100644 index 00000000000000..0c1d3f4588e914 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/DefsView.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.View; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class DefsView extends DefinitionView { + + public DefsView(ReactContext reactContext) { + super(reactContext); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) {} + + void saveDefinition() { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof VirtualView) { + ((VirtualView) child).saveDefinition(); + } + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/EllipseView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/EllipseView.java new file mode 100644 index 00000000000000..50563f061b2cce --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/EllipseView.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import java.util.ArrayList; + +@SuppressLint("ViewConstructor") +class EllipseView extends RenderableView { + private SVGLength mCx; + private SVGLength mCy; + private SVGLength mRx; + private SVGLength mRy; + + public EllipseView(ReactContext reactContext) { + super(reactContext); + } + + public void setCx(Dynamic cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCx(String cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCx(Double cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCy(Dynamic cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setCy(String cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setCy(Double cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setRx(Dynamic rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRx(String rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRx(Double rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRy(Dynamic ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setRy(String ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setRy(Double ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + Path path = new Path(); + double cx = relativeOnWidth(mCx); + double cy = relativeOnHeight(mCy); + double rx = relativeOnWidth(mRx); + double ry = relativeOnHeight(mRy); + RectF oval = + new RectF((float) (cx - rx), (float) (cy - ry), (float) (cx + rx), (float) (cy + ry)); + path.addOval(oval, Path.Direction.CW); + + elements = new ArrayList<>(); + elements.add( + new PathElement( + ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(cx, cy - ry)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx, cy - ry), new Point(cx + rx, cy)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx + rx, cy), new Point(cx, cy + ry)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx, cy + ry), new Point(cx - rx, cy)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, + new Point[] {new Point(cx - rx, cy), new Point(cx, cy - ry)})); + + return path; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/FontData.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/FontData.java new file mode 100644 index 00000000000000..eedf35bb5af3f9 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/FontData.java @@ -0,0 +1,232 @@ +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FONT_FAMILY; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FONT_SIZE; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FONT_STYLE; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FONT_WEIGHT; +import static abi49_0_0.com.horcrux.svg.TextProperties.*; + +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableType; + +class FontData { + + static class AbsoluteFontWeight { + + static final int normal = 400; + + private static final FontWeight[] WEIGHTS = + new FontWeight[] { + FontWeight.w100, + FontWeight.w100, + FontWeight.w200, + FontWeight.w300, + FontWeight.Normal, + FontWeight.w500, + FontWeight.w600, + FontWeight.Bold, + FontWeight.w800, + FontWeight.w900, + FontWeight.w900, + }; + + static FontWeight nearestFontWeight(int absoluteFontWeight) { + return WEIGHTS[Math.round(absoluteFontWeight / 100f)]; + } + + private static final int[] absoluteFontWeights = + new int[] {400, 700, 100, 200, 300, 400, 500, 600, 700, 800, 900}; + + // https://drafts.csswg.org/css-fonts-4/#relative-weights + static int from(FontWeight fontWeight, FontData parent) { + if (fontWeight == FontWeight.Bolder) { + return bolder(parent.absoluteFontWeight); + } else if (fontWeight == FontWeight.Lighter) { + return lighter(parent.absoluteFontWeight); + } else { + return absoluteFontWeights[fontWeight.ordinal()]; + } + } + + private static int bolder(int inherited) { + if (inherited < 350) { + return 400; + } else if (inherited < 550) { + return 700; + } else if (inherited < 900) { + return 900; + } else { + return inherited; + } + } + + private static int lighter(int inherited) { + if (inherited < 100) { + return inherited; + } else if (inherited < 550) { + return 100; + } else if (inherited < 750) { + return 400; + } else { + return 700; + } + } + } + + static final double DEFAULT_FONT_SIZE = 12d; + + private static final double DEFAULT_KERNING = 0d; + private static final double DEFAULT_WORD_SPACING = 0d; + private static final double DEFAULT_LETTER_SPACING = 0d; + + private static final String KERNING = "kerning"; + private static final String FONT_DATA = "fontData"; + private static final String TEXT_ANCHOR = "textAnchor"; + private static final String WORD_SPACING = "wordSpacing"; + private static final String LETTER_SPACING = "letterSpacing"; + private static final String TEXT_DECORATION = "textDecoration"; + private static final String FONT_FEATURE_SETTINGS = "fontFeatureSettings"; + private static final String FONT_VARIATION_SETTINGS = "fontVariationSettings"; + private static final String FONT_VARIANT_LIGATURES = "fontVariantLigatures"; + + final double fontSize; + final String fontFamily; + final FontStyle fontStyle; + final ReadableMap fontData; + + FontWeight fontWeight; + int absoluteFontWeight; + + final String fontFeatureSettings; + final String fontVariationSettings; + final FontVariantLigatures fontVariantLigatures; + + final TextAnchor textAnchor; + private final TextDecoration textDecoration; + + final double kerning; + final double wordSpacing; + final double letterSpacing; + + final boolean manualKerning; + + static final FontData Defaults = new FontData(); + + private FontData() { + fontData = null; + fontFamily = ""; + fontStyle = FontStyle.normal; + fontWeight = FontWeight.Normal; + absoluteFontWeight = AbsoluteFontWeight.normal; + fontFeatureSettings = ""; + fontVariationSettings = ""; + fontVariantLigatures = FontVariantLigatures.normal; + + textAnchor = TextAnchor.start; + textDecoration = TextDecoration.None; + + manualKerning = false; + kerning = DEFAULT_KERNING; + fontSize = DEFAULT_FONT_SIZE; + wordSpacing = DEFAULT_WORD_SPACING; + letterSpacing = DEFAULT_LETTER_SPACING; + } + + private double toAbsolute( + ReadableMap font, String prop, double scale, double fontSize, double relative) { + ReadableType propType = font.getType(prop); + if (propType == ReadableType.Number) { + return font.getDouble(prop); + } else { + String string = font.getString(prop); + return PropHelper.fromRelative(string, relative, scale, fontSize); + } + } + + private void setInheritedWeight(FontData parent) { + absoluteFontWeight = parent.absoluteFontWeight; + fontWeight = parent.fontWeight; + } + + private void handleNumericWeight(FontData parent, double number) { + long weight = Math.round(number); + if (weight >= 1 && weight <= 1000) { + absoluteFontWeight = (int) weight; + fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight); + } else { + setInheritedWeight(parent); + } + } + + FontData(ReadableMap font, FontData parent, double scale) { + double parentFontSize = parent.fontSize; + + if (font.hasKey(FONT_SIZE)) { + fontSize = toAbsolute(font, FONT_SIZE, 1, parentFontSize, parentFontSize); + } else { + fontSize = parentFontSize; + } + + if (font.hasKey(FONT_WEIGHT)) { + ReadableType fontWeightType = font.getType(FONT_WEIGHT); + if (fontWeightType == ReadableType.Number) { + handleNumericWeight(parent, font.getDouble(FONT_WEIGHT)); + } else { + String string = font.getString(FONT_WEIGHT); + if (FontWeight.hasEnum(string)) { + absoluteFontWeight = AbsoluteFontWeight.from(FontWeight.get(string), parent); + fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight); + } else if (string != null) { + handleNumericWeight(parent, Double.parseDouble(string)); + } else { + setInheritedWeight(parent); + } + } + } else { + setInheritedWeight(parent); + } + + fontData = font.hasKey(FONT_DATA) ? font.getMap(FONT_DATA) : parent.fontData; + + fontFamily = font.hasKey(FONT_FAMILY) ? font.getString(FONT_FAMILY) : parent.fontFamily; + fontStyle = + font.hasKey(FONT_STYLE) ? FontStyle.valueOf(font.getString(FONT_STYLE)) : parent.fontStyle; + fontFeatureSettings = + font.hasKey(FONT_FEATURE_SETTINGS) + ? font.getString(FONT_FEATURE_SETTINGS) + : parent.fontFeatureSettings; + fontVariationSettings = + font.hasKey(FONT_VARIATION_SETTINGS) + ? font.getString(FONT_VARIATION_SETTINGS) + : parent.fontVariationSettings; + fontVariantLigatures = + font.hasKey(FONT_VARIANT_LIGATURES) + ? FontVariantLigatures.valueOf(font.getString(FONT_VARIANT_LIGATURES)) + : parent.fontVariantLigatures; + + textAnchor = + font.hasKey(TEXT_ANCHOR) + ? TextAnchor.valueOf(font.getString(TEXT_ANCHOR)) + : parent.textAnchor; + textDecoration = + font.hasKey(TEXT_DECORATION) + ? TextDecoration.getEnum(font.getString(TEXT_DECORATION)) + : parent.textDecoration; + + final boolean hasKerning = font.hasKey(KERNING); + manualKerning = hasKerning || parent.manualKerning; + + // https://www.w3.org/TR/SVG11/text.html#SpacingProperties + // https://drafts.csswg.org/css-text-3/#spacing + // calculated values for units in: kerning, word-spacing, and, letter-spacing. + kerning = hasKerning ? toAbsolute(font, KERNING, scale, fontSize, 0) : parent.kerning; + wordSpacing = + font.hasKey(WORD_SPACING) + ? toAbsolute(font, WORD_SPACING, scale, fontSize, 0) + : parent.wordSpacing; + letterSpacing = + font.hasKey(LETTER_SPACING) + ? toAbsolute(font, LETTER_SPACING, scale, fontSize, 0) + : parent.letterSpacing; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ForeignObjectView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ForeignObjectView.java new file mode 100644 index 00000000000000..ac46e3cdeb8a42 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ForeignObjectView.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.view.View; +import androidx.annotation.NonNull; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class ForeignObjectView extends GroupView { + + SVGLength mX; + SVGLength mY; + SVGLength mW; + SVGLength mH; + + public ForeignObjectView(ReactContext reactContext) { + super(reactContext); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + float x = (float) relativeOnWidth(mX); + float y = (float) relativeOnHeight(mY); + float w = (float) relativeOnWidth(mW); + float h = (float) relativeOnHeight(mH); + canvas.translate(x, y); + canvas.clipRect(0, 0, w, h); + super.draw(canvas, paint, opacity); + } + + @Override + public void onDescendantInvalidated(@NonNull View child, @NonNull View target) { + super.onDescendantInvalidated(child, target); + invalidate(); + } + + public void setX(Dynamic x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(String x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(Double x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setY(Dynamic y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(String y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(Double y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setWidth(Dynamic width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(String width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(Double width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setHeight(Dynamic height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(String height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(Double height) { + mH = SVGLength.from(height); + invalidate(); + } + + void drawGroup(final Canvas canvas, final Paint paint, final float opacity) { + pushGlyphContext(); + final SvgView svg = getSvgView(); + final GroupView self = this; + final RectF groupRect = new RectF(); + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof MaskView) { + continue; + } + if (child instanceof VirtualView) { + VirtualView node = ((VirtualView) child); + if ("none".equals(node.mDisplay)) { + continue; + } + if (node instanceof RenderableView) { + ((RenderableView) node).mergeProperties(self); + } + + int count = node.saveAndSetupCanvas(canvas, mCTM); + node.render(canvas, paint, opacity * mOpacity); + RectF r = node.getClientRect(); + if (r != null) { + groupRect.union(r); + } + + node.restoreCanvas(canvas, count); + + if (node instanceof RenderableView) { + ((RenderableView) node).resetProperties(); + } + + if (node.isResponsible()) { + svg.enableTouchEvents(); + } + } else if (child instanceof SvgView) { + SvgView svgView = (SvgView) child; + svgView.drawChildren(canvas); + if (svgView.isResponsible()) { + svg.enableTouchEvents(); + } + } else { + // Enable rendering other native ancestor views in e.g. masks + child.draw(canvas); + } + } + this.setClientRect(groupRect); + popGlyphContext(); + } + + // Enable rendering other native ancestor views in e.g. masks, but don't render them another time + Bitmap fakeBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + Canvas fake = new Canvas(fakeBitmap); + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(fake); + } + + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + return super.drawChild(fake, child, drawingTime); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GlyphContext.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GlyphContext.java new file mode 100644 index 00000000000000..35f9f3f32792f7 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GlyphContext.java @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import java.util.ArrayList; +import javax.annotation.Nullable; + +// https://www.w3.org/TR/SVG/text.html#TSpanElement +class GlyphContext { + + // Current stack (one per node push/pop) + final ArrayList mFontContext = new ArrayList<>(); + + // Unique input attribute lists (only added if node sets a value) + private final ArrayList mXsContext = new ArrayList<>(); + private final ArrayList mYsContext = new ArrayList<>(); + private final ArrayList mDXsContext = new ArrayList<>(); + private final ArrayList mDYsContext = new ArrayList<>(); + private final ArrayList mRsContext = new ArrayList<>(); + + // Unique index into attribute list (one per unique list) + private final ArrayList mXIndices = new ArrayList<>(); + private final ArrayList mYIndices = new ArrayList<>(); + private final ArrayList mDXIndices = new ArrayList<>(); + private final ArrayList mDYIndices = new ArrayList<>(); + private final ArrayList mRIndices = new ArrayList<>(); + + // Index of unique context used (one per node push/pop) + private final ArrayList mXsIndices = new ArrayList<>(); + private final ArrayList mYsIndices = new ArrayList<>(); + private final ArrayList mDXsIndices = new ArrayList<>(); + private final ArrayList mDYsIndices = new ArrayList<>(); + private final ArrayList mRsIndices = new ArrayList<>(); + + // Calculated on push context, percentage and em length depends on parent font size + private double mFontSize = FontData.DEFAULT_FONT_SIZE; + private FontData topFont = FontData.Defaults; + + // Current accumulated values + // https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate + // syntax is the same as that for + private double mX; + private double mY; + + // https://www.w3.org/TR/SVG/types.html#Length + private double mDX; + private double mDY; + + // Current SVGLengthList + // https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList + // https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates + + // https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute + private SVGLength[] mXs = new SVGLength[] {}; + + // https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute + private SVGLength[] mYs = new SVGLength[] {}; + + // Current SVGLengthList + // https://www.w3.org/TR/SVG/types.html#DataTypeLengths + + // https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute + private SVGLength[] mDXs = new SVGLength[] {}; + + // https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute + private SVGLength[] mDYs = new SVGLength[] {}; + + // Current SVGLengthList + // https://www.w3.org/TR/SVG/types.html#DataTypeNumbers + + // https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute + private double[] mRs = new double[] {0}; + + // Current attribute list index + private int mXsIndex; + private int mYsIndex; + private int mDXsIndex; + private int mDYsIndex; + private int mRsIndex; + + // Current value index in current attribute list + private int mXIndex = -1; + private int mYIndex = -1; + private int mDXIndex = -1; + private int mDYIndex = -1; + private int mRIndex = -1; + + // Top index of stack + private int mTop; + + // Constructor parameters + private final float mScale; + private final float mWidth; + private final float mHeight; + + private void pushIndices() { + mXsIndices.add(mXsIndex); + mYsIndices.add(mYsIndex); + mDXsIndices.add(mDXsIndex); + mDYsIndices.add(mDYsIndex); + mRsIndices.add(mRsIndex); + } + + GlyphContext(float scale, float width, float height) { + mScale = scale; + mWidth = width; + mHeight = height; + + mXsContext.add(mXs); + mYsContext.add(mYs); + mDXsContext.add(mDXs); + mDYsContext.add(mDYs); + mRsContext.add(mRs); + + mXIndices.add(mXIndex); + mYIndices.add(mYIndex); + mDXIndices.add(mDXIndex); + mDYIndices.add(mDYIndex); + mRIndices.add(mRIndex); + + mFontContext.add(topFont); + + pushIndices(); + } + + private void reset() { + mXsIndex = mYsIndex = mDXsIndex = mDYsIndex = mRsIndex = 0; + mXIndex = mYIndex = mDXIndex = mDYIndex = mRIndex = -1; + mX = mY = mDX = mDY = 0; + } + + FontData getFont() { + return topFont; + } + + private FontData getTopOrParentFont(GroupView child) { + if (mTop > 0) { + return topFont; + } else { + GroupView parentRoot = child.getParentTextRoot(); + + while (parentRoot != null) { + FontData map = parentRoot.getGlyphContext().getFont(); + if (map != FontData.Defaults) { + return map; + } + parentRoot = parentRoot.getParentTextRoot(); + } + + return FontData.Defaults; + } + } + + private void pushNodeAndFont(GroupView node, @Nullable ReadableMap font) { + FontData parent = getTopOrParentFont(node); + mTop++; + + if (font == null) { + mFontContext.add(parent); + return; + } + + FontData data = new FontData(font, parent, mScale); + mFontSize = data.fontSize; + mFontContext.add(data); + topFont = data; + } + + void pushContext(GroupView node, @Nullable ReadableMap font) { + pushNodeAndFont(node, font); + pushIndices(); + } + + private SVGLength[] getStringArrayFromReadableArray(ArrayList readableArray) { + int size = readableArray.size(); + SVGLength[] strings = new SVGLength[size]; + for (int i = 0; i < size; i++) { + strings[i] = readableArray.get(i); + } + return strings; + } + + private double[] getDoubleArrayFromReadableArray(ArrayList readableArray) { + int size = readableArray.size(); + double[] doubles = new double[size]; + for (int i = 0; i < size; i++) { + SVGLength length = readableArray.get(i); + doubles[i] = length.value; + } + return doubles; + } + + void pushContext( + boolean reset, + TextView node, + @Nullable ReadableMap font, + @Nullable ArrayList x, + @Nullable ArrayList y, + @Nullable ArrayList deltaX, + @Nullable ArrayList deltaY, + @Nullable ArrayList rotate) { + if (reset) { + this.reset(); + } + + pushNodeAndFont(node, font); + + if (x != null && x.size() != 0) { + mXsIndex++; + mXIndex = -1; + mXIndices.add(mXIndex); + mXs = getStringArrayFromReadableArray(x); + mXsContext.add(mXs); + } + + if (y != null && y.size() != 0) { + mYsIndex++; + mYIndex = -1; + mYIndices.add(mYIndex); + mYs = getStringArrayFromReadableArray(y); + mYsContext.add(mYs); + } + + if (deltaX != null && deltaX.size() != 0) { + mDXsIndex++; + mDXIndex = -1; + mDXIndices.add(mDXIndex); + mDXs = getStringArrayFromReadableArray(deltaX); + mDXsContext.add(mDXs); + } + + if (deltaY != null && deltaY.size() != 0) { + mDYsIndex++; + mDYIndex = -1; + mDYIndices.add(mDYIndex); + mDYs = getStringArrayFromReadableArray(deltaY); + mDYsContext.add(mDYs); + } + + if (rotate != null && rotate.size() != 0) { + mRsIndex++; + mRIndex = -1; + mRIndices.add(mRIndex); + mRs = getDoubleArrayFromReadableArray(rotate); + mRsContext.add(mRs); + } + + pushIndices(); + } + + void popContext() { + mFontContext.remove(mTop); + mXsIndices.remove(mTop); + mYsIndices.remove(mTop); + mDXsIndices.remove(mTop); + mDYsIndices.remove(mTop); + mRsIndices.remove(mTop); + + mTop--; + + int x = mXsIndex; + int y = mYsIndex; + int dx = mDXsIndex; + int dy = mDYsIndex; + int r = mRsIndex; + + topFont = mFontContext.get(mTop); + mXsIndex = mXsIndices.get(mTop); + mYsIndex = mYsIndices.get(mTop); + mDXsIndex = mDXsIndices.get(mTop); + mDYsIndex = mDYsIndices.get(mTop); + mRsIndex = mRsIndices.get(mTop); + + if (x != mXsIndex) { + mXsContext.remove(x); + mXs = mXsContext.get(mXsIndex); + mXIndex = mXIndices.get(mXsIndex); + } + if (y != mYsIndex) { + mYsContext.remove(y); + mYs = mYsContext.get(mYsIndex); + mYIndex = mYIndices.get(mYsIndex); + } + if (dx != mDXsIndex) { + mDXsContext.remove(dx); + mDXs = mDXsContext.get(mDXsIndex); + mDXIndex = mDXIndices.get(mDXsIndex); + } + if (dy != mDYsIndex) { + mDYsContext.remove(dy); + mDYs = mDYsContext.get(mDYsIndex); + mDYIndex = mDYIndices.get(mDYsIndex); + } + if (r != mRsIndex) { + mRsContext.remove(r); + mRs = mRsContext.get(mRsIndex); + mRIndex = mRIndices.get(mRsIndex); + } + } + + private static void incrementIndices(ArrayList indices, int topIndex) { + for (int index = topIndex; index >= 0; index--) { + int xIndex = indices.get(index); + indices.set(index, xIndex + 1); + } + } + + // https://www.w3.org/TR/SVG11/text.html#FontSizeProperty + + /** + * Get font size from context. + * + *

‘font-size’ Value: < absolute-size > | < relative-size > | < length > | < percentage > | + * inherit Initial: medium Applies to: text content elements Inherited: yes, the computed value is + * inherited Percentages: refer to parent element's font size Media: visual Animatable: yes + * + *

This property refers to the size of the font from baseline to baseline when multiple lines + * of text are set solid in a multiline layout environment. + * + *

For SVG, if a < length > is provided without a unit identifier (e.g., an unqualified number + * such as 128), the SVG user agent processes the < length > as a height value in the current user + * coordinate system. + * + *

If a < length > is provided with one of the unit identifiers (e.g., 12pt or 10%), then the + * SVG user agent converts the < length > into a corresponding value in the current user + * coordinate system by applying the rules described in Units. + * + *

Except for any additional information provided in this specification, the normative + * definition of the property is in CSS2 ([CSS2], section 15.2.4). + */ + double getFontSize() { + return mFontSize; + } + + double nextX(double advance) { + incrementIndices(mXIndices, mXsIndex); + + int nextIndex = mXIndex + 1; + if (nextIndex < mXs.length) { + mDX = 0; + mXIndex = nextIndex; + SVGLength string = mXs[nextIndex]; + mX = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize); + } + + mX += advance; + + return mX; + } + + double nextY() { + incrementIndices(mYIndices, mYsIndex); + + int nextIndex = mYIndex + 1; + if (nextIndex < mYs.length) { + mDY = 0; + mYIndex = nextIndex; + SVGLength string = mYs[nextIndex]; + mY = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize); + } + + return mY; + } + + double nextDeltaX() { + incrementIndices(mDXIndices, mDXsIndex); + + int nextIndex = mDXIndex + 1; + if (nextIndex < mDXs.length) { + mDXIndex = nextIndex; + SVGLength string = mDXs[nextIndex]; + double val = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize); + mDX += val; + } + + return mDX; + } + + double nextDeltaY() { + incrementIndices(mDYIndices, mDYsIndex); + + int nextIndex = mDYIndex + 1; + if (nextIndex < mDYs.length) { + mDYIndex = nextIndex; + SVGLength string = mDYs[nextIndex]; + double val = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize); + mDY += val; + } + + return mDY; + } + + double nextRotation() { + incrementIndices(mRIndices, mRsIndex); + + mRIndex = Math.min(mRIndex + 1, mRs.length - 1); + + return mRs[mRIndex]; + } + + float getWidth() { + return mWidth; + } + + float getHeight() { + return mHeight; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GlyphPathBag.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GlyphPathBag.java new file mode 100644 index 00000000000000..94aaeb195f3d03 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GlyphPathBag.java @@ -0,0 +1,47 @@ +package abi49_0_0.com.horcrux.svg; + +import android.graphics.Paint; +import android.graphics.Path; +import java.util.ArrayList; + +class GlyphPathBag { + private final ArrayList paths = new ArrayList<>(); + private final int[][] data = new int[256][]; + private final Paint paint; + + GlyphPathBag(Paint paint) { + this.paint = paint; + // Make indexed-by-one, to allow zero to represent non-cached + paths.add(new Path()); + } + + Path getOrCreateAndCache(char ch, String current) { + int index = getIndex(ch); + Path cached; + + if (index != 0) { + cached = paths.get(index); + } else { + cached = new Path(); + paint.getTextPath(current, 0, 1, 0, 0, cached); + + int[] bin = data[ch >> 8]; + if (bin == null) { + bin = data[ch >> 8] = new int[256]; + } + bin[ch & 0xFF] = paths.size(); + + paths.add(cached); + } + + Path glyph = new Path(); + glyph.addPath(cached); + return glyph; + } + + private int getIndex(char ch) { + int[] bin = data[ch >> 8]; + if (bin == null) return 0; + return bin[ch & 0xFF]; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GroupView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GroupView.java new file mode 100644 index 00000000000000..92b02710ac68cf --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/GroupView.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.os.Build; +import android.view.View; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import java.util.ArrayList; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class GroupView extends RenderableView { + @Nullable ReadableMap mFont; + private GlyphContext mGlyphContext; + + public GroupView(ReactContext reactContext) { + super(reactContext); + } + + public void setFont(@Nullable ReadableMap font) { + mFont = font; + invalidate(); + } + + void setupGlyphContext(Canvas canvas) { + RectF clipBounds = new RectF(canvas.getClipBounds()); + if (mMatrix != null) { + mMatrix.mapRect(clipBounds); + } + if (mTransform != null) { + mTransform.mapRect(clipBounds); + } + mGlyphContext = new GlyphContext(mScale, clipBounds.width(), clipBounds.height()); + } + + GlyphContext getGlyphContext() { + return mGlyphContext; + } + + private static T requireNonNull(T obj) { + if (obj == null) throw new NullPointerException(); + return obj; + } + + GlyphContext getTextRootGlyphContext() { + return requireNonNull(getTextRoot()).getGlyphContext(); + } + + void pushGlyphContext() { + getTextRootGlyphContext().pushContext(this, mFont); + } + + void popGlyphContext() { + getTextRootGlyphContext().popContext(); + } + + void draw(final Canvas canvas, final Paint paint, final float opacity) { + setupGlyphContext(canvas); + clip(canvas, paint); + drawGroup(canvas, paint, opacity); + renderMarkers(canvas, paint, opacity); + } + + void drawGroup(final Canvas canvas, final Paint paint, final float opacity) { + pushGlyphContext(); + final SvgView svg = getSvgView(); + final GroupView self = this; + final RectF groupRect = new RectF(); + elements = new ArrayList<>(); + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof MaskView) { + continue; + } + if (child instanceof VirtualView) { + VirtualView node = ((VirtualView) child); + if ("none".equals(node.mDisplay)) { + continue; + } + if (node instanceof RenderableView) { + ((RenderableView) node).mergeProperties(self); + } + + int count = node.saveAndSetupCanvas(canvas, mCTM); + node.render(canvas, paint, opacity * mOpacity); + RectF r = node.getClientRect(); + + if (r != null) { + groupRect.union(r); + } + + node.restoreCanvas(canvas, count); + + if (node instanceof RenderableView) { + ((RenderableView) node).resetProperties(); + } + + if (node.isResponsible()) { + svg.enableTouchEvents(); + } + + if (node.elements != null) { + elements.addAll(node.elements); + } + + } else if (child instanceof SvgView) { + SvgView svgView = (SvgView) child; + svgView.drawChildren(canvas); + if (svgView.isResponsible()) { + svg.enableTouchEvents(); + } + } + } + this.setClientRect(groupRect); + popGlyphContext(); + } + + void drawPath(Canvas canvas, Paint paint, float opacity) { + super.draw(canvas, paint, opacity); + } + + @Override + Path getPath(final Canvas canvas, final Paint paint) { + if (mPath != null) { + return mPath; + } + mPath = new Path(); + + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof MaskView) { + continue; + } + if (node instanceof VirtualView) { + VirtualView n = (VirtualView) node; + Matrix transform = n.mMatrix; + mPath.addPath(n.getPath(canvas, paint), transform); + } + } + + return mPath; + } + + Path getPath(final Canvas canvas, final Paint paint, final Region.Op op) { + final Path path = new Path(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + final Path.Op pop = Path.Op.valueOf(op.name()); + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof MaskView) { + continue; + } + if (node instanceof VirtualView) { + VirtualView n = (VirtualView) node; + Matrix transform = n.mMatrix; + Path p2; + if (n instanceof GroupView) { + p2 = ((GroupView) n).getPath(canvas, paint, op); + } else { + p2 = n.getPath(canvas, paint); + } + p2.transform(transform); + path.op(p2, pop); + } + } + } else { + Rect clipBounds = canvas.getClipBounds(); + final Region bounds = new Region(clipBounds); + final Region r = new Region(); + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof MaskView) { + continue; + } + if (node instanceof VirtualView) { + VirtualView n = (VirtualView) node; + Matrix transform = n.mMatrix; + Path p2; + if (n instanceof GroupView) { + p2 = ((GroupView) n).getPath(canvas, paint, op); + } else { + p2 = n.getPath(canvas, paint); + } + if (transform != null) { + p2.transform(transform); + } + Region r2 = new Region(); + r2.setPath(p2, bounds); + r.op(r2, op); + } + } + path.addPath(r.getBoundaryPath()); + } + + return path; + } + + @Override + int hitTest(final float[] src) { + if (!mInvertible || !mTransformInvertible) { + return -1; + } + + float[] dst = new float[2]; + mInvMatrix.mapPoints(dst, src); + mInvTransform.mapPoints(dst); + + int x = Math.round(dst[0]); + int y = Math.round(dst[1]); + + Path clipPath = getClipPath(); + if (clipPath != null) { + if (mClipRegionPath != clipPath) { + mClipRegionPath = clipPath; + mClipBounds = new RectF(); + clipPath.computeBounds(mClipBounds, true); + mClipRegion = getRegion(clipPath, mClipBounds); + } + if (!mClipRegion.contains(x, y)) { + return -1; + } + } + + for (int i = getChildCount() - 1; i >= 0; i--) { + View child = getChildAt(i); + if (child instanceof VirtualView) { + if (child instanceof MaskView) { + continue; + } + + VirtualView node = (VirtualView) child; + + int hitChild = node.hitTest(dst); + if (hitChild != -1) { + return (node.isResponsible() || hitChild != child.getId()) ? hitChild : getId(); + } + } else if (child instanceof SvgView) { + SvgView node = (SvgView) child; + + int hitChild = node.reactTagForTouch(dst[0], dst[1]); + if (hitChild != child.getId()) { + return hitChild; + } + } + } + + return -1; + } + + void saveDefinition() { + if (mName != null) { + getSvgView().defineTemplate(this, mName); + } + + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof VirtualView) { + ((VirtualView) node).saveDefinition(); + } + } + } + + @Override + void resetProperties() { + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof RenderableView) { + ((RenderableView) node).resetProperties(); + } + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ImageView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ImageView.java new file mode 100644 index 00000000000000..bbc811c15ff93b --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ImageView.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.net.Uri; +import com.facebook.common.executors.UiThreadImmediateExecutorService; +import com.facebook.common.logging.FLog; +import com.facebook.common.references.CloseableReference; +import com.facebook.datasource.DataSource; +import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.imagepipeline.core.ImagePipeline; +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; +import com.facebook.imagepipeline.image.CloseableBitmap; +import com.facebook.imagepipeline.image.CloseableImage; +import com.facebook.imagepipeline.request.ImageRequest; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import abi49_0_0.com.facebook.react.views.imagehelper.ImageSource; +import abi49_0_0.com.facebook.react.views.imagehelper.ResourceDrawableIdHelper; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class ImageView extends RenderableView { + private SVGLength mX; + private SVGLength mY; + private SVGLength mW; + private SVGLength mH; + private String uriString; + private int mImageWidth; + private int mImageHeight; + private String mAlign; + private int mMeetOrSlice; + private final AtomicBoolean mLoading = new AtomicBoolean(false); + + public ImageView(ReactContext reactContext) { + super(reactContext); + } + + public void setX(Dynamic x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(String x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(Double x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setY(Dynamic y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(String y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(Double y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setWidth(Dynamic width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(String width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(Double width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setHeight(Dynamic height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(String height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(Double height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setSrc(@Nullable ReadableMap src) { + if (src != null) { + uriString = src.getString("uri"); + + if (uriString == null || uriString.isEmpty()) { + // TODO: give warning about this + return; + } + + if (src.hasKey("width") && src.hasKey("height")) { + mImageWidth = src.getInt("width"); + mImageHeight = src.getInt("height"); + } else { + mImageWidth = 0; + mImageHeight = 0; + } + Uri mUri = Uri.parse(uriString); + if (mUri.getScheme() == null) { + ResourceDrawableIdHelper.getInstance().getResourceDrawableUri(mContext, uriString); + } + } + } + + public void setAlign(String align) { + mAlign = align; + invalidate(); + } + + public void setMeetOrSlice(int meetOrSlice) { + mMeetOrSlice = meetOrSlice; + invalidate(); + } + + @Override + void draw(final Canvas canvas, final Paint paint, final float opacity) { + if (!mLoading.get()) { + ImagePipeline imagePipeline = Fresco.getImagePipeline(); + ImageSource imageSource = new ImageSource(mContext, uriString); + ImageRequest request = ImageRequest.fromUri(imageSource.getUri()); + boolean inMemoryCache = imagePipeline.isInBitmapMemoryCache(request); + + if (inMemoryCache) { + tryRenderFromBitmapCache(imagePipeline, request, canvas, paint, opacity * mOpacity); + } else { + loadBitmap(imagePipeline, request); + } + } + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + mPath = new Path(); + mPath.addRect(getRect(), Path.Direction.CW); + return mPath; + } + + private void loadBitmap(final ImagePipeline imagePipeline, final ImageRequest request) { + mLoading.set(true); + final DataSource> dataSource = + imagePipeline.fetchDecodedImage(request, mContext); + BaseBitmapDataSubscriber subscriber = + new BaseBitmapDataSubscriber() { + @Override + public void onNewResultImpl(Bitmap bitmap) { + mLoading.set(false); + SvgView view = getSvgView(); + if (view != null) { + view.invalidate(); + } + } + + @Override + public void onFailureImpl(DataSource dataSource) { + // No cleanup required here. + // TODO: more details about this failure + mLoading.set(false); + FLog.w( + ReactConstants.TAG, + dataSource.getFailureCause(), + "RNSVG: fetchDecodedImage failed!"); + } + }; + dataSource.subscribe(subscriber, UiThreadImmediateExecutorService.getInstance()); + } + + @Nonnull + private RectF getRect() { + double x = relativeOnWidth(mX); + double y = relativeOnHeight(mY); + double w = relativeOnWidth(mW); + double h = relativeOnHeight(mH); + if (w == 0) { + w = mImageWidth * mScale; + } + if (h == 0) { + h = mImageHeight * mScale; + } + + return new RectF((float) x, (float) y, (float) (x + w), (float) (y + h)); + } + + private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) { + if (mImageWidth == 0 || mImageHeight == 0) { + mImageWidth = bitmap.getWidth(); + mImageHeight = bitmap.getHeight(); + } + + RectF renderRect = getRect(); + RectF vbRect = new RectF(0, 0, mImageWidth, mImageHeight); + Matrix transform = ViewBox.getTransform(vbRect, renderRect, mAlign, mMeetOrSlice); + transform.mapRect(vbRect); + + canvas.clipPath(getPath(canvas, paint)); + + Path clipPath = getClipPath(canvas, paint); + if (clipPath != null) { + canvas.clipPath(clipPath); + } + + Paint alphaPaint = new Paint(); + alphaPaint.setAlpha((int) (opacity * 255)); + canvas.drawBitmap(bitmap, null, vbRect, alphaPaint); + mCTM.mapRect(vbRect); + this.setClientRect(vbRect); + } + + private void tryRenderFromBitmapCache( + ImagePipeline imagePipeline, + ImageRequest request, + Canvas canvas, + Paint paint, + float opacity) { + final DataSource> dataSource = + imagePipeline.fetchImageFromBitmapCache(request, mContext); + + try { + final CloseableReference imageReference = dataSource.getResult(); + if (imageReference == null) { + return; + } + + try { + CloseableImage closeableImage = imageReference.get(); + if (!(closeableImage instanceof CloseableBitmap)) { + return; + } + + CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage; + final Bitmap bitmap = closeableBitmap.getUnderlyingBitmap(); + + if (bitmap == null) { + return; + } + + doRender(canvas, paint, bitmap, opacity); + + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + CloseableReference.closeSafely(imageReference); + } + + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + dataSource.close(); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/LineView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/LineView.java new file mode 100644 index 00000000000000..1d3c62ef999e79 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/LineView.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import java.util.ArrayList; + +@SuppressLint("ViewConstructor") +class LineView extends RenderableView { + private SVGLength mX1; + private SVGLength mY1; + private SVGLength mX2; + private SVGLength mY2; + + public LineView(ReactContext reactContext) { + super(reactContext); + } + + public void setX1(Dynamic x1) { + mX1 = SVGLength.from(x1); + invalidate(); + } + + public void setX1(String x1) { + mX1 = SVGLength.from(x1); + invalidate(); + } + + public void setX1(Double x1) { + mX1 = SVGLength.from(x1); + invalidate(); + } + + public void setY1(Dynamic y1) { + mY1 = SVGLength.from(y1); + invalidate(); + } + + public void setY1(String y1) { + mY1 = SVGLength.from(y1); + invalidate(); + } + + public void setY1(Double y1) { + mY1 = SVGLength.from(y1); + invalidate(); + } + + public void setX2(Dynamic x2) { + mX2 = SVGLength.from(x2); + invalidate(); + } + + public void setX2(String x2) { + mX2 = SVGLength.from(x2); + invalidate(); + } + + public void setX2(Double x2) { + mX2 = SVGLength.from(x2); + invalidate(); + } + + public void setY2(Dynamic y2) { + mY2 = SVGLength.from(y2); + invalidate(); + } + + public void setY2(String y2) { + mY2 = SVGLength.from(y2); + invalidate(); + } + + public void setY2(Double y2) { + mY2 = SVGLength.from(y2); + invalidate(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + Path path = new Path(); + double x1 = relativeOnWidth(mX1); + double y1 = relativeOnHeight(mY1); + double x2 = relativeOnWidth(mX2); + double y2 = relativeOnHeight(mY2); + + path.moveTo((float) x1, (float) y1); + path.lineTo((float) x2, (float) y2); + + elements = new ArrayList<>(); + elements.add( + new PathElement(ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(x1, y1)})); + elements.add( + new PathElement(ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x2, y2)})); + + return path; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/LinearGradientView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/LinearGradientView.java new file mode 100644 index 00000000000000..ce9dabcc519617 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/LinearGradientView.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Matrix; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class LinearGradientView extends DefinitionView { + + private SVGLength mX1; + private SVGLength mY1; + private SVGLength mX2; + private SVGLength mY2; + private ReadableArray mGradient; + private Brush.BrushUnits mGradientUnits; + + private static final float[] sRawMatrix = + new float[] { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }; + private Matrix mMatrix = null; + + public LinearGradientView(ReactContext reactContext) { + super(reactContext); + } + + public void setX1(Dynamic x1) { + mX1 = SVGLength.from(x1); + invalidate(); + } + + public void setX1(String x1) { + mX1 = SVGLength.from(x1); + invalidate(); + } + + public void setX1(Double x1) { + mX1 = SVGLength.from(x1); + invalidate(); + } + + public void setY1(Dynamic y1) { + mY1 = SVGLength.from(y1); + invalidate(); + } + + public void setY1(String y1) { + mY1 = SVGLength.from(y1); + invalidate(); + } + + public void setY1(Double y1) { + mY1 = SVGLength.from(y1); + invalidate(); + } + + public void setX2(Dynamic x2) { + mX2 = SVGLength.from(x2); + invalidate(); + } + + public void setX2(String x2) { + mX2 = SVGLength.from(x2); + invalidate(); + } + + public void setX2(Double x2) { + mX2 = SVGLength.from(x2); + invalidate(); + } + + public void setY2(Dynamic y2) { + mY2 = SVGLength.from(y2); + invalidate(); + } + + public void setY2(String y2) { + mY2 = SVGLength.from(y2); + invalidate(); + } + + public void setY2(Double y2) { + mY2 = SVGLength.from(y2); + invalidate(); + } + + public void setGradient(ReadableArray gradient) { + mGradient = gradient; + invalidate(); + } + + public void setGradientUnits(int gradientUnits) { + switch (gradientUnits) { + case 0: + mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + invalidate(); + } + + public void setGradientTransform(@Nullable ReadableArray matrixArray) { + if (matrixArray != null) { + int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); + if (matrixSize == 6) { + if (mMatrix == null) { + mMatrix = new Matrix(); + } + mMatrix.setValues(sRawMatrix); + } else if (matrixSize != -1) { + FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); + } + } else { + mMatrix = null; + } + + invalidate(); + } + + @Override + void saveDefinition() { + if (mName != null) { + SVGLength[] points = new SVGLength[] {mX1, mY1, mX2, mY2}; + Brush brush = new Brush(Brush.BrushType.LINEAR_GRADIENT, points, mGradientUnits); + brush.setGradientColors(mGradient); + if (mMatrix != null) { + brush.setGradientTransform(mMatrix); + } + + SvgView svg = getSvgView(); + if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { + brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); + } + + svg.defineBrush(brush, mName); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/MarkerView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/MarkerView.java new file mode 100644 index 00000000000000..c23e2db8a712e4 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/MarkerView.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.view.View; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class MarkerView extends GroupView { + + private SVGLength mRefX; + private SVGLength mRefY; + private SVGLength mMarkerWidth; + private SVGLength mMarkerHeight; + private String mMarkerUnits; + private String mOrient; + + private float mMinX; + private float mMinY; + private float mVbWidth; + private float mVbHeight; + String mAlign; + int mMeetOrSlice; + + Matrix markerTransform = new Matrix(); + + public MarkerView(ReactContext reactContext) { + super(reactContext); + } + + public void setRefX(Dynamic refX) { + mRefX = SVGLength.from(refX); + invalidate(); + } + + public void setRefX(String refX) { + mRefX = SVGLength.from(refX); + invalidate(); + } + + public void setRefX(Double refX) { + mRefX = SVGLength.from(refX); + invalidate(); + } + + public void setRefY(Dynamic refY) { + mRefY = SVGLength.from(refY); + invalidate(); + } + + public void setRefY(String refY) { + mRefY = SVGLength.from(refY); + invalidate(); + } + + public void setRefY(Double refY) { + mRefY = SVGLength.from(refY); + invalidate(); + } + + public void setMarkerWidth(Dynamic markerWidth) { + mMarkerWidth = SVGLength.from(markerWidth); + invalidate(); + } + + public void setMarkerWidth(String markerWidth) { + mMarkerWidth = SVGLength.from(markerWidth); + invalidate(); + } + + public void setMarkerWidth(Double markerWidth) { + mMarkerWidth = SVGLength.from(markerWidth); + invalidate(); + } + + public void setMarkerHeight(Dynamic markerHeight) { + mMarkerHeight = SVGLength.from(markerHeight); + invalidate(); + } + + public void setMarkerHeight(String markerHeight) { + mMarkerHeight = SVGLength.from(markerHeight); + invalidate(); + } + + public void setMarkerHeight(Double markerHeight) { + mMarkerHeight = SVGLength.from(markerHeight); + invalidate(); + } + + public void setMarkerUnits(String markerUnits) { + mMarkerUnits = markerUnits; + invalidate(); + } + + public void setOrient(String orient) { + mOrient = orient; + invalidate(); + } + + public void setMinX(float minX) { + mMinX = minX; + invalidate(); + } + + public void setMinY(float minY) { + mMinY = minY; + invalidate(); + } + + public void setVbWidth(float vbWidth) { + mVbWidth = vbWidth; + invalidate(); + } + + public void setVbHeight(float vbHeight) { + mVbHeight = vbHeight; + invalidate(); + } + + public void setAlign(String align) { + mAlign = align; + invalidate(); + } + + public void setMeetOrSlice(int meetOrSlice) { + mMeetOrSlice = meetOrSlice; + invalidate(); + } + + @Override + void saveDefinition() { + if (mName != null) { + SvgView svg = getSvgView(); + svg.defineMarker(this, mName); + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof VirtualView) { + ((VirtualView) node).saveDefinition(); + } + } + } + } + + void renderMarker( + Canvas canvas, Paint paint, float opacity, RNSVGMarkerPosition position, float strokeWidth) { + int count = saveAndSetupCanvas(canvas, mCTM); + + markerTransform.reset(); + Point origin = position.origin; + markerTransform.setTranslate((float) origin.x, (float) origin.y); + + double markerAngle = "auto".equals(mOrient) ? -1 : Double.parseDouble(mOrient); + float degrees = 180 + (float) (markerAngle == -1 ? position.angle : markerAngle); + markerTransform.preRotate(degrees); + + boolean useStrokeWidth = "strokeWidth".equals(mMarkerUnits); + if (useStrokeWidth) { + markerTransform.preScale(strokeWidth / mScale, strokeWidth / mScale); + } + + double width = relativeOnWidth(mMarkerWidth) / mScale; + double height = relativeOnHeight(mMarkerHeight) / mScale; + RectF eRect = new RectF(0, 0, (float) width, (float) height); + if (mAlign != null) { + RectF vbRect = + new RectF( + mMinX * mScale, + mMinY * mScale, + (mMinX + mVbWidth) * mScale, + (mMinY + mVbHeight) * mScale); + Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice); + float[] values = new float[9]; + viewBoxMatrix.getValues(values); + markerTransform.preScale(values[Matrix.MSCALE_X], values[Matrix.MSCALE_Y]); + } + + double x = relativeOnWidth(mRefX); + double y = relativeOnHeight(mRefY); + markerTransform.preTranslate((float) -x, (float) -y); + + canvas.concat(markerTransform); + + drawGroup(canvas, paint, opacity); + + restoreCanvas(canvas, count); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/MaskView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/MaskView.java new file mode 100644 index 00000000000000..125dd0a67656b0 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/MaskView.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class MaskView extends GroupView { + + SVGLength mX; + SVGLength mY; + SVGLength mW; + SVGLength mH; + + // TODO implement proper support for units + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + private Brush.BrushUnits mMaskUnits; + + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + private Brush.BrushUnits mMaskContentUnits; + + public MaskView(ReactContext reactContext) { + super(reactContext); + } + + public void setX(Dynamic x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(String x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(Double x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setY(Dynamic y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(String y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(Double y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setWidth(Dynamic width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(String width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(Double width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setHeight(Dynamic height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(String height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(Double height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setMaskUnits(int maskUnits) { + switch (maskUnits) { + case 0: + mMaskUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mMaskUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + invalidate(); + } + + public void setMaskContentUnits(int maskContentUnits) { + switch (maskContentUnits) { + case 0: + mMaskContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mMaskContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + invalidate(); + } + + @Override + void saveDefinition() { + if (mName != null) { + SvgView svg = getSvgView(); + svg.defineMask(this, mName); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PathParser.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PathParser.java new file mode 100644 index 00000000000000..7429d6c94e5996 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PathParser.java @@ -0,0 +1,679 @@ +package abi49_0_0.com.horcrux.svg; + +import android.graphics.Path; +import android.graphics.RectF; +import java.util.ArrayList; + +class PathElement { + ElementType type; + Point[] points; + + PathElement(ElementType type, Point[] points) { + this.type = type; + this.points = points; + } +} + +class PathParser { + static float mScale; + + private static int i; + private static int l; + private static String s; + private static Path mPath; + static ArrayList elements; + + private static float mPenX; + private static float mPenY; + private static float mPivotX; + private static float mPivotY; + private static float mPenDownX; + private static float mPenDownY; + private static boolean mPenDown; + + static Path parse(String d) { + elements = new ArrayList<>(); + mPath = new Path(); + if (d == null) { + return mPath; + } + char prev_cmd = ' '; + l = d.length(); + s = d; + i = 0; + + mPenX = 0f; + mPenY = 0f; + mPivotX = 0f; + mPivotY = 0f; + mPenDownX = 0f; + mPenDownY = 0f; + mPenDown = false; + + while (i < l) { + skip_spaces(); + + if (i >= l) { + break; + } + + boolean has_prev_cmd = prev_cmd != ' '; + char first_char = s.charAt(i); + + if (!has_prev_cmd && first_char != 'M' && first_char != 'm') { + // The first segment must be a MoveTo. + throw new Error(String.format("Unexpected character '%c' (i=%d, s=%s)", first_char, i, s)); + } + + // TODO: simplify + boolean is_implicit_move_to; + char cmd; + if (is_cmd(first_char)) { + is_implicit_move_to = false; + cmd = first_char; + i += 1; + } else if (is_number_start(first_char) && has_prev_cmd) { + if (prev_cmd == 'Z' || prev_cmd == 'z') { + // ClosePath cannot be followed by a number. + throw new Error(String.format("Unexpected number after 'z' (s=%s)", s)); + } + + if (prev_cmd == 'M' || prev_cmd == 'm') { + // 'If a moveto is followed by multiple pairs of coordinates, + // the subsequent pairs are treated as implicit lineto commands.' + // So we parse them as LineTo. + is_implicit_move_to = true; + if (is_absolute(prev_cmd)) { + cmd = 'L'; + } else { + cmd = 'l'; + } + } else { + is_implicit_move_to = false; + cmd = prev_cmd; + } + } else { + throw new Error(String.format("Unexpected character '%c' (i=%d, s=%s)", first_char, i, s)); + } + + boolean absolute = is_absolute(cmd); + switch (cmd) { + case 'm': + { + move(parse_list_number(), parse_list_number()); + break; + } + case 'M': + { + moveTo(parse_list_number(), parse_list_number()); + break; + } + case 'l': + { + line(parse_list_number(), parse_list_number()); + break; + } + case 'L': + { + lineTo(parse_list_number(), parse_list_number()); + break; + } + case 'h': + { + line(parse_list_number(), 0); + break; + } + case 'H': + { + lineTo(parse_list_number(), mPenY); + break; + } + case 'v': + { + line(0, parse_list_number()); + break; + } + case 'V': + { + lineTo(mPenX, parse_list_number()); + break; + } + case 'c': + { + curve( + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_list_number()); + break; + } + case 'C': + { + curveTo( + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_list_number()); + break; + } + case 's': + { + smoothCurve( + parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); + break; + } + case 'S': + { + smoothCurveTo( + parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); + break; + } + case 'q': + { + quadraticBezierCurve( + parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); + break; + } + case 'Q': + { + quadraticBezierCurveTo( + parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); + break; + } + case 't': + { + smoothQuadraticBezierCurve(parse_list_number(), parse_list_number()); + break; + } + case 'T': + { + smoothQuadraticBezierCurveTo(parse_list_number(), parse_list_number()); + break; + } + case 'a': + { + arc( + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_flag(), + parse_flag(), + parse_list_number(), + parse_list_number()); + break; + } + case 'A': + { + arcTo( + parse_list_number(), + parse_list_number(), + parse_list_number(), + parse_flag(), + parse_flag(), + parse_list_number(), + parse_list_number()); + break; + } + case 'z': + case 'Z': + { + close(); + break; + } + default: + { + throw new Error(String.format("Unexpected comand '%c' (s=%s)", cmd, s)); + } + } + + if (is_implicit_move_to) { + if (absolute) { + prev_cmd = 'M'; + } else { + prev_cmd = 'm'; + } + } else { + prev_cmd = cmd; + } + } + + return mPath; + } + + private static void move(float x, float y) { + moveTo(x + mPenX, y + mPenY); + } + + private static void moveTo(float x, float y) { + // FLog.w(ReactConstants.TAG, "move x: " + x + " y: " + y); + mPenDownX = mPivotX = mPenX = x; + mPenDownY = mPivotY = mPenY = y; + mPath.moveTo(x * mScale, y * mScale); + elements.add( + new PathElement(ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(x, y)})); + } + + private static void line(float x, float y) { + lineTo(x + mPenX, y + mPenY); + } + + private static void lineTo(float x, float y) { + // FLog.w(ReactConstants.TAG, "line x: " + x + " y: " + y); + setPenDown(); + mPivotX = mPenX = x; + mPivotY = mPenY = y; + mPath.lineTo(x * mScale, y * mScale); + elements.add( + new PathElement(ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x, y)})); + } + + private static void curve(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { + curveTo(c1x + mPenX, c1y + mPenY, c2x + mPenX, c2y + mPenY, ex + mPenX, ey + mPenY); + } + + private static void curveTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { + // FLog.w(ReactConstants.TAG, "curve c1x: " + c1x + " c1y: " + c1y + "ex: " + ex + " ey: " + + // ey); + mPivotX = c2x; + mPivotY = c2y; + cubicTo(c1x, c1y, c2x, c2y, ex, ey); + } + + private static void cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { + setPenDown(); + mPenX = ex; + mPenY = ey; + mPath.cubicTo(c1x * mScale, c1y * mScale, c2x * mScale, c2y * mScale, ex * mScale, ey * mScale); + elements.add( + new PathElement( + ElementType.kCGPathElementAddCurveToPoint, + new Point[] {new Point(c1x, c1y), new Point(c2x, c2y), new Point(ex, ey)})); + } + + private static void smoothCurve(float c1x, float c1y, float ex, float ey) { + smoothCurveTo(c1x + mPenX, c1y + mPenY, ex + mPenX, ey + mPenY); + } + + private static void smoothCurveTo(float c1x, float c1y, float ex, float ey) { + // FLog.w(ReactConstants.TAG, "smoothcurve c1x: " + c1x + " c1y: " + c1y + "ex: " + ex + " ey: " + // + ey); + float c2x = c1x; + float c2y = c1y; + c1x = (mPenX * 2) - mPivotX; + c1y = (mPenY * 2) - mPivotY; + mPivotX = c2x; + mPivotY = c2y; + cubicTo(c1x, c1y, c2x, c2y, ex, ey); + } + + private static void quadraticBezierCurve(float c1x, float c1y, float c2x, float c2y) { + quadraticBezierCurveTo(c1x + mPenX, c1y + mPenY, c2x + mPenX, c2y + mPenY); + } + + private static void quadraticBezierCurveTo(float c1x, float c1y, float c2x, float c2y) { + // FLog.w(ReactConstants.TAG, "quad c1x: " + c1x + " c1y: " + c1y + "c2x: " + c2x + " c2y: " + + // c2y); + mPivotX = c1x; + mPivotY = c1y; + float ex = c2x; + float ey = c2y; + c2x = (ex + c1x * 2) / 3; + c2y = (ey + c1y * 2) / 3; + c1x = (mPenX + c1x * 2) / 3; + c1y = (mPenY + c1y * 2) / 3; + cubicTo(c1x, c1y, c2x, c2y, ex, ey); + } + + private static void smoothQuadraticBezierCurve(float c1x, float c1y) { + smoothQuadraticBezierCurveTo(c1x + mPenX, c1y + mPenY); + } + + private static void smoothQuadraticBezierCurveTo(float c1x, float c1y) { + // FLog.w(ReactConstants.TAG, "smoothquad c1x: " + c1x + " c1y: " + c1y); + float c2x = c1x; + float c2y = c1y; + c1x = (mPenX * 2) - mPivotX; + c1y = (mPenY * 2) - mPivotY; + quadraticBezierCurveTo(c1x, c1y, c2x, c2y); + } + + private static void arc( + float rx, float ry, float rotation, boolean outer, boolean clockwise, float x, float y) { + arcTo(rx, ry, rotation, outer, clockwise, x + mPenX, y + mPenY); + } + + private static void arcTo( + float rx, float ry, float rotation, boolean outer, boolean clockwise, float x, float y) { + // FLog.w(ReactConstants.TAG, "arc rx: " + rx + " ry: " + ry + " rotation: " + rotation + " + // outer: " + outer + " clockwise: " + clockwise + " x: " + x + " y: " + y); + float tX = mPenX; + float tY = mPenY; + + ry = Math.abs(ry == 0 ? (rx == 0 ? (y - tY) : rx) : ry); + rx = Math.abs(rx == 0 ? (x - tX) : rx); + + if (rx == 0 || ry == 0 || (x == tX && y == tY)) { + lineTo(x, y); + return; + } + + float rad = (float) Math.toRadians(rotation); + float cos = (float) Math.cos(rad); + float sin = (float) Math.sin(rad); + x -= tX; + y -= tY; + + // Ellipse Center + float cx = cos * x / 2 + sin * y / 2; + float cy = -sin * x / 2 + cos * y / 2; + float rxry = rx * rx * ry * ry; + float rycx = ry * ry * cx * cx; + float rxcy = rx * rx * cy * cy; + float a = rxry - rxcy - rycx; + + if (a < 0) { + a = (float) Math.sqrt(1 - a / rxry); + rx *= a; + ry *= a; + cx = x / 2; + cy = y / 2; + } else { + a = (float) Math.sqrt(a / (rxcy + rycx)); + + if (outer == clockwise) { + a = -a; + } + float cxd = -a * cy * rx / ry; + float cyd = a * cx * ry / rx; + cx = cos * cxd - sin * cyd + x / 2; + cy = sin * cxd + cos * cyd + y / 2; + } + + // Rotation + Scale Transform + float xx = cos / rx; + float yx = sin / rx; + float xy = -sin / ry; + float yy = cos / ry; + + // Start and End Angle + float sa = (float) Math.atan2(xy * -cx + yy * -cy, xx * -cx + yx * -cy); + float ea = (float) Math.atan2(xy * (x - cx) + yy * (y - cy), xx * (x - cx) + yx * (y - cy)); + + cx += tX; + cy += tY; + x += tX; + y += tY; + + setPenDown(); + + mPenX = mPivotX = x; + mPenY = mPivotY = y; + + if (rx != ry || rad != 0f) { + arcToBezier(cx, cy, rx, ry, sa, ea, clockwise, rad); + } else { + + float start = (float) Math.toDegrees(sa); + float end = (float) Math.toDegrees(ea); + float sweep = Math.abs((start - end) % 360); + + if (outer) { + if (sweep < 180) { + sweep = 360 - sweep; + } + } else { + if (sweep > 180) { + sweep = 360 - sweep; + } + } + + if (!clockwise) { + sweep = -sweep; + } + + RectF oval = + new RectF((cx - rx) * mScale, (cy - rx) * mScale, (cx + rx) * mScale, (cy + rx) * mScale); + + mPath.arcTo(oval, start, sweep); + elements.add( + new PathElement( + ElementType.kCGPathElementAddCurveToPoint, new Point[] {new Point(x, y)})); + } + } + + private static void close() { + if (mPenDown) { + mPenX = mPenDownX; + mPenY = mPenDownY; + mPenDown = false; + mPath.close(); + elements.add( + new PathElement( + ElementType.kCGPathElementCloseSubpath, new Point[] {new Point(mPenX, mPenY)})); + } + } + + private static void arcToBezier( + float cx, float cy, float rx, float ry, float sa, float ea, boolean clockwise, float rad) { + // Inverse Rotation + Scale Transform + float cos = (float) Math.cos(rad); + float sin = (float) Math.sin(rad); + float xx = cos * rx; + float yx = -sin * ry; + float xy = sin * rx; + float yy = cos * ry; + + // Bezier Curve Approximation + float arc = ea - sa; + if (arc < 0 && clockwise) { + arc += Math.PI * 2; + } else if (arc > 0 && !clockwise) { + arc -= Math.PI * 2; + } + + int n = (int) Math.ceil(Math.abs(round(arc / (Math.PI / 2)))); + + float step = arc / n; + float k = (float) ((4 / 3.0) * Math.tan(step / 4)); + + float x = (float) Math.cos(sa); + float y = (float) Math.sin(sa); + + for (int i = 0; i < n; i++) { + float cp1x = x - k * y; + float cp1y = y + k * x; + + sa += step; + x = (float) Math.cos(sa); + y = (float) Math.sin(sa); + + float cp2x = x + k * y; + float cp2y = y - k * x; + + float c1x = (cx + xx * cp1x + yx * cp1y); + float c1y = (cy + xy * cp1x + yy * cp1y); + float c2x = (cx + xx * cp2x + yx * cp2y); + float c2y = (cy + xy * cp2x + yy * cp2y); + float ex = (cx + xx * x + yx * y); + float ey = (cy + xy * x + yy * y); + + mPath.cubicTo( + c1x * mScale, c1y * mScale, c2x * mScale, c2y * mScale, ex * mScale, ey * mScale); + elements.add( + new PathElement( + ElementType.kCGPathElementAddCurveToPoint, + new Point[] {new Point(c1x, c1y), new Point(c2x, c2y), new Point(ex, ey)})); + } + } + + private static void setPenDown() { + if (!mPenDown) { + mPenDownX = mPenX; + mPenDownY = mPenY; + mPenDown = true; + } + } + + private static double round(double val) { + double multiplier = Math.pow(10, 4); + return Math.round(val * multiplier) / multiplier; + } + + private static void skip_spaces() { + while (i < l && Character.isWhitespace(s.charAt(i))) i++; + } + + private static boolean is_cmd(char c) { + switch (c) { + case 'M': + case 'm': + case 'Z': + case 'z': + case 'L': + case 'l': + case 'H': + case 'h': + case 'V': + case 'v': + case 'C': + case 'c': + case 'S': + case 's': + case 'Q': + case 'q': + case 'T': + case 't': + case 'A': + case 'a': + return true; + } + return false; + } + + private static boolean is_number_start(char c) { + return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+'; + } + + private static boolean is_absolute(char c) { + return Character.isUpperCase(c); + } + + // By the SVG spec 'large-arc' and 'sweep' must contain only one char + // and can be written without any separators, e.g.: 10 20 30 01 10 20. + private static boolean parse_flag() { + skip_spaces(); + + char c = s.charAt(i); + switch (c) { + case '0': + case '1': + { + i += 1; + if (i < l && s.charAt(i) == ',') { + i += 1; + } + skip_spaces(); + break; + } + default: + throw new Error(String.format("Unexpected flag '%c' (i=%d, s=%s)", c, i, s)); + } + + return c == '1'; + } + + private static float parse_list_number() { + if (i == l) { + throw new Error(String.format("Unexpected end (s=%s)", s)); + } + + float n = parse_number(); + skip_spaces(); + parse_list_separator(); + + return n; + } + + private static float parse_number() { + // Strip off leading whitespaces. + skip_spaces(); + + if (i == l) { + throw new Error(String.format("Unexpected end (s=%s)", s)); + } + + int start = i; + + char c = s.charAt(i); + + // Consume sign. + if (c == '-' || c == '+') { + i += 1; + c = s.charAt(i); + } + + // Consume integer. + if (c >= '0' && c <= '9') { + skip_digits(); + if (i < l) { + c = s.charAt(i); + } + } else if (c != '.') { + throw new Error( + String.format("Invalid number formating character '%c' (i=%d, s=%s)", c, i, s)); + } + + // Consume fraction. + if (c == '.') { + i += 1; + skip_digits(); + if (i < l) { + c = s.charAt(i); + } + } + + if ((c == 'e' || c == 'E') && i + 1 < l) { + char c2 = s.charAt(i + 1); + // Check for `em`/`ex`. + if (c2 != 'm' && c2 != 'x') { + i += 1; + c = s.charAt(i); + + if (c == '+' || c == '-') { + i += 1; + skip_digits(); + } else if (c >= '0' && c <= '9') { + skip_digits(); + } else { + throw new Error( + String.format("Invalid number formating character '%c' (i=%d, s=%s)", c, i, s)); + } + } + } + + String num = s.substring(start, i); + float n = Float.parseFloat(num); + + // inf, nan, etc. are an error. + if (Float.isInfinite(n) || Float.isNaN(n)) { + throw new Error( + String.format("Invalid number '%s' (start=%d, i=%d, s=%s)", num, start, i, s)); + } + + return n; + } + + private static void parse_list_separator() { + if (i < l && s.charAt(i) == ',') { + i += 1; + } + } + + private static void skip_digits() { + while (i < l && Character.isDigit(s.charAt(i))) i++; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PathView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PathView.java new file mode 100644 index 00000000000000..6796a43f61ec49 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PathView.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class PathView extends RenderableView { + private Path mPath; + + public PathView(ReactContext reactContext) { + super(reactContext); + PathParser.mScale = mScale; + mPath = new Path(); + } + + public void setD(String d) { + mPath = PathParser.parse(d); + elements = PathParser.elements; + for (PathElement elem : elements) { + for (Point point : elem.points) { + point.x *= mScale; + point.y *= mScale; + } + } + invalidate(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + return mPath; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PatternView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PatternView.java new file mode 100644 index 00000000000000..e818fec351d1f9 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PatternView.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Matrix; +import android.graphics.RectF; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class PatternView extends GroupView { + + private SVGLength mX; + private SVGLength mY; + private SVGLength mW; + private SVGLength mH; + private Brush.BrushUnits mPatternUnits; + private Brush.BrushUnits mPatternContentUnits; + + private float mMinX; + private float mMinY; + private float mVbWidth; + private float mVbHeight; + String mAlign; + int mMeetOrSlice; + + private static final float[] sRawMatrix = + new float[] { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }; + private Matrix mMatrix = null; + + public PatternView(ReactContext reactContext) { + super(reactContext); + } + + public void setX(Dynamic x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(String x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(Double x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setY(Dynamic y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(String y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(Double y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setWidth(Dynamic width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(String width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(Double width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setHeight(Dynamic height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(String height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(Double height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setPatternUnits(int patternUnits) { + switch (patternUnits) { + case 0: + mPatternUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mPatternUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + invalidate(); + } + + public void setPatternContentUnits(int patternContentUnits) { + switch (patternContentUnits) { + case 0: + mPatternContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mPatternContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + invalidate(); + } + + public void setPatternTransform(@Nullable ReadableArray matrixArray) { + if (matrixArray != null) { + int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); + if (matrixSize == 6) { + if (mMatrix == null) { + mMatrix = new Matrix(); + } + mMatrix.setValues(sRawMatrix); + } else if (matrixSize != -1) { + FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); + } + } else { + mMatrix = null; + } + + invalidate(); + } + + public void setMinX(float minX) { + mMinX = minX; + invalidate(); + } + + public void setMinY(float minY) { + mMinY = minY; + invalidate(); + } + + public void setVbWidth(float vbWidth) { + mVbWidth = vbWidth; + invalidate(); + } + + public void setVbHeight(float vbHeight) { + mVbHeight = vbHeight; + invalidate(); + } + + public void setAlign(String align) { + mAlign = align; + invalidate(); + } + + public void setMeetOrSlice(int meetOrSlice) { + mMeetOrSlice = meetOrSlice; + invalidate(); + } + + RectF getViewBox() { + return new RectF( + mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); + } + + @Override + void saveDefinition() { + if (mName != null) { + SVGLength[] points = new SVGLength[] {mX, mY, mW, mH}; + Brush brush = new Brush(Brush.BrushType.PATTERN, points, mPatternUnits); + brush.setContentUnits(mPatternContentUnits); + brush.setPattern(this); + + if (mMatrix != null) { + brush.setGradientTransform(mMatrix); + } + + SvgView svg = getSvgView(); + if (mPatternUnits == Brush.BrushUnits.USER_SPACE_ON_USE + || mPatternContentUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { + brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); + } + + svg.defineBrush(brush, mName); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PropHelper.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PropHelper.java new file mode 100644 index 00000000000000..39ab0602b57f2f --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/PropHelper.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import abi49_0_0.com.facebook.react.bridge.ReadableArray; + +/** Contains static helper methods for accessing props. */ +class PropHelper { + + private static final int inputMatrixDataSize = 6; + + /** + * Converts given {@link ReadableArray} to a matrix data array, {@code float[6]}. Writes result to + * the array passed in {@param into}. This method will write exactly six items to the output array + * from the input array. + * + *

If the input array has a different size, then only the size is returned; Does not check + * output array size. Ensure space for at least six elements. + * + * @param value input array + * @param sRawMatrix output matrix + * @param mScale current resolution scaling + * @return size of input array + */ + static int toMatrixData(ReadableArray value, float[] sRawMatrix, float mScale) { + int fromSize = value.size(); + if (fromSize != inputMatrixDataSize) { + return fromSize; + } + + sRawMatrix[0] = (float) value.getDouble(0); + sRawMatrix[1] = (float) value.getDouble(2); + sRawMatrix[2] = (float) value.getDouble(4) * mScale; + sRawMatrix[3] = (float) value.getDouble(1); + sRawMatrix[4] = (float) value.getDouble(3); + sRawMatrix[5] = (float) value.getDouble(5) * mScale; + + return inputMatrixDataSize; + } + + /** + * Converts length string into px / user units in the current user coordinate system + * + * @param length length string + * @param relative relative size for percentages + * @param scale scaling parameter + * @param fontSize current font size + * @return value in the current user coordinate system + */ + static double fromRelative(String length, double relative, double scale, double fontSize) { + /* + TODO list + + unit relative to + em font size of the element + ex x-height of the element’s font + ch width of the "0" (ZERO, U+0030) glyph in the element’s font + rem font size of the root element + vw 1% of viewport’s width + vh 1% of viewport’s height + vmin 1% of viewport’s smaller dimension + vmax 1% of viewport’s larger dimension + + relative-size [ larger | smaller ] + absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ] + + https://www.w3.org/TR/css3-values/#relative-lengths + https://www.w3.org/TR/css3-values/#absolute-lengths + https://drafts.csswg.org/css-cascade-4/#computed-value + https://drafts.csswg.org/css-fonts-3/#propdef-font-size + https://drafts.csswg.org/css2/fonts.html#propdef-font-size + */ + length = length.trim(); + int stringLength = length.length(); + int percentIndex = stringLength - 1; + if (stringLength == 0 || length.equals("normal")) { + return 0d; + } else if (length.codePointAt(percentIndex) == '%') { + return Double.valueOf(length.substring(0, percentIndex)) / 100 * relative; + } else { + int twoLetterUnitIndex = stringLength - 2; + if (twoLetterUnitIndex > 0) { + String lastTwo = length.substring(twoLetterUnitIndex); + int end = twoLetterUnitIndex; + double unit = 1; + + switch (lastTwo) { + case "px": + break; + + case "em": + unit = fontSize; + break; + + /* + "1pt" equals "1.25px" (and therefore 1.25 user units) + "1pc" equals "15px" (and therefore 15 user units) + "1mm" would be "3.543307px" (3.543307 user units) + "1cm" equals "35.43307px" (and therefore 35.43307 user units) + "1in" equals "90px" (and therefore 90 user units) + */ + + case "pt": + unit = 1.25d; + break; + + case "pc": + unit = 15; + break; + + case "mm": + unit = 3.543307d; + break; + + case "cm": + unit = 35.43307d; + break; + + case "in": + unit = 90; + break; + + default: + end = stringLength; + } + + return Double.valueOf(length.substring(0, end)) * unit * scale; + } else { + return Double.valueOf(length) * scale; + } + } + } + /** + * Converts SVGLength into px / user units in the current user coordinate system + * + * @param length length string + * @param relative relative size for percentages + * @param offset offset for all units + * @param scale scaling parameter + * @param fontSize current font size + * @return value in the current user coordinate system + */ + static double fromRelative( + SVGLength length, double relative, double offset, double scale, double fontSize) { + /* + TODO list + + unit relative to + em font size of the element + ex x-height of the element’s font + ch width of the "0" (ZERO, U+0030) glyph in the element’s font + rem font size of the root element + vw 1% of viewport’s width + vh 1% of viewport’s height + vmin 1% of viewport’s smaller dimension + vmax 1% of viewport’s larger dimension + + relative-size [ larger | smaller ] + absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ] + + https://www.w3.org/TR/css3-values/#relative-lengths + https://www.w3.org/TR/css3-values/#absolute-lengths + https://drafts.csswg.org/css-cascade-4/#computed-value + https://drafts.csswg.org/css-fonts-3/#propdef-font-size + https://drafts.csswg.org/css2/fonts.html#propdef-font-size + */ + if (length == null) { + return offset; + } + SVGLength.UnitType unitType = length.unit; + double value = length.value; + double unit = 1; + switch (unitType) { + case NUMBER: + case PX: + break; + + case PERCENTAGE: + return value / 100 * relative + offset; + + case EMS: + unit = fontSize; + break; + case EXS: + unit = fontSize / 2; + break; + + case CM: + unit = 35.43307; + break; + case MM: + unit = 3.543307; + break; + case IN: + unit = 90; + break; + case PT: + unit = 1.25; + break; + case PC: + unit = 15; + break; + + default: + case UNKNOWN: + return value * scale + offset; + } + return value * unit * scale + offset; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RNSVGMarkerPosition.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RNSVGMarkerPosition.java new file mode 100644 index 00000000000000..3240f121573dc8 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RNSVGMarkerPosition.java @@ -0,0 +1,172 @@ +package abi49_0_0.com.horcrux.svg; + +import java.util.ArrayList; + +enum RNSVGMarkerType { + kStartMarker, + kMidMarker, + kEndMarker +} + +enum ElementType { + kCGPathElementAddCurveToPoint, + kCGPathElementAddQuadCurveToPoint, + kCGPathElementMoveToPoint, + kCGPathElementAddLineToPoint, + kCGPathElementCloseSubpath +} + +class Point { + double x; + double y; + + Point(double x, double y) { + this.x = x; + this.y = y; + } +} + +class SegmentData { + Point start_tangent; // Tangent in the start point of the segment. + Point end_tangent; // Tangent in the end point of the segment. + Point position; // The end point of the segment. +} + +class RNSVGMarkerPosition { + + private static ArrayList positions_; + private static int element_index_; + private static Point origin_; + private static Point subpath_start_; + private static Point in_slope_; + private static Point out_slope_; + + @SuppressWarnings("unused") + private static boolean auto_start_reverse_; // TODO + + RNSVGMarkerType type; + Point origin; + double angle; + + private RNSVGMarkerPosition(RNSVGMarkerType type, Point origin, double angle) { + this.type = type; + this.origin = origin; + this.angle = angle; + } + + static ArrayList fromPath(ArrayList elements) { + positions_ = new ArrayList<>(); + element_index_ = 0; + origin_ = new Point(0, 0); + subpath_start_ = new Point(0, 0); + for (PathElement e : elements) { + UpdateFromPathElement(e); + } + PathIsDone(); + return positions_; + } + + private static void PathIsDone() { + double angle = CurrentAngle(RNSVGMarkerType.kEndMarker); + positions_.add(new RNSVGMarkerPosition(RNSVGMarkerType.kEndMarker, origin_, angle)); + } + + private static double BisectingAngle(double in_angle, double out_angle) { + // WK193015: Prevent bugs due to angles being non-continuous. + if (Math.abs(in_angle - out_angle) > 180) in_angle += 360; + return (in_angle + out_angle) / 2; + } + + private static double rad2deg(double rad) { + double RNSVG_radToDeg = 180 / Math.PI; + return rad * RNSVG_radToDeg; + } + + private static double SlopeAngleRadians(Point p) { + return Math.atan2(p.y, p.x); + } + + private static double CurrentAngle(RNSVGMarkerType type) { + // For details of this calculation, see: + // http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement + double in_angle = rad2deg(SlopeAngleRadians(in_slope_)); + double out_angle = rad2deg(SlopeAngleRadians(out_slope_)); + switch (type) { + case kStartMarker: + if (auto_start_reverse_) out_angle += 180; + return out_angle; + case kMidMarker: + return BisectingAngle(in_angle, out_angle); + case kEndMarker: + return in_angle; + } + return 0; + } + + private static Point subtract(Point p1, Point p2) { + return new Point(p2.x - p1.x, p2.y - p1.y); + } + + private static boolean isZero(Point p) { + return p.x == 0 && p.y == 0; + } + + private static void ComputeQuadTangents(SegmentData data, Point start, Point control, Point end) { + data.start_tangent = subtract(control, start); + data.end_tangent = subtract(end, control); + if (isZero(data.start_tangent)) data.start_tangent = data.end_tangent; + else if (isZero(data.end_tangent)) data.end_tangent = data.start_tangent; + } + + private static SegmentData ExtractPathElementFeatures(PathElement element) { + SegmentData data = new SegmentData(); + Point[] points = element.points; + switch (element.type) { + case kCGPathElementAddCurveToPoint: + data.position = points[2]; + data.start_tangent = subtract(points[0], origin_); + data.end_tangent = subtract(points[2], points[1]); + if (isZero(data.start_tangent)) ComputeQuadTangents(data, points[0], points[1], points[2]); + else if (isZero(data.end_tangent)) ComputeQuadTangents(data, origin_, points[0], points[1]); + break; + case kCGPathElementAddQuadCurveToPoint: + data.position = points[1]; + ComputeQuadTangents(data, origin_, points[0], points[1]); + break; + case kCGPathElementMoveToPoint: + case kCGPathElementAddLineToPoint: + data.position = points[0]; + data.start_tangent = subtract(data.position, origin_); + data.end_tangent = subtract(data.position, origin_); + break; + case kCGPathElementCloseSubpath: + data.position = subpath_start_; + data.start_tangent = subtract(data.position, origin_); + data.end_tangent = subtract(data.position, origin_); + break; + } + return data; + } + + private static void UpdateFromPathElement(PathElement element) { + SegmentData segment_data = ExtractPathElementFeatures(element); + // First update the outgoing slope for the previous element. + out_slope_ = segment_data.start_tangent; + // Record the marker for the previous element. + if (element_index_ > 0) { + RNSVGMarkerType marker_type = + element_index_ == 1 ? RNSVGMarkerType.kStartMarker : RNSVGMarkerType.kMidMarker; + double angle = CurrentAngle(marker_type); + positions_.add(new RNSVGMarkerPosition(marker_type, origin_, angle)); + } + // Update the incoming slope for this marker position. + in_slope_ = segment_data.end_tangent; + // Update marker position. + origin_ = segment_data.position; + // If this is a 'move to' segment, save the point for use with 'close'. + if (element.type == ElementType.kCGPathElementMoveToPoint) subpath_start_ = element.points[0]; + else if (element.type == ElementType.kCGPathElementCloseSubpath) + subpath_start_ = new Point(0, 0); + ++element_index_; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RNSVGRenderableManager.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RNSVGRenderableManager.java new file mode 100644 index 00000000000000..0a667f052cc971 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RNSVGRenderableManager.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.facebook.react.common.StandardCharsets.UTF_8; + +import android.content.res.Resources; +import android.graphics.Matrix; +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.RectF; +import android.graphics.Region; +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.Promise; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.WritableMap; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.horcrux.rnsvg.NativeSvgRenderableModuleSpec; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import javax.annotation.Nonnull; + +@ReactModule(name = RNSVGRenderableManager.NAME) +class RNSVGRenderableManager extends NativeSvgRenderableModuleSpec { + RNSVGRenderableManager(ReactApplicationContext reactContext) { + super(reactContext); + } + + public static final String NAME = "RNSVGRenderableModule"; + + @Nonnull + @Override + public String getName() { + return NAME; + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public boolean isPointInFill(Double tag, ReadableMap options) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return false; + } + + float scale = svg.mScale; + float x = (float) options.getDouble("x") * scale; + float y = (float) options.getDouble("y") * scale; + + int i = svg.hitTest(new float[] {x, y}); + return i != -1; + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public boolean isPointInStroke(Double tag, ReadableMap options) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return false; + } + + try { + svg.getPath(null, null); + } catch (NullPointerException e) { + svg.invalidate(); + return false; + } + + svg.initBounds(); + + float scale = svg.mScale; + int x = (int) (options.getDouble("x") * scale); + int y = (int) (options.getDouble("y") * scale); + + Region strokeRegion = svg.mStrokeRegion; + return strokeRegion != null && strokeRegion.contains(x, y); + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public double getTotalLength(Double tag) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return 0; + } + + Path path; + + try { + path = svg.getPath(null, null); + } catch (NullPointerException e) { + svg.invalidate(); + return -1; + } + + PathMeasure pm = new PathMeasure(path, false); + return pm.getLength() / svg.mScale; + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public WritableMap getPointAtLength(Double tag, ReadableMap options) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return Arguments.createMap(); + } + + Path path; + + try { + path = svg.getPath(null, null); + } catch (NullPointerException e) { + svg.invalidate(); + return Arguments.createMap(); + } + + PathMeasure pm = new PathMeasure(path, false); + float length = (float) options.getDouble("length"); + float scale = svg.mScale; + + float[] pos = new float[2]; + float[] tan = new float[2]; + float distance = Math.max(0, Math.min(length * scale, pm.getLength())); + pm.getPosTan(distance, pos, tan); + + double angle = Math.atan2(tan[1], tan[0]); + WritableMap result = Arguments.createMap(); + result.putDouble("x", pos[0] / scale); + result.putDouble("y", pos[1] / scale); + result.putDouble("angle", angle); + return result; + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public WritableMap getBBox(Double tag, ReadableMap options) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return Arguments.createMap(); + } + + boolean fill = options.getBoolean("fill"); + boolean stroke = options.getBoolean("stroke"); + boolean markers = options.getBoolean("markers"); + boolean clipped = options.getBoolean("clipped"); + + try { + svg.getPath(null, null); + } catch (NullPointerException e) { + svg.invalidate(); + return Arguments.createMap(); + } + + float scale = svg.mScale; + svg.initBounds(); + + RectF bounds = new RectF(); + RectF fillBounds = svg.mFillBounds; + RectF strokeBounds = svg.mStrokeBounds; + RectF markerBounds = svg.mMarkerBounds; + RectF clipBounds = svg.mClipBounds; + + if (fill && fillBounds != null) { + bounds.union(fillBounds); + } + if (stroke && strokeBounds != null) { + bounds.union(strokeBounds); + } + if (markers && markerBounds != null) { + bounds.union(markerBounds); + } + if (clipped && clipBounds != null) { + bounds.intersect(clipBounds); + } + + WritableMap result = Arguments.createMap(); + result.putDouble("x", bounds.left / scale); + result.putDouble("y", bounds.top / scale); + result.putDouble("width", bounds.width() / scale); + result.putDouble("height", bounds.height() / scale); + return result; + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public WritableMap getCTM(Double tag) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return Arguments.createMap(); + } + + float scale = svg.mScale; + Matrix ctm = new Matrix(svg.mCTM); + SvgView svgView = svg.getSvgView(); + if (svgView == null) { + throw new RuntimeException("Did not find parent SvgView for view with tag: " + tag); + } + Matrix invViewBoxMatrix = svgView.mInvViewBoxMatrix; + ctm.preConcat(invViewBoxMatrix); + + float[] values = new float[9]; + ctm.getValues(values); + + WritableMap result = Arguments.createMap(); + result.putDouble("a", values[Matrix.MSCALE_X]); + result.putDouble("b", values[Matrix.MSKEW_Y]); + result.putDouble("c", values[Matrix.MSKEW_X]); + result.putDouble("d", values[Matrix.MSCALE_Y]); + result.putDouble("e", values[Matrix.MTRANS_X] / scale); + result.putDouble("f", values[Matrix.MTRANS_Y] / scale); + return result; + } + + @SuppressWarnings("unused") + @ReactMethod(isBlockingSynchronousMethod = true) + @Override + public WritableMap getScreenCTM(Double tag) { + RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); + if (svg == null) { + return Arguments.createMap(); + } + + float[] values = new float[9]; + svg.mCTM.getValues(values); + float scale = svg.mScale; + + WritableMap result = Arguments.createMap(); + result.putDouble("a", values[Matrix.MSCALE_X]); + result.putDouble("b", values[Matrix.MSKEW_Y]); + result.putDouble("c", values[Matrix.MSKEW_X]); + result.putDouble("d", values[Matrix.MSCALE_Y]); + result.putDouble("e", values[Matrix.MTRANS_X] / scale); + result.putDouble("f", values[Matrix.MTRANS_Y] / scale); + return result; + } + + @ReactMethod + @Override + public void getRawResource(String name, Promise promise) { + try { + ReactApplicationContext context = getReactApplicationContext(); + Resources resources = context.getResources(); + String packageName = context.getPackageName(); + int id = resources.getIdentifier(name, "raw", packageName); + InputStream stream = resources.openRawResource(id); + try { + InputStreamReader reader = new InputStreamReader(stream, UTF_8); + char[] buffer = new char[DEFAULT_BUFFER_SIZE]; + StringBuilder builder = new StringBuilder(); + int n; + while ((n = reader.read(buffer, 0, DEFAULT_BUFFER_SIZE)) != EOF) { + builder.append(buffer, 0, n); + } + String result = builder.toString(); + promise.resolve(result); + } finally { + try { + stream.close(); + } catch (IOException ioe) { + // ignore + } + } + } catch (Exception e) { + e.printStackTrace(); + promise.reject(e); + } + } + + private static final int EOF = -1; + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RadialGradientView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RadialGradientView.java new file mode 100644 index 00000000000000..e0b303472c48e3 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RadialGradientView.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Matrix; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class RadialGradientView extends DefinitionView { + private SVGLength mFx; + private SVGLength mFy; + private SVGLength mRx; + private SVGLength mRy; + private SVGLength mCx; + private SVGLength mCy; + private ReadableArray mGradient; + private Brush.BrushUnits mGradientUnits; + + private static final float[] sRawMatrix = + new float[] { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }; + private Matrix mMatrix = null; + + public RadialGradientView(ReactContext reactContext) { + super(reactContext); + } + + public void setFx(Dynamic fx) { + mFx = SVGLength.from(fx); + invalidate(); + } + + public void setFx(String fx) { + mFx = SVGLength.from(fx); + invalidate(); + } + + public void setFx(Double fx) { + mFx = SVGLength.from(fx); + invalidate(); + } + + public void setFy(Dynamic fy) { + mFy = SVGLength.from(fy); + invalidate(); + } + + public void setFy(String fy) { + mFy = SVGLength.from(fy); + invalidate(); + } + + public void setFy(Double fy) { + mFy = SVGLength.from(fy); + invalidate(); + } + + public void setRx(Dynamic rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRx(String rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRx(Double rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRy(Dynamic ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setRy(String ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setRy(Double ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setCx(Dynamic cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCx(String cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCx(Double cx) { + mCx = SVGLength.from(cx); + invalidate(); + } + + public void setCy(Dynamic cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setCy(String cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setCy(Double cy) { + mCy = SVGLength.from(cy); + invalidate(); + } + + public void setGradient(ReadableArray gradient) { + mGradient = gradient; + invalidate(); + } + + public void setGradientUnits(int gradientUnits) { + switch (gradientUnits) { + case 0: + mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + invalidate(); + } + + public void setGradientTransform(@Nullable ReadableArray matrixArray) { + if (matrixArray != null) { + int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); + if (matrixSize == 6) { + if (mMatrix == null) { + mMatrix = new Matrix(); + } + mMatrix.setValues(sRawMatrix); + } else if (matrixSize != -1) { + FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); + } + } else { + mMatrix = null; + } + + invalidate(); + } + + @Override + void saveDefinition() { + if (mName != null) { + SVGLength[] points = new SVGLength[] {mFx, mFy, mRx, mRy, mCx, mCy}; + Brush brush = new Brush(Brush.BrushType.RADIAL_GRADIENT, points, mGradientUnits); + brush.setGradientColors(mGradient); + if (mMatrix != null) { + brush.setGradientTransform(mMatrix); + } + + SvgView svg = getSvgView(); + if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { + brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); + } + + svg.defineBrush(brush, mName); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RectView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RectView.java new file mode 100644 index 00000000000000..b58a945e0396de --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RectView.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.os.Build; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import java.util.ArrayList; + +@SuppressLint("ViewConstructor") +class RectView extends RenderableView { + private SVGLength mX; + private SVGLength mY; + private SVGLength mW; + private SVGLength mH; + private SVGLength mRx; + private SVGLength mRy; + + public RectView(ReactContext reactContext) { + super(reactContext); + } + + public void setX(Dynamic x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(String x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(Double x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setY(Dynamic y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(String y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(Double y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setWidth(Dynamic width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(String width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(Double width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setHeight(Dynamic height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(String height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(Double height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setRx(Dynamic rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRx(String rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRx(Double rx) { + mRx = SVGLength.from(rx); + invalidate(); + } + + public void setRy(Dynamic ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setRy(String ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + public void setRy(Double ry) { + mRy = SVGLength.from(ry); + invalidate(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + Path path = new Path(); + double x = relativeOnWidth(mX); + double y = relativeOnHeight(mY); + double w = relativeOnWidth(mW); + double h = relativeOnHeight(mH); + + if (mRx != null || mRy != null) { + double rx = 0d; + double ry = 0d; + if (mRx == null) { + ry = relativeOnHeight(mRy); + rx = ry; + } else if (mRy == null) { + rx = relativeOnWidth(mRx); + ry = rx; + } else { + rx = relativeOnWidth(mRx); + ry = relativeOnHeight(mRy); + } + + if (rx > w / 2) { + rx = w / 2; + } + + if (ry > h / 2) { + ry = h / 2; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + path.addRoundRect( + (float) x, + (float) y, + (float) (x + w), + (float) (y + h), + (float) rx, + (float) ry, + Path.Direction.CW); + } else { + path.addRoundRect( + new RectF((float) x, (float) y, (float) (x + w), (float) (y + h)), + (float) rx, + (float) ry, + Path.Direction.CW); + } + } else { + path.addRect((float) x, (float) y, (float) (x + w), (float) (y + h), Path.Direction.CW); + path.close(); // Ensure isSimplePath = false such that rect doesn't become represented using + // integers + } + + elements = new ArrayList<>(); + elements.add( + new PathElement(ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(x, y)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x + w, y)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x + w, y + h)})); + elements.add( + new PathElement( + ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x, y + h)})); + elements.add( + new PathElement(ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x, y)})); + + return path; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RenderableView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RenderableView.java new file mode 100644 index 00000000000000..0ace1f71677fe0 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RenderableView.java @@ -0,0 +1,729 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.DashPathEffect; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import abi49_0_0.com.facebook.react.bridge.ColorPropConverter; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.JSApplicationIllegalArgumentException; +import abi49_0_0.com.facebook.react.bridge.JavaOnlyArray; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableType; +import abi49_0_0.com.facebook.react.touch.ReactHitSlopView; +import abi49_0_0.com.facebook.react.uimanager.PointerEvents; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.Nullable; + +@SuppressWarnings({"WeakerAccess", "RedundantSuppression"}) +public abstract class RenderableView extends VirtualView implements ReactHitSlopView { + + RenderableView(ReactContext reactContext) { + super(reactContext); + setPivotX(0); + setPivotY(0); + } + + static RenderableView contextElement; + // strokeLinecap + private static final int CAP_BUTT = 0; + static final int CAP_ROUND = 1; + private static final int CAP_SQUARE = 2; + + // strokeLinejoin + private static final int JOIN_BEVEL = 2; + private static final int JOIN_MITER = 0; + static final int JOIN_ROUND = 1; + + // fillRule + private static final int FILL_RULE_EVENODD = 0; + static final int FILL_RULE_NONZERO = 1; + + // vectorEffect + private static final int VECTOR_EFFECT_DEFAULT = 0; + private static final int VECTOR_EFFECT_NON_SCALING_STROKE = 1; + // static final int VECTOR_EFFECT_INHERIT = 2; + // static final int VECTOR_EFFECT_URI = 3; + + /* + Used in mergeProperties, keep public + */ + + public int vectorEffect = VECTOR_EFFECT_DEFAULT; + public @Nullable ReadableArray stroke; + public @Nullable SVGLength[] strokeDasharray; + + public SVGLength strokeWidth = new SVGLength(1); + public float strokeOpacity = 1; + public float strokeMiterlimit = 4; + public float strokeDashoffset = 0; + + public Paint.Cap strokeLinecap = Paint.Cap.BUTT; + public Paint.Join strokeLinejoin = Paint.Join.MITER; + + public @Nullable ReadableArray fill; + public float fillOpacity = 1; + public Path.FillType fillRule = Path.FillType.WINDING; + + /* + End merged properties + */ + private @Nullable ArrayList mLastMergedList; + private @Nullable ArrayList mOriginProperties; + private @Nullable ArrayList mPropList; + private @Nullable ArrayList mAttributeList; + + private static final Pattern regex = Pattern.compile("[0-9.-]+"); + + @Nullable + public Rect getHitSlopRect() { + /* + * In order to make the isTouchPointInView fail we need to return a very improbable Rect for the View + * This way an SVG with box_none carrying its last descendent with box_none will have the expected behavior of just having events on the actual painted area + */ + if (mPointerEvents == PointerEvents.BOX_NONE) { + return new Rect(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + } + return null; + } + + @Override + public void setId(int id) { + super.setId(id); + RenderableViewManager.setRenderableView(id, this); + } + + public void setVectorEffect(int vectorEffect) { + this.vectorEffect = vectorEffect; + invalidate(); + } + + public void setFill(@Nullable Dynamic fill) { + if (fill == null || fill.isNull()) { + this.fill = null; + invalidate(); + return; + } + + ReadableType fillType = fill.getType(); + if (fillType.equals(ReadableType.Map)) { + ReadableMap fillMap = fill.asMap(); + setFill(fillMap); + return; + } + + // This code will probably never be reached with current changes + if (fillType.equals(ReadableType.Number)) { + this.fill = JavaOnlyArray.of(0, fill.asInt()); + } else if (fillType.equals(ReadableType.Array)) { + this.fill = fill.asArray(); + } else { + JavaOnlyArray arr = new JavaOnlyArray(); + arr.pushInt(0); + Matcher m = regex.matcher(fill.asString()); + int i = 0; + while (m.find()) { + double parsed = Double.parseDouble(m.group()); + arr.pushDouble(i++ < 3 ? parsed / 255 : parsed); + } + this.fill = arr; + } + invalidate(); + } + + public void setFill(ReadableMap fill) { + if (fill == null) { + this.fill = null; + invalidate(); + return; + } + int type = fill.getInt("type"); + if (type == 0) { + ReadableType valueType = fill.getType("payload"); + if (valueType.equals(ReadableType.Number)) { + this.fill = JavaOnlyArray.of(0, fill.getInt("payload")); + } else if (valueType.equals(ReadableType.Map)) { + this.fill = JavaOnlyArray.of(0, fill.getMap("payload")); + } + } else if (type == 1) { + this.fill = JavaOnlyArray.of(1, fill.getString("brushRef")); + } else { + this.fill = JavaOnlyArray.of(type); + } + invalidate(); + } + + public void setFillOpacity(float fillOpacity) { + this.fillOpacity = fillOpacity; + invalidate(); + } + + public void setFillRule(int fillRule) { + switch (fillRule) { + case FILL_RULE_EVENODD: + this.fillRule = Path.FillType.EVEN_ODD; + break; + case FILL_RULE_NONZERO: + break; + default: + throw new JSApplicationIllegalArgumentException("fillRule " + fillRule + " unrecognized"); + } + + invalidate(); + } + + public void setStroke(@Nullable Dynamic strokeColors) { + if (strokeColors == null || strokeColors.isNull()) { + stroke = null; + invalidate(); + return; + } + + ReadableType strokeType = strokeColors.getType(); + if (strokeType.equals(ReadableType.Map)) { + ReadableMap strokeMap = strokeColors.asMap(); + setStroke(strokeMap); + return; + } + + // This code will probably never be reached with current changes + ReadableType type = strokeColors.getType(); + if (type.equals(ReadableType.Number)) { + stroke = JavaOnlyArray.of(0, strokeColors.asInt()); + } else if (type.equals(ReadableType.Array)) { + stroke = strokeColors.asArray(); + } else { + JavaOnlyArray arr = new JavaOnlyArray(); + arr.pushInt(0); + Matcher m = regex.matcher(strokeColors.asString()); + int i = 0; + while (m.find()) { + double parsed = Double.parseDouble(m.group()); + arr.pushDouble(i++ < 3 ? parsed / 255 : parsed); + } + stroke = arr; + } + invalidate(); + } + + public void setStroke(@Nullable ReadableMap stroke) { + if (stroke == null) { + this.stroke = null; + invalidate(); + return; + } + int type = stroke.getInt("type"); + if (type == 0) { + ReadableType payloadType = stroke.getType("payload"); + if (payloadType.equals(ReadableType.Number)) { + this.stroke = JavaOnlyArray.of(0, stroke.getInt("payload")); + } else if (payloadType.equals(ReadableType.Map)) { + this.stroke = JavaOnlyArray.of(0, stroke.getMap("payload")); + } + } else if (type == 1) { + this.stroke = JavaOnlyArray.of(1, stroke.getString("brushRef")); + } else { + this.stroke = JavaOnlyArray.of(type); + } + invalidate(); + } + + public void setStrokeOpacity(float strokeOpacity) { + this.strokeOpacity = strokeOpacity; + invalidate(); + } + + public void setStrokeDasharray(@Nullable ReadableArray strokeDasharray) { + if (strokeDasharray != null) { + int fromSize = strokeDasharray.size(); + this.strokeDasharray = new SVGLength[fromSize]; + for (int i = 0; i < fromSize; i++) { + this.strokeDasharray[i] = SVGLength.from(strokeDasharray.getDynamic(i)); + } + } else { + this.strokeDasharray = null; + } + invalidate(); + } + + public void setStrokeDashoffset(float strokeDashoffset) { + this.strokeDashoffset = strokeDashoffset * mScale; + invalidate(); + } + + public void setStrokeWidth(Dynamic strokeWidth) { + this.strokeWidth = SVGLength.from(strokeWidth); + invalidate(); + } + + public void setStrokeWidth(String strokeWidth) { + this.strokeWidth = SVGLength.from(strokeWidth); + invalidate(); + } + + public void setStrokeWidth(Double strokeWidth) { + this.strokeWidth = SVGLength.from(strokeWidth); + invalidate(); + } + + public void setStrokeMiterlimit(float strokeMiterlimit) { + this.strokeMiterlimit = strokeMiterlimit; + invalidate(); + } + + public void setStrokeLinecap(int strokeLinecap) { + switch (strokeLinecap) { + case CAP_BUTT: + this.strokeLinecap = Paint.Cap.BUTT; + break; + case CAP_SQUARE: + this.strokeLinecap = Paint.Cap.SQUARE; + break; + case CAP_ROUND: + this.strokeLinecap = Paint.Cap.ROUND; + break; + default: + throw new JSApplicationIllegalArgumentException( + "strokeLinecap " + strokeLinecap + " unrecognized"); + } + invalidate(); + } + + public void setStrokeLinejoin(int strokeLinejoin) { + switch (strokeLinejoin) { + case JOIN_MITER: + this.strokeLinejoin = Paint.Join.MITER; + break; + case JOIN_BEVEL: + this.strokeLinejoin = Paint.Join.BEVEL; + break; + case JOIN_ROUND: + this.strokeLinejoin = Paint.Join.ROUND; + break; + default: + throw new JSApplicationIllegalArgumentException( + "strokeLinejoin " + strokeLinejoin + " unrecognized"); + } + invalidate(); + } + + public void setPropList(@Nullable ReadableArray propList) { + if (propList != null) { + mPropList = mAttributeList = new ArrayList<>(); + for (int i = 0; i < propList.size(); i++) { + mPropList.add(propList.getString(i)); + } + } + + invalidate(); + } + + private static double saturate(double v) { + return v <= 0 ? 0 : (v >= 1 ? 1 : v); + } + + void render(Canvas canvas, Paint paint, float opacity) { + MaskView mask = null; + if (mMask != null) { + SvgView root = getSvgView(); + mask = (MaskView) root.getDefinedMask(mMask); + } + if (mask != null) { + Rect clipBounds = canvas.getClipBounds(); + int height = clipBounds.height(); + int width = clipBounds.width(); + + Bitmap maskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Bitmap original = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + + Canvas originalCanvas = new Canvas(original); + Canvas maskCanvas = new Canvas(maskBitmap); + Canvas resultCanvas = new Canvas(result); + + // Clip to mask bounds and render the mask + float maskX = (float) relativeOnWidth(mask.mX); + float maskY = (float) relativeOnHeight(mask.mY); + float maskWidth = (float) relativeOnWidth(mask.mW); + float maskHeight = (float) relativeOnHeight(mask.mH); + maskCanvas.clipRect(maskX, maskY, maskWidth + maskX, maskHeight + maskY); + + Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mask.draw(maskCanvas, maskPaint, 1); + + // Apply luminanceToAlpha filter primitive + // https://www.w3.org/TR/SVG11/filters.html#feColorMatrixElement + int nPixels = width * height; + int[] pixels = new int[nPixels]; + maskBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + + for (int i = 0; i < nPixels; i++) { + int color = pixels[i]; + + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + int a = color >>> 24; + + double luminance = saturate(((0.299 * r) + (0.587 * g) + (0.144 * b)) / 255); + int alpha = (int) (a * luminance); + int pixel = (alpha << 24); + pixels[i] = pixel; + } + + maskBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + + // Render content of current SVG Renderable to image + draw(originalCanvas, paint, opacity); + + // Blend current element and mask + maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + resultCanvas.drawBitmap(original, 0, 0, null); + resultCanvas.drawBitmap(maskBitmap, 0, 0, maskPaint); + + // Render composited result into current render context + canvas.drawBitmap(result, 0, 0, paint); + } else { + draw(canvas, paint, opacity); + } + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + opacity *= mOpacity; + + boolean computePaths = mPath == null; + if (computePaths) { + mPath = getPath(canvas, paint); + mPath.setFillType(fillRule); + } + boolean nonScalingStroke = vectorEffect == VECTOR_EFFECT_NON_SCALING_STROKE; + Path path = mPath; + if (nonScalingStroke) { + Path scaled = new Path(); + //noinspection deprecation + mPath.transform(mCTM, scaled); + canvas.setMatrix(null); + path = scaled; + } + + if (computePaths || path != mPath) { + mBox = new RectF(); + path.computeBounds(mBox, true); + } + + RectF clientRect = new RectF(mBox); + mCTM.mapRect(clientRect); + this.setClientRect(clientRect); + + clip(canvas, paint); + + if (setupFillPaint(paint, opacity * fillOpacity)) { + if (computePaths) { + mFillPath = new Path(); + paint.getFillPath(path, mFillPath); + } + canvas.drawPath(path, paint); + } + if (setupStrokePaint(paint, opacity * strokeOpacity)) { + if (computePaths) { + mStrokePath = new Path(); + paint.getFillPath(path, mStrokePath); + } + canvas.drawPath(path, paint); + } + renderMarkers(canvas, paint, opacity); + } + + void renderMarkers(Canvas canvas, Paint paint, float opacity) { + MarkerView markerStart = (MarkerView) getSvgView().getDefinedMarker(mMarkerStart); + MarkerView markerMid = (MarkerView) getSvgView().getDefinedMarker(mMarkerMid); + MarkerView markerEnd = (MarkerView) getSvgView().getDefinedMarker(mMarkerEnd); + if (elements != null && (markerStart != null || markerMid != null || markerEnd != null)) { + contextElement = this; + ArrayList positions = RNSVGMarkerPosition.fromPath(elements); + float width = (float) (this.strokeWidth != null ? relativeOnOther(this.strokeWidth) : 1); + mMarkerPath = new Path(); + for (RNSVGMarkerPosition position : positions) { + RNSVGMarkerType type = position.type; + MarkerView marker = null; + switch (type) { + case kStartMarker: + marker = markerStart; + break; + + case kMidMarker: + marker = markerMid; + break; + + case kEndMarker: + marker = markerEnd; + break; + } + if (marker == null) { + continue; + } + marker.renderMarker(canvas, paint, opacity, position, width); + Matrix transform = marker.markerTransform; + mMarkerPath.addPath(marker.getPath(canvas, paint), transform); + } + contextElement = null; + } + } + + /** + * Sets up paint according to the props set on a view. Returns {@code true} if the fill should be + * drawn, {@code false} if not. + */ + boolean setupFillPaint(Paint paint, float opacity) { + if (fill != null && fill.size() > 0) { + paint.reset(); + paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG); + paint.setStyle(Paint.Style.FILL); + setupPaint(paint, opacity, fill); + return true; + } + return false; + } + + /** + * Sets up paint according to the props set on a view. Returns {@code true} if the stroke should + * be drawn, {@code false} if not. + */ + boolean setupStrokePaint(Paint paint, float opacity) { + paint.reset(); + double strokeWidth = relativeOnOther(this.strokeWidth); + if (strokeWidth == 0 || stroke == null || stroke.size() == 0) { + return false; + } + + paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeCap(strokeLinecap); + paint.setStrokeJoin(strokeLinejoin); + paint.setStrokeMiter(strokeMiterlimit * mScale); + paint.setStrokeWidth((float) strokeWidth); + setupPaint(paint, opacity, stroke); + + if (strokeDasharray != null) { + int length = strokeDasharray.length; + float[] intervals = new float[length]; + for (int i = 0; i < length; i++) { + intervals[i] = (float) relativeOnOther(strokeDasharray[i]); + } + paint.setPathEffect(new DashPathEffect(intervals, strokeDashoffset)); + } + + return true; + } + + private void setupPaint(Paint paint, float opacity, ReadableArray colors) { + int colorType = colors.getInt(0); + switch (colorType) { + case 0: + if (colors.size() == 2) { + int color; + if (colors.getType(1) == ReadableType.Map) { + color = ColorPropConverter.getColor(colors.getMap(1), getContext()); + } else { + color = colors.getInt(1); + } + int alpha = color >>> 24; + int combined = Math.round((float) alpha * opacity); + paint.setColor(combined << 24 | (color & 0x00ffffff)); + } else { + // solid color + paint.setARGB( + (int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255), + (int) (colors.getDouble(1) * 255), + (int) (colors.getDouble(2) * 255), + (int) (colors.getDouble(3) * 255)); + } + break; + case 1: + { + Brush brush = getSvgView().getDefinedBrush(colors.getString(1)); + if (brush != null) { + brush.setupPaint(paint, mBox, mScale, opacity); + } + break; + } + case 2: + { + int brush = getSvgView().mTintColor; + paint.setColor(brush); + break; + } + case 3: + { + if (contextElement != null && contextElement.fill != null) { + setupPaint(paint, opacity, contextElement.fill); + } + break; + } + case 4: + { + if (contextElement != null && contextElement.stroke != null) { + setupPaint(paint, opacity, contextElement.stroke); + } + break; + } + } + } + + abstract Path getPath(Canvas canvas, Paint paint); + + @Override + int hitTest(final float[] src) { + if (mPath == null || !mInvertible || !mTransformInvertible) { + return -1; + } + + if (mPointerEvents == PointerEvents.NONE) { + return -1; + } + + float[] dst = new float[2]; + mInvMatrix.mapPoints(dst, src); + mInvTransform.mapPoints(dst); + int x = Math.round(dst[0]); + int y = Math.round(dst[1]); + + initBounds(); + + if ((mRegion == null || !mRegion.contains(x, y)) + && (mStrokeRegion == null + || !mStrokeRegion.contains(x, y) + && (mMarkerRegion == null || !mMarkerRegion.contains(x, y)))) { + return -1; + } + + Path clipPath = getClipPath(); + if (clipPath != null) { + if (!mClipRegion.contains(x, y)) { + return -1; + } + } + + return getId(); + } + + void initBounds() { + if (mRegion == null && mFillPath != null) { + mFillBounds = new RectF(); + mFillPath.computeBounds(mFillBounds, true); + mRegion = getRegion(mFillPath, mFillBounds); + } + if (mRegion == null && mPath != null) { + mFillBounds = new RectF(); + mPath.computeBounds(mFillBounds, true); + mRegion = getRegion(mPath, mFillBounds); + } + if (mStrokeRegion == null && mStrokePath != null) { + mStrokeBounds = new RectF(); + mStrokePath.computeBounds(mStrokeBounds, true); + mStrokeRegion = getRegion(mStrokePath, mStrokeBounds); + } + if (mMarkerRegion == null && mMarkerPath != null) { + mMarkerBounds = new RectF(); + mMarkerPath.computeBounds(mMarkerBounds, true); + mMarkerRegion = getRegion(mMarkerPath, mMarkerBounds); + } + Path clipPath = getClipPath(); + if (clipPath != null) { + if (mClipRegionPath != clipPath) { + mClipRegionPath = clipPath; + mClipBounds = new RectF(); + clipPath.computeBounds(mClipBounds, true); + mClipRegion = getRegion(clipPath, mClipBounds); + } + } + } + + Region getRegion(Path path, RectF rectF) { + Region region = new Region(); + region.setPath( + path, + new Region( + (int) Math.floor(rectF.left), + (int) Math.floor(rectF.top), + (int) Math.ceil(rectF.right), + (int) Math.ceil(rectF.bottom))); + + return region; + } + + private ArrayList getAttributeList() { + return mAttributeList; + } + + void mergeProperties(RenderableView target) { + ArrayList targetAttributeList = target.getAttributeList(); + + if (targetAttributeList == null || targetAttributeList.size() == 0) { + return; + } + + mOriginProperties = new ArrayList<>(); + mAttributeList = mPropList == null ? new ArrayList() : new ArrayList<>(mPropList); + + for (int i = 0, size = targetAttributeList.size(); i < size; i++) { + try { + String fieldName = targetAttributeList.get(i); + Field field = getClass().getField(fieldName); + Object value = field.get(target); + mOriginProperties.add(field.get(this)); + + if (!hasOwnProperty(fieldName)) { + mAttributeList.add(fieldName); + field.set(this, value); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + mLastMergedList = targetAttributeList; + } + + void resetProperties() { + if (mLastMergedList != null && mOriginProperties != null) { + try { + for (int i = mLastMergedList.size() - 1; i >= 0; i--) { + Field field = getClass().getField(mLastMergedList.get(i)); + field.set(this, mOriginProperties.get(i)); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + + mLastMergedList = null; + mOriginProperties = null; + mAttributeList = mPropList; + } + } + + private boolean hasOwnProperty(String propName) { + return mAttributeList != null && mAttributeList.contains(propName); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RenderableViewManager.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RenderableViewManager.java new file mode 100644 index 00000000000000..72fa96f7451629 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/RenderableViewManager.java @@ -0,0 +1,2088 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.determinant; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.inverse; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.multiplyVectorByMatrix; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.roundTo3Places; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.transpose; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.v3Combine; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.v3Cross; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.v3Dot; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.v3Length; +import static abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper.v3Normalize; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.ALIGN_CONTENT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.ALIGN_ITEMS; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.ALIGN_SELF; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_BOTTOM_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_END_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_LEFT_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_RIGHT_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_START_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_TOP_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BORDER_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.BOTTOM; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.COLLAPSABLE; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.DISPLAY; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.END; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FLEX; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FLEX_BASIS; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FLEX_DIRECTION; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FLEX_GROW; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FLEX_SHRINK; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.FLEX_WRAP; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.HEIGHT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.JUSTIFY_CONTENT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.LEFT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_BOTTOM; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_END; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_HORIZONTAL; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_LEFT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_RIGHT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_START; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_TOP; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MARGIN_VERTICAL; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MAX_HEIGHT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MAX_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MIN_HEIGHT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.MIN_WIDTH; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.OVERFLOW; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_BOTTOM; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_END; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_HORIZONTAL; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_LEFT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_RIGHT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_START; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_TOP; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.PADDING_VERTICAL; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.POSITION; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.RIGHT; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.START; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.TOP; +import static abi49_0_0.com.facebook.react.uimanager.ViewProps.WIDTH; +import static abi49_0_0.com.horcrux.svg.RenderableView.CAP_ROUND; +import static abi49_0_0.com.horcrux.svg.RenderableView.FILL_RULE_NONZERO; +import static abi49_0_0.com.horcrux.svg.RenderableView.JOIN_ROUND; + +import android.graphics.Matrix; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.JavaOnlyMap; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableType; +import abi49_0_0.com.facebook.react.uimanager.DisplayMetricsHolder; +import abi49_0_0.com.facebook.react.uimanager.LayoutShadowNode; +import abi49_0_0.com.facebook.react.uimanager.MatrixMathHelper; +import abi49_0_0.com.facebook.react.uimanager.PixelUtil; +import abi49_0_0.com.facebook.react.uimanager.PointerEvents; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import abi49_0_0.com.facebook.react.uimanager.TransformHelper; +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager; +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.ViewProps; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactPropGroup; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGCircleManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGCircleManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGClipPathManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGClipPathManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGDefsManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGDefsManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGEllipseManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGEllipseManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGForeignObjectManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGForeignObjectManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGGroupManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGGroupManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGImageManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGImageManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGLineManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGLineManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGLinearGradientManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGLinearGradientManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGMarkerManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGMarkerManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGMaskManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGMaskManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGPathManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGPathManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGPatternManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGPatternManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGRadialGradientManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGRadialGradientManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGRectManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGRectManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGSymbolManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGSymbolManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGTSpanManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGTSpanManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGTextManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGTextManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGTextPathManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGTextPathManagerInterface; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGUseManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGUseManagerInterface; +import java.util.Locale; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** ViewManager for DefinitionView RNSVG views */ +class VirtualViewManager extends ViewGroupManager { + + protected final SVGClass svgClass; + protected final String mClassName; + + protected VirtualViewManager(SVGClass svgclass) { + svgClass = svgclass; + mClassName = svgclass.toString(); + } + + protected ViewManagerDelegate mDelegate; + + protected ViewManagerDelegate getDelegate() { + return mDelegate; + } + + static class RenderableShadowNode extends LayoutShadowNode { + + @SuppressWarnings({"unused", "EmptyMethod"}) + @ReactPropGroup( + names = { + ALIGN_SELF, + ALIGN_ITEMS, + COLLAPSABLE, + FLEX, + FLEX_BASIS, + FLEX_DIRECTION, + FLEX_GROW, + FLEX_SHRINK, + FLEX_WRAP, + JUSTIFY_CONTENT, + OVERFLOW, + ALIGN_CONTENT, + DISPLAY, + + /* position */ + POSITION, + RIGHT, + TOP, + BOTTOM, + LEFT, + START, + END, + + /* dimensions */ + WIDTH, + HEIGHT, + MIN_WIDTH, + MAX_WIDTH, + MIN_HEIGHT, + MAX_HEIGHT, + + /* margins */ + MARGIN, + MARGIN_VERTICAL, + MARGIN_HORIZONTAL, + MARGIN_LEFT, + MARGIN_RIGHT, + MARGIN_TOP, + MARGIN_BOTTOM, + MARGIN_START, + MARGIN_END, + + /* paddings */ + PADDING, + PADDING_VERTICAL, + PADDING_HORIZONTAL, + PADDING_LEFT, + PADDING_RIGHT, + PADDING_TOP, + PADDING_BOTTOM, + PADDING_START, + PADDING_END, + BORDER_WIDTH, + BORDER_START_WIDTH, + BORDER_END_WIDTH, + BORDER_TOP_WIDTH, + BORDER_BOTTOM_WIDTH, + BORDER_LEFT_WIDTH, + BORDER_RIGHT_WIDTH, + }) + public void ignoreLayoutProps(int index, Dynamic value) {} + } + + @Override + public LayoutShadowNode createShadowNodeInstance() { + return new RenderableShadowNode(); + } + + @Override + public Class getShadowNodeClass() { + return RenderableShadowNode.class; + } + + static class MatrixDecompositionContext extends MatrixMathHelper.MatrixDecompositionContext { + final double[] perspective = new double[4]; + final double[] scale = new double[3]; + final double[] skew = new double[3]; + final double[] translation = new double[3]; + final double[] rotationDegrees = new double[3]; + } + + private static final MatrixDecompositionContext sMatrixDecompositionContext = + new MatrixDecompositionContext(); + private static final double[] sTransformDecompositionArray = new double[16]; + + private static final int PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX = 2; + private static final float CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER = 5; + + private static final double EPSILON = .00001d; + + private static boolean isZero(double d) { + return !Double.isNaN(d) && Math.abs(d) < EPSILON; + } + + private static void decomposeMatrix() { + + // output values + final double[] perspective = sMatrixDecompositionContext.perspective; + final double[] scale = sMatrixDecompositionContext.scale; + final double[] skew = sMatrixDecompositionContext.skew; + final double[] translation = sMatrixDecompositionContext.translation; + final double[] rotationDegrees = sMatrixDecompositionContext.rotationDegrees; + + // create normalized, 2d array matrix + // and normalized 1d array perspectiveMatrix with redefined 4th column + if (isZero(sTransformDecompositionArray[15])) { + return; + } + double[][] matrix = new double[4][4]; + double[] perspectiveMatrix = new double[16]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + double value = sTransformDecompositionArray[(i * 4) + j] / sTransformDecompositionArray[15]; + matrix[i][j] = value; + perspectiveMatrix[(i * 4) + j] = j == 3 ? 0 : value; + } + } + perspectiveMatrix[15] = 1; + + // test for singularity of upper 3x3 part of the perspective matrix + if (isZero(determinant(perspectiveMatrix))) { + return; + } + + // isolate perspective + if (!isZero(matrix[0][3]) || !isZero(matrix[1][3]) || !isZero(matrix[2][3])) { + // rightHandSide is the right hand side of the equation. + // rightHandSide is a vector, or point in 3d space relative to the origin. + double[] rightHandSide = {matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]}; + + // Solve the equation by inverting perspectiveMatrix and multiplying + // rightHandSide by the inverse. + double[] inversePerspectiveMatrix = inverse(perspectiveMatrix); + double[] transposedInversePerspectiveMatrix = transpose(inversePerspectiveMatrix); + multiplyVectorByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspective); + } else { + // no perspective + perspective[0] = perspective[1] = perspective[2] = 0d; + perspective[3] = 1d; + } + + // translation is simple + System.arraycopy(matrix[3], 0, translation, 0, 3); + + // Now get scale and shear. + // 'row' is a 3 element array of 3 component vectors + double[][] row = new double[3][3]; + for (int i = 0; i < 3; i++) { + row[i][0] = matrix[i][0]; + row[i][1] = matrix[i][1]; + row[i][2] = matrix[i][2]; + } + + // Compute X scale factor and normalize first row. + scale[0] = v3Length(row[0]); + row[0] = v3Normalize(row[0], scale[0]); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + skew[0] = v3Dot(row[0], row[1]); + row[1] = v3Combine(row[1], row[0], 1.0, -skew[0]); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + skew[0] = v3Dot(row[0], row[1]); + row[1] = v3Combine(row[1], row[0], 1.0, -skew[0]); + + // Now, compute Y scale and normalize 2nd row. + scale[1] = v3Length(row[1]); + row[1] = v3Normalize(row[1], scale[1]); + skew[0] /= scale[1]; + + // Compute XZ and YZ shears, orthogonalize 3rd row + skew[1] = v3Dot(row[0], row[2]); + row[2] = v3Combine(row[2], row[0], 1.0, -skew[1]); + skew[2] = v3Dot(row[1], row[2]); + row[2] = v3Combine(row[2], row[1], 1.0, -skew[2]); + + // Next, get Z scale and normalize 3rd row. + scale[2] = v3Length(row[2]); + row[2] = v3Normalize(row[2], scale[2]); + skew[1] /= scale[2]; + skew[2] /= scale[2]; + + // At this point, the matrix (in rows) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + double[] pdum3 = v3Cross(row[1], row[2]); + if (v3Dot(row[0], pdum3) < 0) { + for (int i = 0; i < 3; i++) { + scale[i] *= -1; + row[i][0] *= -1; + row[i][1] *= -1; + row[i][2] *= -1; + } + } + + // Now, get the rotations out + // Based on: http://nghiaho.com/?page_id=846 + double conv = 180 / Math.PI; + rotationDegrees[0] = roundTo3Places(-Math.atan2(row[2][1], row[2][2]) * conv); + rotationDegrees[1] = + roundTo3Places( + -Math.atan2(-row[2][0], Math.sqrt(row[2][1] * row[2][1] + row[2][2] * row[2][2])) + * conv); + rotationDegrees[2] = roundTo3Places(-Math.atan2(row[1][0], row[0][0]) * conv); + } + + private static void setTransformProperty(View view, ReadableArray transforms) { + TransformHelper.processTransform(transforms, sTransformDecompositionArray); + decomposeMatrix(); + view.setTranslationX( + PixelUtil.toPixelFromDIP((float) sMatrixDecompositionContext.translation[0])); + view.setTranslationY( + PixelUtil.toPixelFromDIP((float) sMatrixDecompositionContext.translation[1])); + view.setRotation((float) sMatrixDecompositionContext.rotationDegrees[2]); + view.setRotationX((float) sMatrixDecompositionContext.rotationDegrees[0]); + view.setRotationY((float) sMatrixDecompositionContext.rotationDegrees[1]); + view.setScaleX((float) sMatrixDecompositionContext.scale[0]); + view.setScaleY((float) sMatrixDecompositionContext.scale[1]); + + double[] perspectiveArray = sMatrixDecompositionContext.perspective; + + if (perspectiveArray.length > PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX) { + float invertedCameraDistance = + (float) perspectiveArray[PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX]; + if (invertedCameraDistance == 0) { + // Default camera distance, before scale multiplier (1280) + invertedCameraDistance = 0.00078125f; + } + float cameraDistance = -1 / invertedCameraDistance; + float scale = DisplayMetricsHolder.getScreenDisplayMetrics().density; + + // The following converts the matrix's perspective to a camera distance + // such that the camera perspective looks the same on Android and iOS. + // The native Android implementation removed the screen density from the + // calculation, so squaring and a normalization value of + // sqrt(5) produces an exact replica with iOS. + // For more information, see https://github.com/facebook/react-native/pull/18302 + float normalizedCameraDistance = + scale * scale * cameraDistance * CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER; + view.setCameraDistance(normalizedCameraDistance); + } + } + + private static void resetTransformProperty(View view) { + view.setTranslationX(0); + view.setTranslationY(0); + view.setRotation(0); + view.setRotationX(0); + view.setRotationY(0); + view.setScaleX(1); + view.setScaleY(1); + view.setCameraDistance(0); + } + + @Nonnull + public String getName() { + return mClassName; + } + + @ReactProp(name = "mask") + public void setMask(V node, String mask) { + node.setMask(mask); + } + + @ReactProp(name = "markerStart") + public void setMarkerStart(V node, String markerStart) { + node.setMarkerStart(markerStart); + } + + @ReactProp(name = "markerMid") + public void setMarkerMid(V node, String markerMid) { + node.setMarkerMid(markerMid); + } + + @ReactProp(name = "markerEnd") + public void setMarkerEnd(V node, String markerEnd) { + node.setMarkerEnd(markerEnd); + } + + @ReactProp(name = "clipPath") + public void setClipPath(V node, String clipPath) { + node.setClipPath(clipPath); + } + + @ReactProp(name = "clipRule") + public void setClipRule(V node, int clipRule) { + node.setClipRule(clipRule); + } + + @ReactProp(name = "opacity", defaultFloat = 1f) + public void setOpacity(@Nonnull V node, float opacity) { + node.setOpacity(opacity); + } + + @ReactProp(name = "responsible") + public void setResponsible(V node, boolean responsible) { + node.setResponsible(responsible); + } + + @ReactProp(name = ViewProps.POINTER_EVENTS) + public void setPointerEvents(V view, @Nullable String pointerEventsStr) { + if (pointerEventsStr == null) { + view.setPointerEvents(PointerEvents.AUTO); + } else { + PointerEvents pointerEvents = + PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_")); + view.setPointerEvents(pointerEvents); + } + } + + @ReactProp(name = "name") + public void setName(V node, String name) { + node.setName(name); + } + + @ReactProp(name = "display") + public void setDisplay(V node, String display) { + node.setDisplay(display); + } + + @ReactProp(name = "matrix") + public void setMatrix(V node, Dynamic matrixArray) { + node.setMatrix(matrixArray); + } + + public void setMatrix(V view, @Nullable ReadableArray value) { + view.setMatrix(value); + } + + @Override + public void setTransform(VirtualView node, @Nullable ReadableArray matrix) { + if (matrix == null) { + resetTransformProperty(node); + } else { + setTransformProperty(node, matrix); + } + + Matrix m = node.getMatrix(); + node.mTransform = m; + node.mTransformInvertible = m.invert(node.mInvTransform); + } + + @ReactProp(name = "transform") + public void setTransform(V node, Dynamic matrix) { + if (matrix.getType() != ReadableType.Array) { + return; + } + ReadableArray ma = matrix.asArray(); + setTransform(node, ma); + } + + private void invalidateSvgView(V node) { + SvgView view = node.getSvgView(); + if (view != null) { + view.invalidate(); + } + if (node instanceof TextView) { + ((TextView) node).getTextContainer().clearChildCache(); + } + } + + @Override + protected void addEventEmitters( + @Nonnull ThemedReactContext reactContext, @Nonnull VirtualView view) { + super.addEventEmitters(reactContext, view); + view.setOnHierarchyChangeListener( + new ViewGroup.OnHierarchyChangeListener() { + @Override + public void onChildViewAdded(View view, View view1) { + if (view instanceof VirtualView) { + invalidateSvgView((V) view); + } + } + + @Override + public void onChildViewRemoved(View view, View view1) { + if (view instanceof VirtualView) { + invalidateSvgView((V) view); + } + } + }); + } + + /** + * Callback that will be triggered after all properties are updated in current update transaction + * (all @ReactProp handlers for properties updated in current transaction have been called). If + * you want to override this method you should call super.onAfterUpdateTransaction from it as the + * parent class of the ViewManager may rely on callback being executed. + */ + @Override + protected void onAfterUpdateTransaction(@Nonnull VirtualView node) { + super.onAfterUpdateTransaction(node); + invalidateSvgView((V) node); + } + + protected enum SVGClass { + RNSVGGroup, + RNSVGPath, + RNSVGText, + RNSVGTSpan, + RNSVGTextPath, + RNSVGImage, + RNSVGCircle, + RNSVGEllipse, + RNSVGLine, + RNSVGRect, + RNSVGClipPath, + RNSVGDefs, + RNSVGUse, + RNSVGSymbol, + RNSVGLinearGradient, + RNSVGRadialGradient, + RNSVGPattern, + RNSVGMask, + RNSVGMarker, + RNSVGForeignObject, + } + + @Nonnull + @Override + protected VirtualView createViewInstance(@Nonnull ThemedReactContext reactContext) { + switch (svgClass) { + case RNSVGGroup: + return new GroupView(reactContext); + case RNSVGPath: + return new PathView(reactContext); + case RNSVGCircle: + return new CircleView(reactContext); + case RNSVGEllipse: + return new EllipseView(reactContext); + case RNSVGLine: + return new LineView(reactContext); + case RNSVGRect: + return new RectView(reactContext); + case RNSVGText: + return new TextView(reactContext); + case RNSVGTSpan: + return new TSpanView(reactContext); + case RNSVGTextPath: + return new TextPathView(reactContext); + case RNSVGImage: + return new ImageView(reactContext); + case RNSVGClipPath: + return new ClipPathView(reactContext); + case RNSVGDefs: + return new DefsView(reactContext); + case RNSVGUse: + return new UseView(reactContext); + case RNSVGSymbol: + return new SymbolView(reactContext); + case RNSVGLinearGradient: + return new LinearGradientView(reactContext); + case RNSVGRadialGradient: + return new RadialGradientView(reactContext); + case RNSVGPattern: + return new PatternView(reactContext); + case RNSVGMask: + return new MaskView(reactContext); + case RNSVGMarker: + return new MarkerView(reactContext); + case RNSVGForeignObject: + return new ForeignObjectView(reactContext); + default: + throw new IllegalStateException("Unexpected type " + svgClass.toString()); + } + } + + private static final SparseArray mTagToRenderableView = new SparseArray<>(); + private static final SparseArray mTagToRunnable = new SparseArray<>(); + + static void setRenderableView(int tag, RenderableView svg) { + mTagToRenderableView.put(tag, svg); + Runnable task = mTagToRunnable.get(tag); + if (task != null) { + task.run(); + mTagToRunnable.delete(tag); + } + } + + static void runWhenViewIsAvailable(int tag, Runnable task) { + mTagToRunnable.put(tag, task); + } + + static @Nullable RenderableView getRenderableViewByTag(int tag) { + return mTagToRenderableView.get(tag); + } + + @Override + public void onDropViewInstance(@Nonnull VirtualView view) { + super.onDropViewInstance(view); + mTagToRenderableView.remove(view.getId()); + } +} +/** ViewManager for Renderable RNSVG views */ +class RenderableViewManager extends VirtualViewManager { + + RenderableViewManager(SVGClass svgclass) { + super(svgclass); + } + + static class GroupViewManagerAbstract extends RenderableViewManager { + GroupViewManagerAbstract(SVGClass svgClass) { + super(svgClass); + } + + @ReactProp(name = "font") + public void setFont(U node, @Nullable ReadableMap font) { + node.setFont(font); + } + + @ReactProp(name = "fontSize") + public void setFontSize(U node, Dynamic fontSize) { + JavaOnlyMap map = new JavaOnlyMap(); + switch (fontSize.getType()) { + case Number: + map.putDouble("fontSize", fontSize.asDouble()); + break; + case String: + map.putString("fontSize", fontSize.asString()); + break; + default: + return; + } + node.setFont(map); + } + + public void setFontSize(U view, @Nullable String value) { + JavaOnlyMap map = new JavaOnlyMap(); + map.putString("fontSize", value); + view.setFont(map); + } + + public void setFontSize(U view, @Nullable Double value) { + JavaOnlyMap map = new JavaOnlyMap(); + map.putDouble("fontSize", value); + view.setFont(map); + } + + @ReactProp(name = "fontWeight") + public void setFontWeight(U node, Dynamic fontWeight) { + JavaOnlyMap map = new JavaOnlyMap(); + switch (fontWeight.getType()) { + case Number: + map.putDouble("fontWeight", fontWeight.asDouble()); + break; + case String: + map.putString("fontWeight", fontWeight.asString()); + break; + default: + return; + } + node.setFont(map); + } + + public void setFontWeight(U view, @Nullable String value) { + JavaOnlyMap map = new JavaOnlyMap(); + map.putString("fontWeight", value); + view.setFont(map); + } + + public void setFontWeight(U view, @Nullable Double value) { + JavaOnlyMap map = new JavaOnlyMap(); + map.putDouble("fontWeight", value); + view.setFont(map); + } + } + + static class GroupViewManager extends GroupViewManagerAbstract + implements RNSVGGroupManagerInterface { + GroupViewManager() { + super(SVGClass.RNSVGGroup); + mDelegate = new RNSVGGroupManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGGroup"; + } + + static class PathViewManager extends RenderableViewManager + implements RNSVGPathManagerInterface { + PathViewManager() { + super(SVGClass.RNSVGPath); + mDelegate = new RNSVGPathManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGPath"; + + @ReactProp(name = "d") + public void setD(PathView node, String d) { + node.setD(d); + } + } + + static class TextViewManagerAbstract extends GroupViewManagerAbstract { + TextViewManagerAbstract(SVGClass svgClass) { + super(svgClass); + } + + @ReactProp(name = "inlineSize") + public void setInlineSize(K node, Dynamic inlineSize) { + node.setInlineSize(inlineSize); + } + + @ReactProp(name = "textLength") + public void setTextLength(K node, Dynamic length) { + node.setTextLength(length); + } + + @ReactProp(name = "lengthAdjust") + public void setLengthAdjust(K node, @Nullable String adjustment) { + node.setLengthAdjust(adjustment); + } + + @ReactProp(name = "alignmentBaseline") + public void setMethod(K node, @Nullable String alignment) { + node.setMethod(alignment); + } + + @ReactProp(name = "baselineShift") + public void setBaselineShift(K node, Dynamic baselineShift) { + node.setBaselineShift(baselineShift); + } + + @ReactProp(name = "verticalAlign") + public void setVerticalAlign(K node, @Nullable String verticalAlign) { + node.setVerticalAlign(verticalAlign); + } + + @ReactProp(name = "rotate") + public void setRotate(K node, Dynamic rotate) { + node.setRotate(rotate); + } + + @ReactProp(name = "dx") + public void setDeltaX(K node, Dynamic deltaX) { + node.setDeltaX(deltaX); + } + + @ReactProp(name = "dy") + public void setDeltaY(K node, Dynamic deltaY) { + node.setDeltaY(deltaY); + } + + @ReactProp(name = "x") + public void setX(K node, Dynamic positionX) { + node.setPositionX(positionX); + } + + @ReactProp(name = "y") + public void setY(K node, Dynamic positionY) { + node.setPositionY(positionY); + } + + @ReactProp(name = "font") + public void setFont(K node, @Nullable ReadableMap font) { + node.setFont(font); + } + + public void setAlignmentBaseline(K view, @Nullable String value) { + view.setMethod(value); + } + + public void setDx(K view, @Nullable ReadableArray value) { + view.setDeltaX(value); + } + + public void setDy(K view, @Nullable ReadableArray value) { + view.setDeltaY(value); + } + + public void setX(K view, @Nullable ReadableArray value) { + view.setPositionX(value); + } + + public void setY(K view, @Nullable ReadableArray value) { + view.setPositionY(value); + } + + public void setRotate(K view, @Nullable ReadableArray value) { + view.setRotate(value); + } + + public void setInlineSize(K view, @Nullable String value) { + view.setInlineSize(value); + } + + public void setTextLength(K view, @Nullable String value) { + view.setTextLength(value); + } + + public void setBaselineShift(K view, @Nullable String value) { + view.setBaselineShift(value); + } + + public void setInlineSize(K view, @Nullable Double value) { + view.setInlineSize(value); + } + + public void setTextLength(K view, @Nullable Double value) { + view.setTextLength(value); + } + + public void setBaselineShift(K view, @Nullable Double value) { + view.setBaselineShift(value); + } + } + + static class TextViewManager extends TextViewManagerAbstract + implements RNSVGTextManagerInterface { + TextViewManager() { + super(SVGClass.RNSVGText); + mDelegate = new RNSVGTextManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGText"; + + TextViewManager(SVGClass svgClass) { + super(svgClass); + mDelegate = new RNSVGTextManagerDelegate(this); + } + } + + static class TSpanViewManager extends TextViewManagerAbstract + implements RNSVGTSpanManagerInterface { + TSpanViewManager() { + super(SVGClass.RNSVGTSpan); + mDelegate = new RNSVGTSpanManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGTSpan"; + + TSpanViewManager(SVGClass svgClass) { + super(svgClass); + mDelegate = new RNSVGTSpanManagerDelegate(this); + } + + @ReactProp(name = "content") + public void setContent(TSpanView node, @Nullable String content) { + node.setContent(content); + } + } + + static class TextPathViewManager extends TextViewManagerAbstract + implements RNSVGTextPathManagerInterface { + TextPathViewManager() { + super(SVGClass.RNSVGTextPath); + mDelegate = new RNSVGTextPathManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGTextPath"; + + TextPathViewManager(SVGClass svgClass) { + super(svgClass); + mDelegate = new RNSVGTextPathManagerDelegate(this); + } + + @ReactProp(name = "href") + public void setHref(TextPathView node, String href) { + node.setHref(href); + } + + @ReactProp(name = "startOffset") + public void setStartOffset(TextPathView node, Dynamic startOffset) { + node.setStartOffset(startOffset); + } + + @ReactProp(name = "method") + public void setMethod(TextPathView node, @Nullable String method) { + node.setMethod(method); + } + + @Override + public void setMidLine(TextPathView view, @Nullable String value) { + view.setSharp(value); + } + + @ReactProp(name = "spacing") + public void setSpacing(TextPathView node, @Nullable String spacing) { + node.setSpacing(spacing); + } + + @Override + public void setStartOffset(TextPathView view, @Nullable String value) { + view.setStartOffset(value); + } + + public void setStartOffset(TextPathView view, @Nullable Double value) { + view.setStartOffset(value); + } + + @ReactProp(name = "side") + public void setSide(TextPathView node, @Nullable String side) { + node.setSide(side); + } + + @ReactProp(name = "midLine") + public void setSharp(TextPathView node, @Nullable String midLine) { + node.setSharp(midLine); + } + } + + static class ImageViewManager extends RenderableViewManager + implements RNSVGImageManagerInterface { + ImageViewManager() { + super(SVGClass.RNSVGImage); + mDelegate = new RNSVGImageManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGImage"; + + @ReactProp(name = "x") + public void setX(ImageView node, Dynamic x) { + node.setX(x); + } + + @ReactProp(name = "y") + public void setY(ImageView node, Dynamic y) { + node.setY(y); + } + + @ReactProp(name = "width") + public void setWidth(ImageView node, Dynamic width) { + node.setWidth(width); + } + + @ReactProp(name = "height") + public void setHeight(ImageView node, Dynamic height) { + node.setHeight(height); + } + + @Override + public void setX(ImageView view, @Nullable String value) { + view.setX(value); + } + + @Override + public void setY(ImageView view, @Nullable String value) { + view.setY(value); + } + + @Override + public void setWidth(ImageView view, @Nullable String value) { + view.setWidth(value); + } + + @Override + public void setHeight(ImageView view, @Nullable String value) { + view.setHeight(value); + } + + public void setX(ImageView view, @Nullable Double value) { + view.setX(value); + } + + public void setY(ImageView view, @Nullable Double value) { + view.setY(value); + } + + public void setWidth(ImageView view, @Nullable Double value) { + view.setWidth(value); + } + + public void setHeight(ImageView view, @Nullable Double value) { + view.setHeight(value); + } + + @ReactProp(name = "src", customType = "ImageSource") + public void setSrc(ImageView node, @Nullable ReadableMap src) { + node.setSrc(src); + } + + @ReactProp(name = "align") + public void setAlign(ImageView node, String align) { + node.setAlign(align); + } + + @ReactProp(name = "meetOrSlice") + public void setMeetOrSlice(ImageView node, int meetOrSlice) { + node.setMeetOrSlice(meetOrSlice); + } + } + + static class CircleViewManager extends RenderableViewManager + implements RNSVGCircleManagerInterface { + CircleViewManager() { + super(SVGClass.RNSVGCircle); + mDelegate = new RNSVGCircleManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGCircle"; + + @ReactProp(name = "cx") + public void setCx(CircleView node, Dynamic cx) { + node.setCx(cx); + } + + @ReactProp(name = "cy") + public void setCy(CircleView node, Dynamic cy) { + node.setCy(cy); + } + + @ReactProp(name = "r") + public void setR(CircleView node, Dynamic r) { + node.setR(r); + } + + @Override + public void setCx(CircleView view, String value) { + view.setCx(value); + } + + public void setCx(CircleView view, Double value) { + view.setCx(value); + } + + @Override + public void setCy(CircleView view, String value) { + view.setCy(value); + } + + public void setCy(CircleView view, Double value) { + view.setCy(value); + } + + @Override + public void setR(CircleView view, String value) { + view.setR(value); + } + + public void setR(CircleView view, Double value) { + view.setR(value); + } + } + + static class EllipseViewManager extends RenderableViewManager + implements RNSVGEllipseManagerInterface { + EllipseViewManager() { + super(SVGClass.RNSVGEllipse); + mDelegate = new RNSVGEllipseManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGEllipse"; + + @ReactProp(name = "cx") + public void setCx(EllipseView node, Dynamic cx) { + node.setCx(cx); + } + + @ReactProp(name = "cy") + public void setCy(EllipseView node, Dynamic cy) { + node.setCy(cy); + } + + @ReactProp(name = "rx") + public void setRx(EllipseView node, Dynamic rx) { + node.setRx(rx); + } + + @ReactProp(name = "ry") + public void setRy(EllipseView node, Dynamic ry) { + node.setRy(ry); + } + + @Override + public void setCx(EllipseView view, @Nullable String value) { + view.setCx(value); + } + + @Override + public void setCy(EllipseView view, @Nullable String value) { + view.setCy(value); + } + + @Override + public void setRx(EllipseView view, @Nullable String value) { + view.setRx(value); + } + + @Override + public void setRy(EllipseView view, @Nullable String value) { + view.setRy(value); + } + + public void setCx(EllipseView view, @Nullable Double value) { + view.setCx(value); + } + + public void setCy(EllipseView view, @Nullable Double value) { + view.setCy(value); + } + + public void setRx(EllipseView view, @Nullable Double value) { + view.setRx(value); + } + + public void setRy(EllipseView view, @Nullable Double value) { + view.setRy(value); + } + } + + static class LineViewManager extends RenderableViewManager + implements RNSVGLineManagerInterface { + + LineViewManager() { + super(SVGClass.RNSVGLine); + mDelegate = new RNSVGLineManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGLine"; + + @ReactProp(name = "x1") + public void setX1(LineView node, Dynamic x1) { + node.setX1(x1); + } + + @ReactProp(name = "y1") + public void setY1(LineView node, Dynamic y1) { + node.setY1(y1); + } + + @ReactProp(name = "x2") + public void setX2(LineView node, Dynamic x2) { + node.setX2(x2); + } + + @ReactProp(name = "y2") + public void setY2(LineView node, Dynamic y2) { + node.setY2(y2); + } + + @Override + public void setX1(LineView view, @Nullable String value) { + view.setX1(value); + } + + @Override + public void setY1(LineView view, @Nullable String value) { + view.setY1(value); + } + + @Override + public void setX2(LineView view, @Nullable String value) { + view.setX2(value); + } + + @Override + public void setY2(LineView view, @Nullable String value) { + view.setY2(value); + } + + public void setX1(LineView view, @Nullable Double value) { + view.setX1(value); + } + + public void setY1(LineView view, @Nullable Double value) { + view.setY1(value); + } + + public void setX2(LineView view, @Nullable Double value) { + view.setX2(value); + } + + public void setY2(LineView view, @Nullable Double value) { + view.setY2(value); + } + } + + static class RectViewManager extends RenderableViewManager + implements RNSVGRectManagerInterface { + + RectViewManager() { + super(SVGClass.RNSVGRect); + mDelegate = new RNSVGRectManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGRect"; + + @ReactProp(name = "x") + public void setX(RectView node, Dynamic x) { + node.setX(x); + } + + @ReactProp(name = "y") + public void setY(RectView node, Dynamic y) { + node.setY(y); + } + + @ReactProp(name = "width") + public void setWidth(RectView node, Dynamic width) { + node.setWidth(width); + } + + @ReactProp(name = "height") + public void setHeight(RectView node, Dynamic height) { + node.setHeight(height); + } + + @ReactProp(name = "rx") + public void setRx(RectView node, Dynamic rx) { + node.setRx(rx); + } + + @ReactProp(name = "ry") + public void setRy(RectView node, Dynamic ry) { + node.setRy(ry); + } + + @Override + public void setX(RectView view, @Nullable String value) { + view.setX(value); + } + + @Override + public void setY(RectView view, @Nullable String value) { + view.setY(value); + } + + @Override + public void setHeight(RectView view, @Nullable String value) { + view.setHeight(value); + } + + @Override + public void setWidth(RectView view, @Nullable String value) { + view.setWidth(value); + } + + @Override + public void setRx(RectView view, @Nullable String value) { + view.setRx(value); + } + + @Override + public void setRy(RectView view, @Nullable String value) { + view.setRy(value); + } + + public void setX(RectView view, @Nullable Double value) { + view.setX(value); + } + + public void setY(RectView view, @Nullable Double value) { + view.setY(value); + } + + public void setHeight(RectView view, @Nullable Double value) { + view.setHeight(value); + } + + public void setWidth(RectView view, @Nullable Double value) { + view.setWidth(value); + } + + public void setRx(RectView view, @Nullable Double value) { + view.setRx(value); + } + + public void setRy(RectView view, @Nullable Double value) { + view.setRy(value); + } + } + + static class ClipPathViewManager extends GroupViewManagerAbstract + implements RNSVGClipPathManagerInterface { + ClipPathViewManager() { + super(SVGClass.RNSVGClipPath); + mDelegate = new RNSVGClipPathManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGClipPath"; + } + + static class DefsViewManager extends VirtualViewManager + implements RNSVGDefsManagerInterface { + + DefsViewManager() { + super(SVGClass.RNSVGDefs); + mDelegate = new RNSVGDefsManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGDefs"; + } + + static class UseViewManager extends RenderableViewManager + implements RNSVGUseManagerInterface { + + UseViewManager() { + super(SVGClass.RNSVGUse); + mDelegate = new RNSVGUseManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGUse"; + + @ReactProp(name = "href") + public void setHref(UseView node, String href) { + node.setHref(href); + } + + @Override + public void setX(UseView view, @Nullable String value) { + view.setX(value); + } + + @Override + public void setY(UseView view, @Nullable String value) { + view.setY(value); + } + + @Override + public void setHeight(UseView view, @Nullable String value) { + view.setHeight(value); + } + + public void setWidth(UseView view, @Nullable Double value) { + view.setWidth(value); + } + + public void setX(UseView view, @Nullable Double value) { + view.setX(value); + } + + public void setY(UseView view, @Nullable Double value) { + view.setY(value); + } + + public void setHeight(UseView view, @Nullable Double value) { + view.setHeight(value); + } + + @Override + public void setWidth(UseView view, @Nullable String value) { + view.setWidth(value); + } + + @ReactProp(name = "x") + public void setX(UseView node, Dynamic x) { + node.setX(x); + } + + @ReactProp(name = "y") + public void setY(UseView node, Dynamic y) { + node.setY(y); + } + + @ReactProp(name = "width") + public void setWidth(UseView node, Dynamic width) { + node.setWidth(width); + } + + @ReactProp(name = "height") + public void setHeight(UseView node, Dynamic height) { + node.setHeight(height); + } + } + + static class SymbolManager extends GroupViewManagerAbstract + implements RNSVGSymbolManagerInterface { + SymbolManager() { + super(SVGClass.RNSVGSymbol); + mDelegate = new RNSVGSymbolManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGSymbol"; + + @ReactProp(name = "minX") + public void setMinX(SymbolView node, float minX) { + node.setMinX(minX); + } + + @ReactProp(name = "minY") + public void setMinY(SymbolView node, float minY) { + node.setMinY(minY); + } + + @ReactProp(name = "vbWidth") + public void setVbWidth(SymbolView node, float vbWidth) { + node.setVbWidth(vbWidth); + } + + @ReactProp(name = "vbHeight") + public void setVbHeight(SymbolView node, float vbHeight) { + node.setVbHeight(vbHeight); + } + + @ReactProp(name = "align") + public void setAlign(SymbolView node, String align) { + node.setAlign(align); + } + + @ReactProp(name = "meetOrSlice") + public void setMeetOrSlice(SymbolView node, int meetOrSlice) { + node.setMeetOrSlice(meetOrSlice); + } + } + + static class PatternManager extends GroupViewManagerAbstract + implements RNSVGPatternManagerInterface { + PatternManager() { + super(SVGClass.RNSVGPattern); + mDelegate = new RNSVGPatternManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGPattern"; + + @ReactProp(name = "x") + public void setX(PatternView node, Dynamic x) { + node.setX(x); + } + + @ReactProp(name = "y") + public void setY(PatternView node, Dynamic y) { + node.setY(y); + } + + @ReactProp(name = "width") + public void setWidth(PatternView node, Dynamic width) { + node.setWidth(width); + } + + @ReactProp(name = "height") + public void setHeight(PatternView node, Dynamic height) { + node.setHeight(height); + } + + @Override + public void setX(PatternView view, @Nullable String value) { + view.setX(value); + } + + @Override + public void setY(PatternView view, @Nullable String value) { + view.setY(value); + } + + @Override + public void setHeight(PatternView view, @Nullable String value) { + view.setHeight(value); + } + + @Override + public void setWidth(PatternView view, @Nullable String value) { + view.setWidth(value); + } + + public void setX(PatternView view, @Nullable Double value) { + view.setX(value); + } + + public void setY(PatternView view, @Nullable Double value) { + view.setY(value); + } + + public void setHeight(PatternView view, @Nullable Double value) { + view.setHeight(value); + } + + public void setWidth(PatternView view, @Nullable Double value) { + view.setWidth(value); + } + + @ReactProp(name = "patternUnits") + public void setPatternUnits(PatternView node, int patternUnits) { + node.setPatternUnits(patternUnits); + } + + @ReactProp(name = "patternContentUnits") + public void setPatternContentUnits(PatternView node, int patternContentUnits) { + node.setPatternContentUnits(patternContentUnits); + } + + @ReactProp(name = "patternTransform") + public void setPatternTransform(PatternView node, @Nullable ReadableArray matrixArray) { + node.setPatternTransform(matrixArray); + } + + @ReactProp(name = "minX") + public void setMinX(PatternView node, float minX) { + node.setMinX(minX); + } + + @ReactProp(name = "minY") + public void setMinY(PatternView node, float minY) { + node.setMinY(minY); + } + + @ReactProp(name = "vbWidth") + public void setVbWidth(PatternView node, float vbWidth) { + node.setVbWidth(vbWidth); + } + + @ReactProp(name = "vbHeight") + public void setVbHeight(PatternView node, float vbHeight) { + node.setVbHeight(vbHeight); + } + + @ReactProp(name = "align") + public void setAlign(PatternView node, String align) { + node.setAlign(align); + } + + @ReactProp(name = "meetOrSlice") + public void setMeetOrSlice(PatternView node, int meetOrSlice) { + node.setMeetOrSlice(meetOrSlice); + } + } + + static class MaskManager extends GroupViewManagerAbstract + implements RNSVGMaskManagerInterface { + MaskManager() { + super(SVGClass.RNSVGMask); + mDelegate = new RNSVGMaskManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGMask"; + + @ReactProp(name = "x") + public void setX(MaskView node, Dynamic x) { + node.setX(x); + } + + @ReactProp(name = "y") + public void setY(MaskView node, Dynamic y) { + node.setY(y); + } + + @ReactProp(name = "width") + public void setWidth(MaskView node, Dynamic width) { + node.setWidth(width); + } + + @ReactProp(name = "height") + public void setHeight(MaskView node, Dynamic height) { + node.setHeight(height); + } + + @Override + public void setX(MaskView view, @Nullable String value) { + view.setX(value); + } + + @Override + public void setY(MaskView view, @Nullable String value) { + view.setY(value); + } + + @Override + public void setHeight(MaskView view, @Nullable String value) { + view.setHeight(value); + } + + @Override + public void setWidth(MaskView view, @Nullable String value) { + view.setWidth(value); + } + + public void setX(MaskView view, @Nullable Double value) { + view.setX(value); + } + + public void setY(MaskView view, @Nullable Double value) { + view.setY(value); + } + + public void setHeight(MaskView view, @Nullable Double value) { + view.setHeight(value); + } + + public void setWidth(MaskView view, @Nullable Double value) { + view.setWidth(value); + } + + @ReactProp(name = "maskUnits") + public void setMaskUnits(MaskView node, int maskUnits) { + node.setMaskUnits(maskUnits); + } + + @ReactProp(name = "maskContentUnits") + public void setMaskContentUnits(MaskView node, int maskContentUnits) { + node.setMaskContentUnits(maskContentUnits); + } + } + + static class ForeignObjectManager extends GroupViewManagerAbstract + implements RNSVGForeignObjectManagerInterface { + ForeignObjectManager() { + super(SVGClass.RNSVGForeignObject); + mDelegate = new RNSVGForeignObjectManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGForeignObject"; + + @ReactProp(name = "x") + public void setX(ForeignObjectView node, Dynamic x) { + node.setX(x); + } + + @ReactProp(name = "y") + public void setY(ForeignObjectView node, Dynamic y) { + node.setY(y); + } + + @ReactProp(name = "width") + public void setWidth(ForeignObjectView node, Dynamic width) { + node.setWidth(width); + } + + @ReactProp(name = "height") + public void setHeight(ForeignObjectView node, Dynamic height) { + node.setHeight(height); + } + + @Override + public void setX(ForeignObjectView view, @Nullable String value) { + view.setX(value); + } + + @Override + public void setY(ForeignObjectView view, @Nullable String value) { + view.setY(value); + } + + @Override + public void setHeight(ForeignObjectView view, @Nullable String value) { + view.setHeight(value); + } + + @Override + public void setWidth(ForeignObjectView view, @Nullable String value) { + view.setWidth(value); + } + + public void setX(ForeignObjectView view, @Nullable Double value) { + view.setX(value); + } + + public void setY(ForeignObjectView view, @Nullable Double value) { + view.setY(value); + } + + public void setHeight(ForeignObjectView view, @Nullable Double value) { + view.setHeight(value); + } + + public void setWidth(ForeignObjectView view, @Nullable Double value) { + view.setWidth(value); + } + } + + static class MarkerManager extends GroupViewManagerAbstract + implements RNSVGMarkerManagerInterface { + MarkerManager() { + super(SVGClass.RNSVGMarker); + mDelegate = new RNSVGMarkerManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGMarker"; + + @ReactProp(name = "refX") + public void setRefX(MarkerView node, Dynamic refX) { + node.setRefX(refX); + } + + @ReactProp(name = "refY") + public void setRefY(MarkerView node, Dynamic refY) { + node.setRefY(refY); + } + + @ReactProp(name = "markerWidth") + public void setMarkerWidth(MarkerView node, Dynamic markerWidth) { + node.setMarkerWidth(markerWidth); + } + + @ReactProp(name = "markerHeight") + public void setMarkerHeight(MarkerView node, Dynamic markerHeight) { + node.setMarkerHeight(markerHeight); + } + + @Override + public void setRefX(MarkerView view, @Nullable String value) { + view.setRefX(value); + } + + @Override + public void setRefY(MarkerView view, @Nullable String value) { + view.setRefY(value); + } + + @Override + public void setMarkerHeight(MarkerView view, @Nullable String value) { + view.setMarkerHeight(value); + } + + @Override + public void setMarkerWidth(MarkerView view, @Nullable String value) { + view.setMarkerWidth(value); + } + + public void setRefX(MarkerView view, @Nullable Double value) { + view.setRefX(value); + } + + public void setRefY(MarkerView view, @Nullable Double value) { + view.setRefY(value); + } + + public void setMarkerHeight(MarkerView view, @Nullable Double value) { + view.setMarkerHeight(value); + } + + public void setMarkerWidth(MarkerView view, @Nullable Double value) { + view.setMarkerWidth(value); + } + + @ReactProp(name = "markerUnits") + public void setMarkerUnits(MarkerView node, String markerUnits) { + node.setMarkerUnits(markerUnits); + } + + @ReactProp(name = "orient") + public void setOrient(MarkerView node, String orient) { + node.setOrient(orient); + } + + @ReactProp(name = "minX") + public void setMinX(MarkerView node, float minX) { + node.setMinX(minX); + } + + @ReactProp(name = "minY") + public void setMinY(MarkerView node, float minY) { + node.setMinY(minY); + } + + @ReactProp(name = "vbWidth") + public void setVbWidth(MarkerView node, float vbWidth) { + node.setVbWidth(vbWidth); + } + + @ReactProp(name = "vbHeight") + public void setVbHeight(MarkerView node, float vbHeight) { + node.setVbHeight(vbHeight); + } + + @ReactProp(name = "align") + public void setAlign(MarkerView node, String align) { + node.setAlign(align); + } + + @ReactProp(name = "meetOrSlice") + public void setMeetOrSlice(MarkerView node, int meetOrSlice) { + node.setMeetOrSlice(meetOrSlice); + } + } + + static class LinearGradientManager extends VirtualViewManager + implements RNSVGLinearGradientManagerInterface { + + LinearGradientManager() { + super(SVGClass.RNSVGLinearGradient); + mDelegate = new RNSVGLinearGradientManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGLinearGradient"; + + @ReactProp(name = "x1") + public void setX1(LinearGradientView node, Dynamic x1) { + node.setX1(x1); + } + + @ReactProp(name = "y1") + public void setY1(LinearGradientView node, Dynamic y1) { + node.setY1(y1); + } + + @ReactProp(name = "x2") + public void setX2(LinearGradientView node, Dynamic x2) { + node.setX2(x2); + } + + @ReactProp(name = "y2") + public void setY2(LinearGradientView node, Dynamic y2) { + node.setY2(y2); + } + + @Override + public void setX1(LinearGradientView view, @Nullable String value) { + view.setX1(value); + } + + @Override + public void setY1(LinearGradientView view, @Nullable String value) { + view.setY1(value); + } + + @Override + public void setX2(LinearGradientView view, @Nullable String value) { + view.setX2(value); + } + + @Override + public void setY2(LinearGradientView view, @Nullable String value) { + view.setY2(value); + } + + public void setX1(LinearGradientView view, @Nullable Double value) { + view.setX1(value); + } + + public void setY1(LinearGradientView view, @Nullable Double value) { + view.setY1(value); + } + + public void setX2(LinearGradientView view, @Nullable Double value) { + view.setX2(value); + } + + public void setY2(LinearGradientView view, @Nullable Double value) { + view.setY2(value); + } + + @ReactProp(name = "gradient") + public void setGradient(LinearGradientView node, ReadableArray gradient) { + node.setGradient(gradient); + } + + @ReactProp(name = "gradientUnits") + public void setGradientUnits(LinearGradientView node, int gradientUnits) { + node.setGradientUnits(gradientUnits); + } + + @ReactProp(name = "gradientTransform") + public void setGradientTransform(LinearGradientView node, @Nullable ReadableArray matrixArray) { + node.setGradientTransform(matrixArray); + } + } + + static class RadialGradientManager extends VirtualViewManager + implements RNSVGRadialGradientManagerInterface { + + RadialGradientManager() { + super(SVGClass.RNSVGRadialGradient); + mDelegate = new RNSVGRadialGradientManagerDelegate(this); + } + + public static final String REACT_CLASS = "RNSVGRadialGradient"; + + @ReactProp(name = "fx") + public void setFx(RadialGradientView node, Dynamic fx) { + node.setFx(fx); + } + + @ReactProp(name = "fy") + public void setFy(RadialGradientView node, Dynamic fy) { + node.setFy(fy); + } + + @ReactProp(name = "rx") + public void setRx(RadialGradientView node, Dynamic rx) { + node.setRx(rx); + } + + @ReactProp(name = "ry") + public void setRy(RadialGradientView node, Dynamic ry) { + node.setRy(ry); + } + + @ReactProp(name = "cx") + public void setCx(RadialGradientView node, Dynamic cx) { + node.setCx(cx); + } + + @ReactProp(name = "cy") + public void setCy(RadialGradientView node, Dynamic cy) { + node.setCy(cy); + } + + @Override + public void setFx(RadialGradientView view, @Nullable String value) { + view.setFx(value); + } + + @Override + public void setFy(RadialGradientView view, @Nullable String value) { + view.setFy(value); + } + + @Override + public void setCx(RadialGradientView view, @Nullable String value) { + view.setCx(value); + } + + @Override + public void setCy(RadialGradientView view, @Nullable String value) { + view.setCy(value); + } + + @Override + public void setRx(RadialGradientView view, @Nullable String value) { + view.setRx(value); + } + + @Override + public void setRy(RadialGradientView view, @Nullable String value) { + view.setRy(value); + } + + public void setFx(RadialGradientView view, @Nullable Double value) { + view.setFx(value); + } + + public void setFy(RadialGradientView view, @Nullable Double value) { + view.setFy(value); + } + + public void setCx(RadialGradientView view, @Nullable Double value) { + view.setCx(value); + } + + public void setCy(RadialGradientView view, @Nullable Double value) { + view.setCy(value); + } + + public void setRx(RadialGradientView view, @Nullable Double value) { + view.setRx(value); + } + + public void setRy(RadialGradientView view, @Nullable Double value) { + view.setRy(value); + } + + @ReactProp(name = "gradient") + public void setGradient(RadialGradientView node, ReadableArray gradient) { + node.setGradient(gradient); + } + + @ReactProp(name = "gradientUnits") + public void setGradientUnits(RadialGradientView node, int gradientUnits) { + node.setGradientUnits(gradientUnits); + } + + @ReactProp(name = "gradientTransform") + public void setGradientTransform(RadialGradientView node, @Nullable ReadableArray matrixArray) { + node.setGradientTransform(matrixArray); + } + } + + @ReactProp(name = "fill") + public void setFill(T node, @Nullable Dynamic fill) { + node.setFill(fill); + } + + public void setFill(T view, @Nullable ReadableMap value) { + view.setFill(value); + } + + @ReactProp(name = "fillOpacity", defaultFloat = 1f) + public void setFillOpacity(T node, float fillOpacity) { + node.setFillOpacity(fillOpacity); + } + + @ReactProp(name = "fillRule", defaultInt = FILL_RULE_NONZERO) + public void setFillRule(T node, int fillRule) { + node.setFillRule(fillRule); + } + + @ReactProp(name = "stroke") + public void setStroke(T node, @Nullable Dynamic strokeColors) { + node.setStroke(strokeColors); + } + + public void setStroke(T view, @Nullable ReadableMap value) { + view.setStroke(value); + } + + @ReactProp(name = "strokeOpacity", defaultFloat = 1f) + public void setStrokeOpacity(T node, float strokeOpacity) { + node.setStrokeOpacity(strokeOpacity); + } + + @ReactProp(name = "strokeDasharray") + public void setStrokeDasharray(T node, @Nullable ReadableArray strokeDasharray) { + node.setStrokeDasharray(strokeDasharray); + } + + @ReactProp(name = "strokeDashoffset") + public void setStrokeDashoffset(T node, float strokeDashoffset) { + node.setStrokeDashoffset(strokeDashoffset); + } + + @ReactProp(name = "strokeWidth") + public void setStrokeWidth(T node, Dynamic strokeWidth) { + node.setStrokeWidth(strokeWidth); + } + + public void setStrokeWidth(T view, @Nullable String value) { + view.setStrokeWidth(value); + } + + public void setStrokeWidth(T view, @Nullable Double value) { + view.setStrokeWidth(value); + } + + @ReactProp(name = "strokeMiterlimit", defaultFloat = 4f) + public void setStrokeMiterlimit(T node, float strokeMiterlimit) { + node.setStrokeMiterlimit(strokeMiterlimit); + } + + @ReactProp(name = "strokeLinecap", defaultInt = CAP_ROUND) + public void setStrokeLinecap(T node, int strokeLinecap) { + node.setStrokeLinecap(strokeLinecap); + } + + @ReactProp(name = "strokeLinejoin", defaultInt = JOIN_ROUND) + public void setStrokeLinejoin(T node, int strokeLinejoin) { + node.setStrokeLinejoin(strokeLinejoin); + } + + @ReactProp(name = "vectorEffect") + public void setVectorEffect(T node, int vectorEffect) { + node.setVectorEffect(vectorEffect); + } + + @ReactProp(name = "propList") + public void setPropList(T node, @Nullable ReadableArray propList) { + node.setPropList(propList); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SVGLength.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SVGLength.java new file mode 100644 index 00000000000000..e9086e087be596 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SVGLength.java @@ -0,0 +1,164 @@ +package abi49_0_0.com.horcrux.svg; + +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import java.util.ArrayList; + +class SVGLength { + // https://www.w3.org/TR/SVG/types.html#InterfaceSVGLength + public enum UnitType { + UNKNOWN, + NUMBER, + PERCENTAGE, + EMS, + EXS, + PX, + CM, + MM, + IN, + PT, + PC, + } + + final double value; + final UnitType unit; + + private SVGLength() { + value = 0; + unit = UnitType.UNKNOWN; + } + + SVGLength(double number) { + value = number; + unit = UnitType.NUMBER; + } + + private SVGLength(String length) { + length = length.trim(); + int stringLength = length.length(); + int percentIndex = stringLength - 1; + if (stringLength == 0 || length.equals("normal")) { + unit = UnitType.UNKNOWN; + value = 0; + } else if (length.codePointAt(percentIndex) == '%') { + unit = UnitType.PERCENTAGE; + value = Double.valueOf(length.substring(0, percentIndex)); + } else { + int twoLetterUnitIndex = stringLength - 2; + if (twoLetterUnitIndex > 0) { + String lastTwo = length.substring(twoLetterUnitIndex); + int end = twoLetterUnitIndex; + switch (lastTwo) { + case "px": + unit = UnitType.NUMBER; + break; + + case "em": + unit = UnitType.EMS; + break; + case "ex": + unit = UnitType.EXS; + break; + + case "pt": + unit = UnitType.PT; + break; + + case "pc": + unit = UnitType.PC; + break; + + case "mm": + unit = UnitType.MM; + break; + + case "cm": + unit = UnitType.CM; + break; + + case "in": + unit = UnitType.IN; + break; + + default: + unit = UnitType.NUMBER; + end = stringLength; + } + value = Double.valueOf(length.substring(0, end)); + } else { + unit = UnitType.NUMBER; + value = Double.valueOf(length); + } + } + } + + static SVGLength from(Dynamic dynamic) { + switch (dynamic.getType()) { + case Number: + return new SVGLength(dynamic.asDouble()); + case String: + return new SVGLength(dynamic.asString()); + default: + return new SVGLength(); + } + } + + static SVGLength from(String string) { + return string != null ? new SVGLength(string) : new SVGLength(); + } + + static SVGLength from(Double value) { + return value != null ? new SVGLength(value) : new SVGLength(); + } + + static String toString(Dynamic dynamic) { + switch (dynamic.getType()) { + case Number: + return String.valueOf(dynamic.asDouble()); + case String: + return dynamic.asString(); + default: + return null; + } + } + + static ArrayList arrayFrom(Dynamic dynamic) { + switch (dynamic.getType()) { + case Number: + { + ArrayList list = new ArrayList<>(1); + list.add(new SVGLength(dynamic.asDouble())); + return list; + } + case Array: + { + ReadableArray arr = dynamic.asArray(); + int size = arr.size(); + ArrayList list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + Dynamic val = arr.getDynamic(i); + list.add(from(val)); + } + return list; + } + case String: + { + ArrayList list = new ArrayList<>(1); + list.add(new SVGLength(dynamic.asString())); + return list; + } + default: + return null; + } + } + + static ArrayList arrayFrom(ReadableArray arr) { + int size = arr.size(); + ArrayList list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + Dynamic val = arr.getDynamic(i); + list.add(from(val)); + } + return list; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgPackage.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgPackage.java new file mode 100644 index 00000000000000..8d1c8612cb83f6 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgPackage.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.horcrux.svg.RenderableViewManager.*; + +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.TurboReactPackage; +import abi49_0_0.com.facebook.react.ViewManagerOnDemandReactPackage; +import abi49_0_0.com.facebook.react.bridge.JavaScriptModule; +import abi49_0_0.com.facebook.react.bridge.ModuleSpec; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.common.MapBuilder; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.facebook.react.module.annotations.ReactModuleList; +import abi49_0_0.com.facebook.react.module.model.ReactModuleInfo; +import abi49_0_0.com.facebook.react.module.model.ReactModuleInfoProvider; +import abi49_0_0.com.facebook.react.turbomodule.core.interfaces.TurboModule; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.inject.Provider; + +@ReactModuleList( + nativeModules = { + SvgViewModule.class, + RNSVGRenderableManager.class, + }) +public class SvgPackage extends TurboReactPackage implements ViewManagerOnDemandReactPackage { + + private @Nullable Map mViewManagers; + + private Map getViewManagersMap(final ReactApplicationContext reactContext) { + if (mViewManagers == null) { + Map specs = MapBuilder.newHashMap(); + specs.put( + GroupViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new GroupViewManager(); + } + })); + specs.put( + PathViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new PathViewManager(); + } + })); + specs.put( + CircleViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new CircleViewManager(); + } + })); + specs.put( + EllipseViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new EllipseViewManager(); + } + })); + specs.put( + LineViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new LineViewManager(); + } + })); + specs.put( + RectViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new RectViewManager(); + } + })); + specs.put( + TextViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new TextViewManager(); + } + })); + specs.put( + TSpanViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new TSpanViewManager(); + } + })); + specs.put( + TextPathViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new TextPathViewManager(); + } + })); + specs.put( + ImageViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new ImageViewManager(); + } + })); + specs.put( + ClipPathViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new ClipPathViewManager(); + } + })); + specs.put( + DefsViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new DefsViewManager(); + } + })); + specs.put( + UseViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new UseViewManager(); + } + })); + specs.put( + SymbolManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new SymbolManager(); + } + })); + specs.put( + LinearGradientManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new LinearGradientManager(); + } + })); + specs.put( + RadialGradientManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new RadialGradientManager(); + } + })); + specs.put( + PatternManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new PatternManager(); + } + })); + specs.put( + MaskManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new MaskManager(); + } + })); + specs.put( + ForeignObjectManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new ForeignObjectManager(); + } + })); + specs.put( + MarkerManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new MarkerManager(); + } + })); + specs.put( + SvgViewManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new SvgViewManager(); + } + })); + mViewManagers = specs; + } + return mViewManagers; + } + + /** {@inheritDoc} */ + @Override + public List getViewManagerNames(ReactApplicationContext reactContext) { + return (List) getViewManagersMap(reactContext).keySet(); + } + + @Override + protected List getViewManagers(ReactApplicationContext reactContext) { + return new ArrayList<>(getViewManagersMap(reactContext).values()); + } + + /** {@inheritDoc} */ + @Override + public @Nullable ViewManager createViewManager( + ReactApplicationContext reactContext, String viewManagerName) { + ModuleSpec spec = getViewManagersMap(reactContext).get(viewManagerName); + return spec != null ? (ViewManager) spec.getProvider().get() : null; + } + + @Override + public NativeModule getModule(String name, @Nonnull ReactApplicationContext reactContext) { + switch (name) { + case SvgViewModule.NAME: + return new SvgViewModule(reactContext); + case RNSVGRenderableManager.NAME: + return new RNSVGRenderableManager(reactContext); + default: + return null; + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + try { + Class reactModuleInfoProviderClass = + Class.forName("com.horcrux.svg.SvgPackage$$ReactModuleInfoProvider"); + return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance(); + } catch (ClassNotFoundException e) { + // ReactModuleSpecProcessor does not run at build-time. Create this ReactModuleInfoProvider by + // hand. + return new ReactModuleInfoProvider() { + @Override + public Map getReactModuleInfos() { + final Map reactModuleInfoMap = new HashMap<>(); + + Class[] moduleList = + new Class[] { + SvgViewModule.class, RNSVGRenderableManager.class, + }; + + for (Class moduleClass : moduleList) { + ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); + + reactModuleInfoMap.put( + reactModule.name(), + new ReactModuleInfo( + reactModule.name(), + moduleClass.getName(), + reactModule.canOverrideExistingModule(), + reactModule.needsEagerInit(), + reactModule.hasConstants(), + reactModule.isCxxModule(), + TurboModule.class.isAssignableFrom(moduleClass))); + } + + return reactModuleInfoMap; + } + }; + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException( + "No ReactModuleInfoProvider for MyPackage$$ReactModuleInfoProvider", e); + } + } + + @SuppressWarnings("unused") + public List> createJSModules() { + return Collections.emptyList(); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgView.java new file mode 100644 index 00000000000000..0dc6ee67383962 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgView.java @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.util.Base64; +import android.view.View; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityNodeInfo; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.uimanager.DisplayMetricsHolder; +import abi49_0_0.com.facebook.react.uimanager.ReactCompoundView; +import abi49_0_0.com.facebook.react.uimanager.ReactCompoundViewGroup; +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup; +import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** Custom {@link View} implementation that draws an RNSVGSvg React view and its children. */ +@SuppressLint("ViewConstructor") +public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactCompoundViewGroup { + + @Override + public boolean interceptsTouchEvent(float touchX, float touchY) { + return true; + } + + @SuppressWarnings("unused") + public enum Events { + EVENT_DATA_URL("onDataURL"); + + private final String mName; + + Events(final String name) { + mName = name; + } + + @Nonnull + public String toString() { + return mName; + } + } + + private @Nullable Bitmap mBitmap; + private boolean mRemovalTransitionStarted; + + public SvgView(ReactContext reactContext) { + super(reactContext); + mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density; + // for some reason on Fabric the `onDraw` won't be called without it + setWillNotDraw(false); + } + + @Override + public void setId(int id) { + super.setId(id); + SvgViewManager.setSvgView(id, this); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + + Rect r = new Rect(); + boolean isVisible = this.getGlobalVisibleRect(r); + info.setVisibleToUser(isVisible); + info.setClassName(this.getClass().getCanonicalName()); + } + + @Override + public void invalidate() { + super.invalidate(); + ViewParent parent = getParent(); + if (parent instanceof VirtualView) { + if (!mRendered) { + return; + } + mRendered = false; + ((VirtualView) parent).getSvgView().invalidate(); + return; + } + if (!mRemovalTransitionStarted) { + // when view is removed from the view hierarchy, we want to recycle the mBitmap when + // the view is detached from window, in order to preserve it for during animation, see + // https://github.com/react-native-svg/react-native-svg/pull/1542 + if (mBitmap != null) { + mBitmap.recycle(); + } + mBitmap = null; + } + } + + @Override + public void startViewTransition(View view) { + mRemovalTransitionStarted = true; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mBitmap != null) { + mBitmap.recycle(); + } + mBitmap = null; + } + + @Override + protected void onDraw(Canvas canvas) { + if (getParent() instanceof VirtualView) { + return; + } + super.onDraw(canvas); + if (mBitmap == null) { + mBitmap = drawOutput(); + } + if (mBitmap != null) { + canvas.drawBitmap(mBitmap, 0, 0, null); + if (toDataUrlTask != null) { + toDataUrlTask.run(); + toDataUrlTask = null; + } + } + } + + private Runnable toDataUrlTask = null; + + void setToDataUrlTask(Runnable task) { + toDataUrlTask = task; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + this.invalidate(); + } + + @Override + public int reactTagForTouch(float touchX, float touchY) { + return hitTest(touchX, touchY); + } + + private boolean mResponsible = false; + + private final Map mDefinedClipPaths = new HashMap<>(); + private final Map mDefinedTemplates = new HashMap<>(); + private final Map mDefinedMarkers = new HashMap<>(); + private final Map mDefinedMasks = new HashMap<>(); + private final Map mDefinedBrushes = new HashMap<>(); + private Canvas mCanvas; + private final float mScale; + + private float mMinX; + private float mMinY; + private float mVbWidth; + private float mVbHeight; + private SVGLength mbbWidth; + private SVGLength mbbHeight; + private String mAlign; + private int mMeetOrSlice; + final Matrix mInvViewBoxMatrix = new Matrix(); + private boolean mInvertible = true; + private boolean mRendered = false; + int mTintColor = 0; + + boolean notRendered() { + return !mRendered; + } + + private void clearChildCache() { + if (!mRendered) { + return; + } + mRendered = false; + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof VirtualView) { + VirtualView n = ((VirtualView) node); + n.clearChildCache(); + } + } + } + + public void setTintColor(Integer tintColor) { + mTintColor = tintColor != null ? tintColor : 0; + invalidate(); + clearChildCache(); + } + + public void setMinX(float minX) { + mMinX = minX; + invalidate(); + clearChildCache(); + } + + public void setMinY(float minY) { + mMinY = minY; + invalidate(); + clearChildCache(); + } + + public void setVbWidth(float vbWidth) { + mVbWidth = vbWidth; + invalidate(); + clearChildCache(); + } + + public void setVbHeight(float vbHeight) { + mVbHeight = vbHeight; + invalidate(); + clearChildCache(); + } + + public void setBbWidth(Dynamic bbWidth) { + mbbWidth = SVGLength.from(bbWidth); + invalidate(); + clearChildCache(); + } + + public void setBbWidth(String bbWidth) { + mbbWidth = SVGLength.from(bbWidth); + invalidate(); + clearChildCache(); + } + + public void setBbWidth(Double bbWidth) { + mbbWidth = SVGLength.from(bbWidth); + invalidate(); + clearChildCache(); + } + + public void setBbHeight(Dynamic bbHeight) { + mbbHeight = SVGLength.from(bbHeight); + invalidate(); + clearChildCache(); + } + + public void setBbHeight(String bbHeight) { + mbbHeight = SVGLength.from(bbHeight); + invalidate(); + clearChildCache(); + } + + public void setBbHeight(Double bbHeight) { + mbbHeight = SVGLength.from(bbHeight); + invalidate(); + clearChildCache(); + } + + public void setAlign(String align) { + mAlign = align; + invalidate(); + clearChildCache(); + } + + public void setMeetOrSlice(int meetOrSlice) { + mMeetOrSlice = meetOrSlice; + invalidate(); + clearChildCache(); + } + + private Bitmap drawOutput() { + mRendered = true; + float width = getWidth(); + float height = getHeight(); + boolean invalid = + Float.isNaN(width) + || Float.isNaN(height) + || width < 1 + || height < 1 + || (Math.log10(width) + Math.log10(height) > 42); + if (invalid) { + return null; + } + Bitmap bitmap = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888); + + drawChildren(new Canvas(bitmap)); + return bitmap; + } + + Rect getCanvasBounds() { + return mCanvas.getClipBounds(); + } + + synchronized void drawChildren(final Canvas canvas) { + mRendered = true; + mCanvas = canvas; + Matrix mViewBoxMatrix = new Matrix(); + if (mAlign != null) { + RectF vbRect = getViewBox(); + float width = canvas.getWidth(); + float height = canvas.getHeight(); + boolean nested = getParent() instanceof VirtualView; + if (nested) { + width = (float) PropHelper.fromRelative(mbbWidth, width, 0f, mScale, 12); + height = (float) PropHelper.fromRelative(mbbHeight, height, 0f, mScale, 12); + } + RectF eRect = new RectF(0, 0, width, height); + if (nested) { + canvas.clipRect(eRect); + } + mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice); + mInvertible = mViewBoxMatrix.invert(mInvViewBoxMatrix); + canvas.concat(mViewBoxMatrix); + } + + final Paint paint = new Paint(); + + paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG); + + paint.setTypeface(Typeface.DEFAULT); + + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof VirtualView) { + ((VirtualView) node).saveDefinition(); + } + } + + for (int i = 0; i < getChildCount(); i++) { + View lNode = getChildAt(i); + if (lNode instanceof VirtualView) { + VirtualView node = (VirtualView) lNode; + int count = node.saveAndSetupCanvas(canvas, mViewBoxMatrix); + node.render(canvas, paint, 1f); + node.restoreCanvas(canvas, count); + + if (node.isResponsible() && !mResponsible) { + mResponsible = true; + } + } + } + } + + private RectF getViewBox() { + return new RectF( + mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); + } + + String toDataURL() { + Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); + + clearChildCache(); + drawChildren(new Canvas(bitmap)); + clearChildCache(); + this.invalidate(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); + bitmap.recycle(); + byte[] bitmapBytes = stream.toByteArray(); + return Base64.encodeToString(bitmapBytes, Base64.DEFAULT); + } + + String toDataURL(int width, int height) { + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + + clearChildCache(); + drawChildren(new Canvas(bitmap)); + clearChildCache(); + this.invalidate(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); + bitmap.recycle(); + byte[] bitmapBytes = stream.toByteArray(); + return Base64.encodeToString(bitmapBytes, Base64.DEFAULT); + } + + void enableTouchEvents() { + if (!mResponsible) { + mResponsible = true; + } + } + + boolean isResponsible() { + return mResponsible; + } + + private int hitTest(float touchX, float touchY) { + if (!mResponsible || !mInvertible) { + return getId(); + } + + float[] transformed = {touchX, touchY}; + mInvViewBoxMatrix.mapPoints(transformed); + + int count = getChildCount(); + int viewTag = -1; + for (int i = count - 1; i >= 0; i--) { + View child = getChildAt(i); + if (child instanceof VirtualView) { + viewTag = ((VirtualView) child).hitTest(transformed); + } else if (child instanceof SvgView) { + viewTag = ((SvgView) child).hitTest(touchX, touchY); + } + if (viewTag != -1) { + break; + } + } + + return viewTag == -1 ? getId() : viewTag; + } + + void defineClipPath(VirtualView clipPath, String clipPathRef) { + mDefinedClipPaths.put(clipPathRef, clipPath); + } + + VirtualView getDefinedClipPath(String clipPathRef) { + return mDefinedClipPaths.get(clipPathRef); + } + + void defineTemplate(VirtualView template, String templateRef) { + mDefinedTemplates.put(templateRef, template); + } + + VirtualView getDefinedTemplate(String templateRef) { + return mDefinedTemplates.get(templateRef); + } + + void defineBrush(Brush brush, String brushRef) { + mDefinedBrushes.put(brushRef, brush); + } + + Brush getDefinedBrush(String brushRef) { + return mDefinedBrushes.get(brushRef); + } + + void defineMask(VirtualView mask, String maskRef) { + mDefinedMasks.put(maskRef, mask); + } + + VirtualView getDefinedMask(String maskRef) { + return mDefinedMasks.get(maskRef); + } + + void defineMarker(VirtualView marker, String markerRef) { + mDefinedMarkers.put(markerRef, marker); + } + + VirtualView getDefinedMarker(String markerRef) { + return mDefinedMarkers.get(markerRef); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgViewManager.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgViewManager.java new file mode 100644 index 00000000000000..1d5b207fec6888 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgViewManager.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.graphics.Rect; +import android.util.SparseArray; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.PixelUtil; +import abi49_0_0.com.facebook.react.uimanager.PointerEvents; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import abi49_0_0.com.facebook.react.uimanager.ViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.ViewProps; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGSvgViewAndroidManagerDelegate; +import abi49_0_0.com.facebook.react.viewmanagers.RNSVGSvgViewAndroidManagerInterface; +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup; +import abi49_0_0.com.facebook.react.views.view.ReactViewManager; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Locale; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * ViewManager for RNSVGSvgView React views. Renders as a {@link SvgView} and handles invalidating + * the native view on view updates happening in the underlying tree. + */ +class SvgViewManager extends ReactViewManager + implements RNSVGSvgViewAndroidManagerInterface { + + public static final String REACT_CLASS = "RNSVGSvgViewAndroid"; + + private static final SparseArray mTagToSvgView = new SparseArray<>(); + private static final SparseArray mTagToRunnable = new SparseArray<>(); + + private final ViewManagerDelegate mDelegate; + + protected ViewManagerDelegate getDelegate() { + return mDelegate; + } + + public SvgViewManager() { + mDelegate = new RNSVGSvgViewAndroidManagerDelegate(this); + } + + static void setSvgView(int tag, SvgView svg) { + mTagToSvgView.put(tag, svg); + Runnable task = mTagToRunnable.get(tag); + if (task != null) { + task.run(); + mTagToRunnable.delete(tag); + } + } + + static void runWhenViewIsAvailable(int tag, Runnable task) { + mTagToRunnable.put(tag, task); + } + + static @Nullable SvgView getSvgViewByTag(int tag) { + return mTagToSvgView.get(tag); + } + + @Nonnull + @Override + public String getName() { + return REACT_CLASS; + } + + @Nonnull + @Override + public ReactViewGroup createViewInstance(ThemedReactContext reactContext) { + return new SvgView(reactContext); + } + + @Override + public void updateExtraData(ReactViewGroup root, Object extraData) { + super.updateExtraData(root, extraData); + root.invalidate(); + } + + @Override + public void onDropViewInstance(@Nonnull ReactViewGroup view) { + super.onDropViewInstance(view); + mTagToSvgView.remove(view.getId()); + } + + @Override + public boolean needsCustomLayoutForChildren() { + return true; + } + + @ReactProp(name = "tintColor", customType = "Color") + @Override + public void setTintColor(SvgView node, Integer tintColor) { + node.setTintColor(tintColor); + } + + @ReactProp(name = "color", customType = "Color") + @Override + public void setColor(SvgView node, Integer color) { + node.setTintColor(color); + } + + @ReactProp(name = "minX") + @Override + public void setMinX(SvgView node, float minX) { + node.setMinX(minX); + } + + @ReactProp(name = "minY") + @Override + public void setMinY(SvgView node, float minY) { + node.setMinY(minY); + } + + @ReactProp(name = "vbWidth") + @Override + public void setVbWidth(SvgView node, float vbWidth) { + node.setVbWidth(vbWidth); + } + + @ReactProp(name = "vbHeight") + @Override + public void setVbHeight(SvgView node, float vbHeight) { + node.setVbHeight(vbHeight); + } + + @ReactProp(name = "bbWidth") + public void setBbWidth(SvgView node, Dynamic bbWidth) { + node.setBbWidth(bbWidth); + } + + @ReactProp(name = "bbHeight") + public void setBbHeight(SvgView node, Dynamic bbHeight) { + node.setBbHeight(bbHeight); + } + + @ReactProp(name = "align") + @Override + public void setAlign(SvgView node, String align) { + node.setAlign(align); + } + + @ReactProp(name = "meetOrSlice") + @Override + public void setMeetOrSlice(SvgView node, int meetOrSlice) { + node.setMeetOrSlice(meetOrSlice); + } + + @Override + public void setBbWidth(SvgView view, @Nullable String value) { + view.setBbWidth(value); + } + + public void setBbWidth(SvgView view, @Nullable Double value) { + view.setBbWidth(value); + } + + @Override + public void setBbHeight(SvgView view, @Nullable String value) { + view.setBbHeight(value); + } + + public void setBbHeight(SvgView view, @Nullable Double value) { + view.setBbHeight(value); + } + + @ReactProp(name = ViewProps.POINTER_EVENTS) + public void setPointerEvents(SvgView view, @Nullable String pointerEventsStr) { + try { + Class superclass = view.getClass().getSuperclass(); + if (superclass != null) { + Method method = superclass.getDeclaredMethod("setPointerEvents", PointerEvents.class); + method.setAccessible(true); + method.invoke( + view, PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_"))); + } + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + e.printStackTrace(); + } + } + + @Override + public void setHasTVPreferredFocus(SvgView view, boolean value) { + super.setTVPreferredFocus(view, value); + } + + @Override + public void setBorderTopEndRadius(SvgView view, float value) { + super.setBorderRadius(view, 6, value); + } + + @Override + public void setBorderBottomStartRadius(SvgView view, float value) { + super.setBorderRadius(view, 7, value); + } + + @Override + public void setBorderBottomColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 4, value); + } + + @Override + public void setNextFocusDown(SvgView view, int value) { + super.nextFocusDown(view, value); + } + + @Override + public void setBorderRightColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 2, value); + } + + @Override + public void setNextFocusRight(SvgView view, int value) { + super.nextFocusRight(view, value); + } + + @Override + public void setBorderLeftColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 1, value); + } + + @Override + public void setBorderColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 0, value); + } + + @Override + public void setRemoveClippedSubviews(SvgView view, boolean value) { + super.setRemoveClippedSubviews(view, value); + } + + @Override + public void setNextFocusForward(SvgView view, int value) { + super.nextFocusForward(view, value); + } + + @Override + public void setNextFocusUp(SvgView view, int value) { + super.nextFocusUp(view, value); + } + + @Override + public void setAccessible(SvgView view, boolean value) { + super.setAccessible(view, value); + } + + @Override + public void setBorderStartColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 5, value); + } + + @Override + public void setBorderBottomEndRadius(SvgView view, float value) { + super.setBorderRadius(view, 8, value); + } + + @Override + public void setBorderEndColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 6, value); + } + + @Override + public void setFocusable(SvgView view, boolean value) { + super.setFocusable(view, value); + } + + @Override + public void setNativeBackgroundAndroid(SvgView view, @Nullable ReadableMap value) { + super.setNativeBackground(view, value); + } + + @Override + public void setBorderTopStartRadius(SvgView view, float value) { + super.setBorderRadius(view, 5, value); + } + + @Override + public void setNativeForegroundAndroid(SvgView view, @Nullable ReadableMap value) { + super.setNativeForeground(view, value); + } + + @Override + public void setBackfaceVisibility(SvgView view, @Nullable String value) { + super.setBackfaceVisibility(view, value); + } + + @Override + public void setBorderStyle(SvgView view, @Nullable String value) { + super.setBorderStyle(view, value); + } + + @Override + public void setNeedsOffscreenAlphaCompositing(SvgView view, boolean value) { + super.setNeedsOffscreenAlphaCompositing(view, value); + } + + @Override + public void setHitSlop(SvgView view, @Nullable ReadableMap hitSlopMap) { + // we don't call super here since its signature changed in RN 0.69 and we want backwards + // compatibility + if (hitSlopMap != null) { + view.setHitSlopRect( + new Rect( + hitSlopMap.hasKey("left") + ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("left")) + : 0, + hitSlopMap.hasKey("top") + ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("top")) + : 0, + hitSlopMap.hasKey("right") + ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("right")) + : 0, + hitSlopMap.hasKey("bottom") + ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("bottom")) + : 0)); + } + } + + @Override + public void setBorderTopColor(SvgView view, @Nullable Integer value) { + super.setBorderColor(view, 3, value); + } + + @Override + public void setNextFocusLeft(SvgView view, int value) { + super.nextFocusLeft(view, value); + } + + @Override + public void setBorderRadius(SvgView view, double value) { + super.setBorderRadius(view, 0, (float) value); + } + + @Override + public void setBorderTopLeftRadius(SvgView view, double value) { + super.setBorderRadius(view, 1, (float) value); + } + + @Override + public void setBorderTopRightRadius(SvgView view, double value) { + super.setBorderRadius(view, 2, (float) value); + } + + @Override + public void setBorderBottomRightRadius(SvgView view, double value) { + super.setBorderRadius(view, 3, (float) value); + } + + @Override + public void setBorderBottomLeftRadius(SvgView view, double value) { + super.setBorderRadius(view, 4, (float) value); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgViewModule.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgViewModule.java new file mode 100644 index 00000000000000..276b43eec3f31e --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SvgViewModule.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import abi49_0_0.com.facebook.react.bridge.Callback; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil; +import abi49_0_0.com.facebook.react.module.annotations.ReactModule; +import abi49_0_0.com.horcrux.rnsvg.NativeSvgViewModuleSpec; +import javax.annotation.Nonnull; + +@ReactModule(name = SvgViewModule.NAME) +class SvgViewModule extends NativeSvgViewModuleSpec { + SvgViewModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + public static final String NAME = "RNSVGSvgViewModule"; + + @Nonnull + @Override + public String getName() { + return NAME; + } + + private static void toDataURL( + final int tag, final ReadableMap options, final Callback successCallback, final int attempt) { + UiThreadUtil.runOnUiThread( + new Runnable() { + @Override + public void run() { + SvgView svg = SvgViewManager.getSvgViewByTag(tag); + + if (svg == null) { + SvgViewManager.runWhenViewIsAvailable( + tag, + new Runnable() { + @Override + public void run() { + SvgView svg = SvgViewManager.getSvgViewByTag(tag); + if (svg == null) { // Should never happen + return; + } + svg.setToDataUrlTask( + new Runnable() { + @Override + public void run() { + toDataURL(tag, options, successCallback, attempt + 1); + } + }); + } + }); + } else if (svg.notRendered()) { + svg.setToDataUrlTask( + new Runnable() { + @Override + public void run() { + toDataURL(tag, options, successCallback, attempt + 1); + } + }); + } else { + if (options != null) { + successCallback.invoke( + svg.toDataURL(options.getInt("width"), options.getInt("height"))); + } else { + successCallback.invoke(svg.toDataURL()); + } + } + } + }); + } + + @SuppressWarnings("unused") + @ReactMethod + @Override + public void toDataURL(Double tag, ReadableMap options, Callback successCallback) { + toDataURL(tag.intValue(), options, successCallback, 0); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SymbolView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SymbolView.java new file mode 100644 index 00000000000000..4b836b89b01b7b --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/SymbolView.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +@SuppressLint("ViewConstructor") +class SymbolView extends GroupView { + + private float mMinX; + private float mMinY; + private float mVbWidth; + private float mVbHeight; + private String mAlign; + private int mMeetOrSlice; + + public SymbolView(ReactContext reactContext) { + super(reactContext); + } + + public void setMinX(float minX) { + mMinX = minX; + invalidate(); + } + + public void setMinY(float minY) { + mMinY = minY; + invalidate(); + } + + public void setVbWidth(float vbWidth) { + mVbWidth = vbWidth; + invalidate(); + } + + public void setVbHeight(float vbHeight) { + mVbHeight = vbHeight; + invalidate(); + } + + public void setAlign(String align) { + mAlign = align; + invalidate(); + } + + public void setMeetOrSlice(int meetOrSlice) { + mMeetOrSlice = meetOrSlice; + invalidate(); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + saveDefinition(); + } + + void drawSymbol(Canvas canvas, Paint paint, float opacity, float width, float height) { + if (mAlign != null) { + RectF vbRect = + new RectF( + mMinX * mScale, + mMinY * mScale, + (mMinX + mVbWidth) * mScale, + (mMinY + mVbHeight) * mScale); + RectF eRect = new RectF(0, 0, width, height); + Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice); + canvas.concat(viewBoxMatrix); + super.draw(canvas, paint, opacity); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TSpanView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TSpanView.java new file mode 100644 index 00000000000000..84f5ead29c245b --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TSpanView.java @@ -0,0 +1,1241 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import static android.graphics.Matrix.MTRANS_X; +import static android.graphics.Matrix.MTRANS_Y; +import static android.graphics.PathMeasure.POSITION_MATRIX_FLAG; +import static android.graphics.PathMeasure.TANGENT_MATRIX_FLAG; +import static abi49_0_0.com.horcrux.svg.TextProperties.AlignmentBaseline; +import static abi49_0_0.com.horcrux.svg.TextProperties.FontStyle; +import static abi49_0_0.com.horcrux.svg.TextProperties.FontVariantLigatures; +import static abi49_0_0.com.horcrux.svg.TextProperties.FontWeight; +import static abi49_0_0.com.horcrux.svg.TextProperties.TextAnchor; +import static abi49_0_0.com.horcrux.svg.TextProperties.TextPathMidLine; +import static abi49_0_0.com.horcrux.svg.TextProperties.TextPathSide; + +import android.annotation.SuppressLint; +import android.content.res.AssetManager; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.os.Build; +import android.text.Layout; +import android.text.SpannableString; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.view.View; +import android.view.ViewParent; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.views.text.ReactFontManager; +import java.text.Bidi; +import java.util.ArrayList; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class TSpanView extends TextView { + private static final double tau = 2 * Math.PI; + private static final double radToDeg = 360 / tau; + + private static final String FONTS = "fonts/"; + private static final String OTF = ".otf"; + private static final String TTF = ".ttf"; + + private Path mCachedPath; + @Nullable String mContent; + private TextPathView textPath; + private final ArrayList emoji = new ArrayList<>(); + private final ArrayList emojiTransforms = new ArrayList<>(); + private final AssetManager assets; + + public TSpanView(ReactContext reactContext) { + super(reactContext); + assets = mContext.getResources().getAssets(); + } + + public void setContent(@Nullable String content) { + mContent = content; + invalidate(); + } + + @Override + public void invalidate() { + mCachedPath = null; + super.invalidate(); + } + + void clearCache() { + mCachedPath = null; + super.clearCache(); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + if (mContent != null) { + if (mInlineSize != null && mInlineSize.value != 0) { + if (setupFillPaint(paint, opacity * fillOpacity)) { + drawWrappedText(canvas, paint); + } + if (setupStrokePaint(paint, opacity * strokeOpacity)) { + drawWrappedText(canvas, paint); + } + } else { + int numEmoji = emoji.size(); + if (numEmoji > 0) { + GlyphContext gc = getTextRootGlyphContext(); + FontData font = gc.getFont(); + applyTextPropertiesToPaint(paint, font); + for (int i = 0; i < numEmoji; i++) { + String current = emoji.get(i); + Matrix mid = emojiTransforms.get(i); + canvas.save(); + canvas.concat(mid); + canvas.drawText(current, 0, 0, paint); + canvas.restore(); + } + } + drawPath(canvas, paint, opacity); + } + } else { + clip(canvas, paint); + drawGroup(canvas, paint, opacity); + } + } + + private void drawWrappedText(Canvas canvas, Paint paint) { + GlyphContext gc = getTextRootGlyphContext(); + pushGlyphContext(); + FontData font = gc.getFont(); + TextPaint tp = new TextPaint(paint); + applyTextPropertiesToPaint(tp, font); + applySpacingAndFeatures(tp, font); + double fontSize = gc.getFontSize(); + + Layout.Alignment align; + switch (font.textAnchor) { + default: + case start: + align = Layout.Alignment.ALIGN_NORMAL; + break; + + case middle: + align = Layout.Alignment.ALIGN_CENTER; + break; + + case end: + align = Layout.Alignment.ALIGN_OPPOSITE; + break; + } + + boolean includeFontPadding = true; + SpannableString text = new SpannableString(mContent); + final double width = + PropHelper.fromRelative(mInlineSize, canvas.getWidth(), 0, mScale, fontSize); + StaticLayout layout = getStaticLayout(tp, align, includeFontPadding, text, (int) width); + + int lineAscent = layout.getLineAscent(0); + + float dx = (float) gc.nextX(0); + float dy = (float) (gc.nextY() + lineAscent); + popGlyphContext(); + + canvas.save(); + canvas.translate(dx, dy); + layout.draw(canvas); + canvas.restore(); + } + + @SuppressWarnings("deprecation") + private StaticLayout getStaticLayout( + TextPaint tp, + Layout.Alignment align, + boolean includeFontPadding, + SpannableString text, + int width) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return new StaticLayout(text, tp, width, align, 1.f, 0.f, includeFontPadding); + } else { + return StaticLayout.Builder.obtain(text, 0, text.length(), tp, width) + .setAlignment(align) + .setLineSpacing(0.f, 1.f) + .setIncludePad(includeFontPadding) + .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(); + } + } + + /** + * Implements visual to logical order converter. + * + * @author Nesterovsky bros + * @param text an input text in visual order to convert. + * @return a String value in logical order. + */ + public static String visualToLogical(String text) { + if ((text == null) || (text.length() == 0)) { + return text; + } + + Bidi bidi = new Bidi(text, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT); + + if (bidi.isLeftToRight()) { + return text; + } + + int count = bidi.getRunCount(); + byte[] levels = new byte[count]; + Integer[] runs = new Integer[count]; + + for (int i = 0; i < count; i++) { + levels[i] = (byte) bidi.getRunLevel(i); + runs[i] = i; + } + + Bidi.reorderVisually(levels, 0, runs, 0, count); + + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < count; i++) { + int index = runs[i]; + int start = bidi.getRunStart(index); + int end = bidi.getRunLimit(index); + int level = levels[index]; + + if ((level & 1) != 0) { + for (; --end >= start; ) { + result.append(text.charAt(end)); + } + } else { + result.append(text, start, end); + } + } + + return result.toString(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + if (mCachedPath != null) { + return mCachedPath; + } + + if (mContent == null) { + mCachedPath = getGroupPath(canvas, paint); + return mCachedPath; + } + + setupTextPath(); + + pushGlyphContext(); + mCachedPath = getLinePath(visualToLogical(mContent), paint, canvas); + popGlyphContext(); + + return mCachedPath; + } + + double getSubtreeTextChunksTotalAdvance(Paint paint) { + if (!Double.isNaN(cachedAdvance)) { + return cachedAdvance; + } + double advance = 0; + + if (mContent == null) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof TextView) { + TextView text = (TextView) child; + advance += text.getSubtreeTextChunksTotalAdvance(paint); + } + } + cachedAdvance = advance; + return advance; + } + + String line = mContent; + final int length = line.length(); + + if (length == 0) { + cachedAdvance = 0; + return advance; + } + + GlyphContext gc = getTextRootGlyphContext(); + FontData font = gc.getFont(); + applyTextPropertiesToPaint(paint, font); + + applySpacingAndFeatures(paint, font); + + cachedAdvance = paint.measureText(line); + return cachedAdvance; + } + + static final String requiredFontFeatures = + "'rlig', 'liga', 'clig', 'calt', 'locl', 'ccmp', 'mark', 'mkmk',"; + static final String disableDiscretionaryLigatures = + "'liga' 0, 'clig' 0, 'dlig' 0, 'hlig' 0, 'cala' 0, "; + static final String defaultFeatures = requiredFontFeatures + "'kern', "; + static final String additionalLigatures = "'hlig', 'cala', "; + static final String fontWeightTag = "'wght' "; + + private void applySpacingAndFeatures(Paint paint, FontData font) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + double letterSpacing = font.letterSpacing; + paint.setLetterSpacing((float) (letterSpacing / (font.fontSize * mScale))); + + final boolean allowOptionalLigatures = + letterSpacing == 0 && font.fontVariantLigatures == FontVariantLigatures.normal; + + if (allowOptionalLigatures) { + paint.setFontFeatureSettings( + defaultFeatures + additionalLigatures + font.fontFeatureSettings); + } else { + paint.setFontFeatureSettings( + defaultFeatures + disableDiscretionaryLigatures + font.fontFeatureSettings); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + paint.setFontVariationSettings( + fontWeightTag + font.absoluteFontWeight + font.fontVariationSettings); + } + } + } + + @SuppressWarnings("ConstantConditions") + private Path getLinePath(String line, Paint paint, Canvas canvas) { + final int length = line.length(); + final Path path = new Path(); + + emoji.clear(); + emojiTransforms.clear(); + + if (length == 0) { + return path; + } + + double pathLength = 0; + PathMeasure pm = null; + boolean isClosed = false; + final boolean hasTextPath = textPath != null; + if (hasTextPath) { + pm = new PathMeasure(textPath.getTextPath(canvas, paint), false); + pathLength = pm.getLength(); + isClosed = pm.isClosed(); + if (pathLength == 0) { + return path; + } + } + + GlyphContext gc = getTextRootGlyphContext(); + FontData font = gc.getFont(); + applyTextPropertiesToPaint(paint, font); + GlyphPathBag bag = new GlyphPathBag(paint); + boolean[] ligature = new boolean[length]; + final char[] chars = line.toCharArray(); + + /* + * + * Three properties affect the space between characters and words: + * + * ‘kerning’ indicates whether the user agent should adjust inter-glyph spacing + * based on kerning tables that are included in the relevant font + * (i.e., enable auto-kerning) or instead disable auto-kerning + * and instead set inter-character spacing to a specific length (typically, zero). + * + * ‘letter-spacing’ indicates an amount of space that is to be added between text + * characters supplemental to any spacing due to the ‘kerning’ property. + * + * ‘word-spacing’ indicates the spacing behavior between words. + * + * Letter-spacing is applied after bidi reordering and is in addition to any word-spacing. + * Depending on the justification rules in effect, user agents may further increase + * or decrease the space between typographic character units in order to justify text. + * + * */ + double kerning = font.kerning; + double wordSpacing = font.wordSpacing; + double letterSpacing = font.letterSpacing; + final boolean autoKerning = !font.manualKerning; + + /* + 11.1.2. Fonts and glyphs + + A font consists of a collection of glyphs together with other information (collectively, + the font tables) necessary to use those glyphs to present characters on some visual medium. + + The combination of the collection of glyphs and the font tables is called the font data. + + A font may supply substitution and positioning tables that can be used by a formatter + (text shaper) to re-order, combine and position a sequence of glyphs to form one or more + composite glyphs. + + The combining may be as simple as a ligature, or as complex as an indic syllable which + combines, usually with some re-ordering, multiple consonants and vowel glyphs. + + The tables may be language dependent, allowing the use of language appropriate letter forms. + + When a glyph, simple or composite, represents an indivisible unit for typesetting purposes, + it is know as a typographic character. + + Ligatures are an important feature of advance text layout. + + Some ligatures are discretionary while others (e.g. in Arabic) are required. + + The following explicit rules apply to ligature formation: + + Ligature formation should not be enabled when characters are in different DOM text nodes; + thus, characters separated by markup should not use ligatures. + + Ligature formation should not be enabled when characters are in different text chunks. + + Discretionary ligatures should not be used when the spacing between two characters is not + the same as the default space (e.g. when letter-spacing has a non-default value, + or text-align has a value of justify and text-justify has a value of distribute). + (See CSS Text Module Level 3, ([css-text-3]). + + SVG attributes such as ‘dx’, ‘textLength’, and ‘spacing’ (in ‘textPath’) that may reposition + typographic characters do not break discretionary ligatures. + + If discretionary ligatures are not desired + they can be turned off by using the font-variant-ligatures property. + + /* + When the effective letter-spacing between two characters is not zero + (due to either justification or non-zero computed ‘letter-spacing’), + user agents should not apply optional ligatures. + https://www.w3.org/TR/css-text-3/#letter-spacing-property + */ + final boolean allowOptionalLigatures = + letterSpacing == 0 && font.fontVariantLigatures == FontVariantLigatures.normal; + + /* + For OpenType fonts, discretionary ligatures include those enabled by + the liga, clig, dlig, hlig, and cala features; + required ligatures are found in the rlig feature. + https://svgwg.org/svg2-draft/text.html#FontsGlyphs + + http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings + + https://www.microsoft.com/typography/otspec/featurelist.htm + https://www.microsoft.com/typography/otspec/featuretags.htm + https://www.microsoft.com/typography/otspec/features_pt.htm + https://www.microsoft.com/typography/otfntdev/arabicot/features.aspx + http://unifraktur.sourceforge.net/testcases/enable_opentype_features/ + https://en.wikipedia.org/wiki/List_of_typographic_features + http://ilovetypography.com/OpenType/opentype-features.html + https://www.typotheque.com/articles/opentype_features_in_css + https://practice.typekit.com/lesson/caring-about-opentype-features/ + http://stateofwebtype.com/ + + 6.12. Low-level font feature settings control: the font-feature-settings property + + Name: font-feature-settings + Value: normal | # + Initial: normal + Applies to: all elements + Inherited: yes + Percentages: N/A + Media: visual + Computed value: as specified + Animatable: no + + https://drafts.csswg.org/css-fonts-3/#default-features + + 7.1. Default features + + For OpenType fonts, user agents must enable the default features defined in the OpenType + documentation for a given script and writing mode. + + Required ligatures, common ligatures and contextual forms must be enabled by default + (OpenType features: rlig, liga, clig, calt), + along with localized forms (OpenType feature: locl), + and features required for proper display of composed characters and marks + (OpenType features: ccmp, mark, mkmk). + + These features must always be enabled, even when the value of the ‘font-variant’ and + ‘font-feature-settings’ properties is ‘normal’. + + Individual features are only disabled when explicitly overridden by the author, + as when ‘font-variant-ligatures’ is set to ‘no-common-ligatures’. + + TODO For handling complex scripts such as Arabic, Mongolian or Devanagari additional features + are required. + + TODO For upright text within vertical text runs, + vertical alternates (OpenType feature: vert) must be enabled. + */ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // String arabic = "'isol', 'fina', 'medi', 'init', 'rclt', 'mset', 'curs', "; + if (allowOptionalLigatures) { + paint.setFontFeatureSettings( + defaultFeatures + additionalLigatures + font.fontFeatureSettings); + } else { + paint.setFontFeatureSettings( + defaultFeatures + disableDiscretionaryLigatures + font.fontFeatureSettings); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + paint.setFontVariationSettings( + fontWeightTag + font.absoluteFontWeight + font.fontVariationSettings); + } + } + // OpenType.js font data + ReadableMap fontData = font.fontData; + + float[] advances = new float[length]; + paint.getTextWidths(line, advances); + + /* + This would give both advances and textMeasure in one call / looping over the text + double textMeasure = paint.getTextRunAdvances(line, 0, length, 0, length, true, advances, 0); + */ + /* + Determine the startpoint-on-the-path for the first glyph using attribute ‘startOffset’ + and property text-anchor. + + For text-anchor:start, startpoint-on-the-path is the point + on the path which represents the point on the path which is ‘startOffset’ distance + along the path from the start of the path, calculated using the user agent's distance + along the path algorithm. + + For text-anchor:middle, startpoint-on-the-path is the point + on the path which represents the point on the path which is [ ‘startOffset’ minus half + of the total advance values for all of the glyphs in the ‘textPath’ element ] distance + along the path from the start of the path, calculated using the user agent's distance + along the path algorithm. + + For text-anchor:end, startpoint-on-the-path is the point on + the path which represents the point on the path which is [ ‘startOffset’ minus the + total advance values for all of the glyphs in the ‘textPath’ element ]. + + Before rendering the first glyph, the horizontal component of the startpoint-on-the-path + is adjusted to take into account various horizontal alignment text properties and + attributes, such as a ‘dx’ attribute value on a ‘tspan’ element. + */ + final TextAnchor textAnchor = font.textAnchor; + TextView anchorRoot = getTextAnchorRoot(); + final double textMeasure = anchorRoot.getSubtreeTextChunksTotalAdvance(paint); + double offset = getTextAnchorOffset(textAnchor, textMeasure); + + int side = 1; + double startOfRendering = 0; + double endOfRendering = pathLength; + double fontSize = gc.getFontSize(); + boolean sharpMidLine = false; + if (hasTextPath) { + sharpMidLine = textPath.getMidLine() == TextPathMidLine.sharp; + /* + Name + side + Value + left | right + initial value + left + Animatable + yes + + Determines the side of the path the text is placed on + (relative to the path direction). + + Specifying a value of right effectively reverses the path. + + Added in SVG 2 to allow text either inside or outside closed subpaths + and basic shapes (e.g. rectangles, circles, and ellipses). + + Adding 'side' was resolved at the Sydney (2015) meeting. + */ + side = textPath.getSide() == TextPathSide.right ? -1 : 1; + /* + Name + startOffset + Value + | | + initial value + 0 + Animatable + yes + + An offset from the start of the path for the initial current text position, + calculated using the user agent's distance along the path algorithm, + after converting the path to the ‘textPath’ element's coordinate system. + + If a other than a percentage is given, then the ‘startOffset’ + represents a distance along the path measured in the current user coordinate + system for the ‘textPath’ element. + + If a percentage is given, then the ‘startOffset’ represents a percentage + distance along the entire path. Thus, startOffset="0%" indicates the start + point of the path and startOffset="100%" indicates the end point of the path. + + Negative values and values larger than the path length (e.g. 150%) are allowed. + + Any typographic characters with mid-points that are not on the path are not rendered + + For paths consisting of a single closed subpath (including an equivalent path for a + basic shape), typographic characters are rendered along one complete circuit of the + path. The text is aligned as determined by the text-anchor property to a position + along the path set by the ‘startOffset’ attribute. + + For the start (end) value, the text is rendered from the start (end) of the line + until the initial position along the path is reached again. + + For the middle, the text is rendered from the middle point in both directions until + a point on the path equal distance in both directions from the initial position on + the path is reached. + */ + final double absoluteStartOffset = + getAbsoluteStartOffset(textPath.getStartOffset(), pathLength, fontSize); + offset += absoluteStartOffset; + if (isClosed) { + final double halfPathDistance = pathLength / 2; + startOfRendering = + absoluteStartOffset + (textAnchor == TextAnchor.middle ? -halfPathDistance : 0); + endOfRendering = startOfRendering + pathLength; + } + /* + TextPathSpacing spacing = textPath.getSpacing(); + if (spacing == TextPathSpacing.auto) { + // Hmm, what to do here? + // https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute + } + */ + } + + /* + Name + method + Value + align | stretch + initial value + align + Animatable + yes + Indicates the method by which text should be rendered along the path. + + A value of align indicates that the typographic character should be rendered using + simple 2×3 matrix transformations such that there is no stretching/warping of the + typographic characters. Typically, supplemental rotation, scaling and translation + transformations are done for each typographic characters to be rendered. + + As a result, with align, in fonts where the typographic characters are designed to be + connected (e.g., cursive fonts), the connections may not align properly when text is + rendered along a path. + + A value of stretch indicates that the typographic character outlines will be converted + into paths, and then all end points and control points will be adjusted to be along the + perpendicular vectors from the path, thereby stretching and possibly warping the glyphs. + + With this approach, connected typographic characters, such as in cursive scripts, + will maintain their connections. (Non-vertical straight path segments should be + converted to Bézier curves in such a way that horizontal straight paths have an + (approximately) constant offset from the path along which the typographic characters + are rendered.) + + TODO implement stretch + */ + + /* + Name Value Initial value Animatable + textLength | | See below yes + + The author's computation of the total sum of all of the advance values that correspond + to character data within this element, including the advance value on the glyph + (horizontal or vertical), the effect of properties letter-spacing and word-spacing and + adjustments due to attributes ‘dx’ and ‘dy’ on this ‘text’ or ‘tspan’ element or any + descendants. This value is used to calibrate the user agent's own calculations with + that of the author. + + The purpose of this attribute is to allow the author to achieve exact alignment, + in visual rendering order after any bidirectional reordering, for the first and + last rendered glyphs that correspond to this element; thus, for the last rendered + character (in visual rendering order after any bidirectional reordering), + any supplemental inter-character spacing beyond normal glyph advances are ignored + (in most cases) when the user agent determines the appropriate amount to expand/compress + the text string to fit within a length of ‘textLength’. + + If attribute ‘textLength’ is specified on a given element and also specified on an + ancestor, the adjustments on all character data within this element are controlled by + the value of ‘textLength’ on this element exclusively, with the possible side-effect + that the adjustment ratio for the contents of this element might be different than the + adjustment ratio used for other content that shares the same ancestor. The user agent + must assume that the total advance values for the other content within that ancestor is + the difference between the advance value on that ancestor and the advance value for + this element. + + This attribute is not intended for use to obtain effects such as shrinking or + expanding text. + + A negative value is an error (see Error processing). + + The ‘textLength’ attribute is only applied when the wrapping area is not defined by the + TODO shape-inside or the inline-size properties. It is also not applied for any ‘text’ or + TODO ‘tspan’ element that has forced line breaks (due to a white-space value of pre or + pre-line). + + If the attribute is not specified anywhere within a ‘text’ element, the effect is as if + the author's computation exactly matched the value calculated by the user agent; + thus, no advance adjustments are made. + */ + double scaleSpacingAndGlyphs = 1; + if (mTextLength != null) { + final double author = + PropHelper.fromRelative(mTextLength, canvas.getWidth(), 0, mScale, fontSize); + if (author < 0) { + throw new IllegalArgumentException("Negative textLength value"); + } + switch (mLengthAdjust) { + default: + case spacing: + letterSpacing += (author - textMeasure) / (length - 1); + break; + case spacingAndGlyphs: + scaleSpacingAndGlyphs = author / textMeasure; + break; + } + } + final double scaledDirection = scaleSpacingAndGlyphs * side; + + /* + https://developer.mozilla.org/en/docs/Web/CSS/vertical-align + https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html + https://www.microsoft.com/typography/otspec/base.htm + http://apike.ca/prog_svg_text_style.html + https://www.w3schools.com/tags/canvas_textbaseline.asp + http://vanseodesign.com/web-design/svg-text-baseline-alignment/ + https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align + https://tympanus.net/codrops/css_reference/vertical-align/ + + https://svgwg.org/svg2-draft/text.html#AlignmentBaselineProperty + 11.10.2.6. The ‘alignment-baseline’ property + + This property is defined in the CSS Line Layout Module 3 specification. See 'alignment-baseline'. [css-inline-3] + https://drafts.csswg.org/css-inline/#propdef-alignment-baseline + + The vertical-align property shorthand should be preferred in new content. + + SVG 2 introduces some changes to the definition of this property. + In particular: the values 'auto', 'before-edge', and 'after-edge' have been removed. + For backwards compatibility, 'text-before-edge' should be mapped to 'text-top' and + 'text-after-edge' should be mapped to 'text-bottom'. + + Neither 'text-before-edge' nor 'text-after-edge' should be used with the vertical-align property. + */ + final Paint.FontMetrics fm = paint.getFontMetrics(); + final double descenderDepth = fm.descent; + final double bottom = descenderDepth + fm.leading; + final double ascenderHeight = -fm.ascent + fm.leading; + final double top = -fm.top; + final double totalHeight = top + bottom; + double baselineShift = 0; + String baselineShiftString = getBaselineShift(); + AlignmentBaseline baseline = getAlignmentBaseline(); + if (baseline != null) { + // TODO alignment-baseline, test / verify behavior + // TODO get per glyph baselines from font baseline table, for high-precision alignment + switch (baseline) { + // https://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling + default: + case baseline: + // Use the dominant baseline choice of the parent. + // Match the box’s corresponding baseline to that of its parent. + baselineShift = 0; + break; + + case textBottom: + case afterEdge: + case textAfterEdge: + // Match the bottom of the box to the bottom of the parent’s content area. + // text-after-edge = text-bottom + // text-after-edge = descender depth + baselineShift = -descenderDepth; + break; + + case alphabetic: + // Match the box’s alphabetic baseline to that of its parent. + // alphabetic = 0 + baselineShift = 0; + break; + + case ideographic: + // Match the box’s ideographic character face under-side baseline to that of its parent. + // ideographic = descender depth + baselineShift = -descenderDepth; + break; + + case middle: + // Align the vertical midpoint of the box with the baseline of the parent box plus half + // the x-height of the parent. + // middle = x height / 2 + Rect bounds = new Rect(); + // this will just retrieve the bounding rect for 'x' + paint.getTextBounds("x", 0, 1, bounds); + int xHeight = bounds.height(); + baselineShift = xHeight / 2.0; + break; + + case central: + // Match the box’s central baseline to the central baseline of its parent. + // central = (ascender height - descender depth) / 2 + baselineShift = (ascenderHeight - descenderDepth) / 2; + break; + + case mathematical: + // Match the box’s mathematical baseline to that of its parent. + // Hanging and mathematical baselines + // There are no obvious formulas to calculate the position of these baselines. + // At the time of writing FOP puts the hanging baseline at 80% of the ascender + // height and the mathematical baseline at 50%. + baselineShift = 0.5 * ascenderHeight; + break; + + case hanging: + baselineShift = 0.8 * ascenderHeight; + break; + + case textTop: + case beforeEdge: + case textBeforeEdge: + // Match the top of the box to the top of the parent’s content area. + // text-before-edge = text-top + // text-before-edge = ascender height + baselineShift = ascenderHeight; + break; + + case bottom: + // Align the top of the aligned subtree with the top of the line box. + baselineShift = bottom; + break; + + case center: + // Align the center of the aligned subtree with the center of the line box. + baselineShift = totalHeight / 2; + break; + + case top: + // Align the bottom of the aligned subtree with the bottom of the line box. + baselineShift = top; + break; + } + } + /* + 2.2.2. Alignment Shift: baseline-shift longhand + + This property specifies by how much the box is shifted up from its alignment point. + It does not apply when alignment-baseline is top or bottom. + + Authors should use the vertical-align shorthand instead of this property. + + Values have the following meanings: + + + Raise (positive value) or lower (negative value) by the specified length. + + Raise (positive value) or lower (negative value) by the specified percentage of the line-height. + TODO sub + Lower by the offset appropriate for subscripts of the parent’s box. + (The UA should use the parent’s font data to find this offset whenever possible.) + TODO super + Raise by the offset appropriate for superscripts of the parent’s box. + (The UA should use the parent’s font data to find this offset whenever possible.) + + User agents may additionally support the keyword baseline as computing to 0 + if is necessary for them to support legacy SVG content. + Issue: We would prefer to remove this, + and are looking for feedback from SVG user agents as to whether it’s necessary. + + https://www.w3.org/TR/css-inline-3/#propdef-baseline-shift + */ + if (baselineShiftString != null && !baselineShiftString.isEmpty()) { + switch (baseline) { + case top: + case bottom: + break; + + default: + switch (baselineShiftString) { + case "sub": + // TODO + if (fontData != null && fontData.hasKey("tables") && fontData.hasKey("unitsPerEm")) { + int unitsPerEm = fontData.getInt("unitsPerEm"); + ReadableMap tables = fontData.getMap("tables"); + if (tables.hasKey("os2")) { + ReadableMap os2 = tables.getMap("os2"); + if (os2.hasKey("ySubscriptYOffset")) { + double subOffset = os2.getDouble("ySubscriptYOffset"); + baselineShift += mScale * fontSize * subOffset / unitsPerEm; + } + } + } + break; + + case "super": + // TODO + if (fontData != null && fontData.hasKey("tables") && fontData.hasKey("unitsPerEm")) { + int unitsPerEm = fontData.getInt("unitsPerEm"); + ReadableMap tables = fontData.getMap("tables"); + if (tables.hasKey("os2")) { + ReadableMap os2 = tables.getMap("os2"); + if (os2.hasKey("ySuperscriptYOffset")) { + double superOffset = os2.getDouble("ySuperscriptYOffset"); + baselineShift -= mScale * fontSize * superOffset / unitsPerEm; + } + } + } + break; + + case "baseline": + break; + + default: + baselineShift -= + PropHelper.fromRelative(baselineShiftString, mScale * fontSize, mScale, fontSize); + } + break; + } + } + + final Matrix start = new Matrix(); + final Matrix mid = new Matrix(); + final Matrix end = new Matrix(); + + final float[] startPointMatrixData = new float[9]; + final float[] endPointMatrixData = new float[9]; + + for (int index = 0; index < length; index++) { + char currentChar = chars[index]; + String current = String.valueOf(currentChar); + boolean alreadyRenderedGraphemeCluster = ligature[index]; + + /* + Determine the glyph's charwidth (i.e., the amount which the current text position + advances horizontally when the glyph is drawn using horizontal text layout). + */ + boolean hasLigature = false; + if (alreadyRenderedGraphemeCluster) { + current = ""; + } else { + int nextIndex = index; + while (++nextIndex < length) { + float nextWidth = advances[nextIndex]; + if (nextWidth > 0) { + break; + } + String nextLigature = current + chars[nextIndex]; + ligature[nextIndex] = true; + current = nextLigature; + hasLigature = true; + } + } + double charWidth = paint.measureText(current) * scaleSpacingAndGlyphs; + + /* + For each subsequent glyph, set a new startpoint-on-the-path as the previous + endpoint-on-the-path, but with appropriate adjustments taking into account + horizontal kerning tables in the font and current values of various attributes + and properties, including spacing properties (e.g. letter-spacing and word-spacing) + and ‘tspan’ elements with values provided for attributes ‘dx’ and ‘dy’. All + adjustments are calculated as distance adjustments along the path, calculated + using the user agent's distance along the path algorithm. + */ + if (autoKerning) { + double kerned = advances[index] * scaleSpacingAndGlyphs; + kerning = kerned - charWidth; + } + + boolean isWordSeparator = currentChar == ' '; + double wordSpace = isWordSeparator ? wordSpacing : 0; + double spacing = wordSpace + letterSpacing; + double advance = charWidth + spacing; + + double x = gc.nextX(alreadyRenderedGraphemeCluster ? 0 : kerning + advance); + double y = gc.nextY(); + double dx = gc.nextDeltaX(); + double dy = gc.nextDeltaY(); + double r = gc.nextRotation(); + + if (alreadyRenderedGraphemeCluster || isWordSeparator) { + // Skip rendering other grapheme clusters of ligatures (already rendered), + // But, make sure to increment index positions by making gc.next() calls. + continue; + } + + advance *= side; + charWidth *= side; + double cursor = offset + (x + dx) * side; + double startPoint = cursor - advance; + + if (hasTextPath) { + /* + Determine the point on the curve which is charwidth distance along the path from + the startpoint-on-the-path for this glyph, calculated using the user agent's + distance along the path algorithm. This point is the endpoint-on-the-path for + the glyph. + */ + double endPoint = startPoint + charWidth; + + /* + Determine the midpoint-on-the-path, which is the point on the path which is + "halfway" (user agents can choose either a distance calculation or a parametric + calculation) between the startpoint-on-the-path and the endpoint-on-the-path. + */ + double halfWay = charWidth / 2; + double midPoint = startPoint + halfWay; + + // Glyphs whose midpoint-on-the-path are off the path are not rendered. + if (midPoint > endOfRendering) { + continue; + } else if (midPoint < startOfRendering) { + continue; + } + + /* + Determine the glyph-midline, which is the vertical line in the glyph's + coordinate system that goes through the glyph's x-axis midpoint. + + Position the glyph such that the glyph-midline passes through + the midpoint-on-the-path and is perpendicular to the line + through the startpoint-on-the-path and the endpoint-on-the-path. + + TODO suggest adding a compatibility mid-line rendering attribute to textPath, + for a chrome/firefox/opera/safari compatible sharp text path rendering, + which doesn't bend text smoothly along a right angle curve, (like Edge does) + but keeps the mid-line orthogonal to the mid-point tangent at all times instead. + https://github.com/w3c/svgwg/issues/337 + */ + final int posAndTanFlags = POSITION_MATRIX_FLAG | TANGENT_MATRIX_FLAG; + if (sharpMidLine) { + pm.getMatrix((float) midPoint, mid, posAndTanFlags); + } else { + /* + In the calculation above, if either the startpoint-on-the-path + or the endpoint-on-the-path is off the end of the path, + then extend the path beyond its end points with a straight line + that is parallel to the tangent at the path at its end point + so that the midpoint-on-the-path can still be calculated. + + TODO suggest change in wording of svg spec: + so that the midpoint-on-the-path can still be calculated. + to + so that the angle of the glyph-midline to the x-axis can still be calculated. + or + so that the line through the startpoint-on-the-path and the + endpoint-on-the-path can still be calculated. + https://github.com/w3c/svgwg/issues/337#issuecomment-318056199 + */ + if (startPoint < 0) { + pm.getMatrix(0, start, posAndTanFlags); + start.preTranslate((float) startPoint, 0); + } else { + pm.getMatrix((float) startPoint, start, POSITION_MATRIX_FLAG); + } + + pm.getMatrix((float) midPoint, mid, POSITION_MATRIX_FLAG); + + if (endPoint > pathLength) { + pm.getMatrix((float) pathLength, end, posAndTanFlags); + end.preTranslate((float) (endPoint - pathLength), 0); + } else { + pm.getMatrix((float) endPoint, end, POSITION_MATRIX_FLAG); + } + + start.getValues(startPointMatrixData); + end.getValues(endPointMatrixData); + + double startX = startPointMatrixData[MTRANS_X]; + double startY = startPointMatrixData[MTRANS_Y]; + double endX = endPointMatrixData[MTRANS_X]; + double endY = endPointMatrixData[MTRANS_Y]; + + // line through the startpoint-on-the-path and the endpoint-on-the-path + double lineX = endX - startX; + double lineY = endY - startY; + + double glyphMidlineAngle = Math.atan2(lineY, lineX); + + mid.preRotate((float) (glyphMidlineAngle * radToDeg * side)); + } + + /* + Align the glyph vertically relative to the midpoint-on-the-path based on property + alignment-baseline and any specified values for attribute ‘dy’ on a ‘tspan’ element. + */ + mid.preTranslate((float) -halfWay, (float) (dy + baselineShift)); + mid.preScale((float) scaledDirection, (float) side); + mid.postTranslate(0, (float) y); + } else { + mid.setTranslate((float) startPoint, (float) (y + dy + baselineShift)); + } + + mid.preRotate((float) r); + + Path glyph; + if (hasLigature) { + glyph = new Path(); + paint.getTextPath(current, 0, current.length(), 0, 0, glyph); + } else { + glyph = bag.getOrCreateAndCache(currentChar, current); + } + RectF bounds = new RectF(); + glyph.computeBounds(bounds, true); + float width = bounds.width(); + if (width == 0) { // Render unicode emoji + canvas.save(); + canvas.concat(mid); + emoji.add(current); + emojiTransforms.add(new Matrix(mid)); + canvas.drawText(current, 0, 0, paint); + canvas.restore(); + } else { + glyph.transform(mid); + path.addPath(glyph); + } + } + + return path; + } + + private double getAbsoluteStartOffset(SVGLength startOffset, double distance, double fontSize) { + return PropHelper.fromRelative(startOffset, distance, 0, mScale, fontSize); + } + + private double getTextAnchorOffset(TextAnchor textAnchor, double textMeasure) { + switch (textAnchor) { + default: + case start: + return 0; + + case middle: + return -textMeasure / 2; + + case end: + return -textMeasure; + } + } + + private void applyTextPropertiesToPaint(Paint paint, FontData font) { + boolean isBold = font.fontWeight == FontWeight.Bold || font.absoluteFontWeight >= 550; + boolean isItalic = font.fontStyle == FontStyle.italic; + + int style; + if (isBold && isItalic) { + style = Typeface.BOLD_ITALIC; + } else if (isBold) { + style = Typeface.BOLD; + } else if (isItalic) { + style = Typeface.ITALIC; + } else { + style = Typeface.NORMAL; + } + + Typeface typeface = null; + int weight = font.absoluteFontWeight; + final String fontFamily = font.fontFamily; + if (fontFamily != null && fontFamily.length() > 0) { + String otfpath = FONTS + fontFamily + OTF; + String ttfpath = FONTS + fontFamily + TTF; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Typeface.Builder builder = new Typeface.Builder(assets, otfpath); + builder.setFontVariationSettings("'wght' " + weight + font.fontVariationSettings); + builder.setWeight(weight); + builder.setItalic(isItalic); + typeface = builder.build(); + if (typeface == null) { + builder = new Typeface.Builder(assets, ttfpath); + builder.setFontVariationSettings("'wght' " + weight + font.fontVariationSettings); + builder.setWeight(weight); + builder.setItalic(isItalic); + typeface = builder.build(); + } + } else { + try { + typeface = Typeface.createFromAsset(assets, otfpath); + typeface = Typeface.create(typeface, style); + } catch (Exception ignored) { + try { + typeface = Typeface.createFromAsset(assets, ttfpath); + typeface = Typeface.create(typeface, style); + } catch (Exception ignored2) { + } + } + } + } + + if (typeface == null) { + try { + typeface = ReactFontManager.getInstance().getTypeface(fontFamily, style, assets); + } catch (Exception ignored) { + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + typeface = Typeface.create(typeface, weight, isItalic); + } + + paint.setLinearText(true); + paint.setSubpixelText(true); + paint.setTypeface(typeface); + paint.setTextSize((float) (font.fontSize * mScale)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + paint.setLetterSpacing(0); + } + } + + private void setupTextPath() { + ViewParent parent = getParent(); + + while (parent != null) { + if (parent.getClass() == TextPathView.class) { + textPath = (TextPathView) parent; + break; + } else if (!(parent instanceof TextView)) { + break; + } + + parent = parent.getParent(); + } + } + + @Override + int hitTest(final float[] src) { + if (mContent == null) { + return super.hitTest(src); + } + if (mPath == null || !mInvertible || !mTransformInvertible) { + return -1; + } + + float[] dst = new float[2]; + mInvMatrix.mapPoints(dst, src); + mInvTransform.mapPoints(dst); + int x = Math.round(dst[0]); + int y = Math.round(dst[1]); + + initBounds(); + + if ((mRegion == null || !mRegion.contains(x, y)) + && (mStrokeRegion == null || !mStrokeRegion.contains(x, y))) { + return -1; + } + + Path clipPath = getClipPath(); + if (clipPath != null) { + if (!mClipRegion.contains(x, y)) { + return -1; + } + } + + return getId(); + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextLayoutAlgorithm.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextLayoutAlgorithm.java new file mode 100644 index 00000000000000..667b860ab50bb8 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextLayoutAlgorithm.java @@ -0,0 +1,1294 @@ +package abi49_0_0.com.horcrux.svg; + +// TODO implement https://www.w3.org/TR/SVG2/text.html#TextLayoutAlgorithm + +import static abi49_0_0.com.horcrux.svg.TextProperties.Direction; +import static abi49_0_0.com.horcrux.svg.TextProperties.TextAnchor; +import static abi49_0_0.com.horcrux.svg.TextProperties.TextPathSide; + +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.PointF; +import android.view.View; +import java.util.ArrayList; + +@SuppressWarnings("ALL") +class TextLayoutAlgorithm { + class CharacterInformation { + int index; + double x = 0; + double y = 0; + double advance; + char character; + double rotate = 0; + TextView element; + boolean hidden = false; + boolean middle = false; + boolean resolved = false; + boolean xSpecified = false; + boolean ySpecified = false; + boolean addressable = true; + boolean anchoredChunk = false; + boolean rotateSpecified = false; + boolean firstCharacterInResolvedDescendant = false; + + CharacterInformation(int index, char c) { + this.index = index; + this.character = c; + } + } + + class LayoutInput { + TextView text; + boolean horizontal; + } + + private void getSubTreeTypographicCharacterPositions( + ArrayList inTextPath, + ArrayList subtree, + StringBuilder line, + View node, + TextPathView textPath) { + if (node instanceof TSpanView) { + final TSpanView tSpanView = (TSpanView) node; + String content = tSpanView.mContent; + if (content == null) { + for (int i = 0; i < tSpanView.getChildCount(); i++) { + getSubTreeTypographicCharacterPositions( + inTextPath, subtree, line, tSpanView.getChildAt(i), textPath); + } + } else { + for (int i = 0; i < content.length(); i++) { + subtree.add(tSpanView); + inTextPath.add(textPath); + } + line.append(content); + } + } else { + textPath = node instanceof TextPathView ? (TextPathView) node : textPath; + for (int i = 0; i < textPath.getChildCount(); i++) { + getSubTreeTypographicCharacterPositions( + inTextPath, subtree, line, textPath.getChildAt(i), textPath); + } + } + } + + CharacterInformation[] layoutText(LayoutInput layoutInput) { + /* + Setup + + Let root be the result of generating + typographic character positions for the + ‘text’ element and its subtree, laid out as if it + were an absolutely positioned element. + + This will be a single line of text unless the + white-space property causes line breaks. + */ + TextView text = layoutInput.text; + StringBuilder line = new StringBuilder(); + ArrayList subtree = new ArrayList<>(); + ArrayList inTextPath = new ArrayList<>(); + getSubTreeTypographicCharacterPositions(inTextPath, subtree, line, text, null); + final char[] root = line.toString().toCharArray(); + /* + Let count be the number of DOM characters + within the ‘text’ element's subtree. + */ + int count = root.length; + /* + + Let result be an array of length count + whose entries contain the per-character information described + above. Each entry is initialized as follows: + + its global index number equal to its position in the array, + its "x" coordinate set to "unspecified", + its "y" coordinate set to "unspecified", + its "rotate" coordinate set to "unspecified", + its "hidden" flag is false, + its "addressable" flag is true, + its "middle" flag is false, + its "anchored chunk" flag is false. + */ + final CharacterInformation[] result = new CharacterInformation[count]; + for (int i = 0; i < count; i++) { + result[i] = new CharacterInformation(i, root[i]); + } + /* + If result is empty, then return result. + */ + if (count == 0) { + return result; + } + /* + + Let CSS_positions be an array of length + count whose entries will be filled with the + x and y positions of the corresponding + typographic character in root. The array + entries are initialized to (0, 0). + */ + PointF[] CSS_positions = new PointF[count]; + for (int i = 0; i < count; i++) { + CSS_positions[i] = new PointF(0, 0); + } + /* + Let "horizontal" be a flag, true if the writing mode of ‘text’ + is horizontal, false otherwise. + */ + final boolean horizontal = true; + /* + Set flags and assign initial positions + + For each array element with index i in + result: + */ + for (int i = 0; i < count; i++) { + /* + TODO Set addressable to false if the character at index i was: + + part of the text content of a non-rendered element + + discarded during layout due to being a + collapsed + white space character, a soft hyphen character, or a + bidi control character; or + + + discarded during layout due to being a + collapsed + segment break; or + + + trimmed + from the start or end of a line. + + Since there is collapsible white space not addressable by glyph + positioning attributes in the following ‘text’ element + (with a standard font), the "B" glyph will be placed at x=300. + + + A + B + + + This is because the white space before the "A", and all but one white space + character between the "A" and "B", is collapsed away or trimmed. + + */ + result[i].addressable = true; + /* + + Set middle to true if the character at index i + TODO is the second or later character that corresponds to a typographic character. + */ + result[i].middle = false; + /* + + TODO If the character at index i corresponds to a typographic character at the beginning of a line, then set the "anchored + chunk" flag of result[i] to true. + + This ensures chunks shifted by text-anchor do not + span multiple lines. + */ + result[i].anchoredChunk = i == 0; + /* + + If addressable is true and middle is false then + set CSS_positions[i] to the position of the + TODO corresponding typographic character as determined by the CSS + renderer. Otherwise, if i > 0, then set + CSS_positions[i] = + CSS_positions[i − 1] + + */ + if (result[i].addressable && !result[i].middle) { + CSS_positions[i].set(0, 0); + } else if (i > 0) { + CSS_positions[i].set(CSS_positions[i - 1]); + } + } + /* + + Resolve character positioning + + Position adjustments (e.g values in a ‘x’ attribute) + specified by a node apply to all characters in that node including + characters in the node's descendants. Adjustments specified in + descendant nodes, however, override adjustments from ancestor + nodes. This section resolves which adjustments are to be applied to + which characters. It also directly sets the rotate coordinate + of result. + + Set up: + + Let resolve_x, resolve_y, + resolve_dx, and resolve_dy be arrays of + length count whose entries are all initialized + to "unspecified". + */ + String[] resolve_x = new String[count]; + String[] resolve_y = new String[count]; + String[] resolve_dx = new String[count]; + String[] resolve_dy = new String[count]; + /* + + Set "in_text_path" flag false. + + This flag will allow ‘y’ (‘x’) + attribute values to be ignored for horizontal (vertical) + text inside ‘textPath’ elements. + */ + boolean in_text_path = false; + /* + Call the following procedure with the ‘text’ element node. + + Procedure: resolve character + positioning: + + A recursive procedure that takes as input a node and + whose steps are as follows: + */ + class CharacterPositioningResolver { + private int global = 0; + private boolean horizontal = true; + private boolean in_text_path = false; + private CharacterInformation[] result; + private String[] resolve_x; + private String[] resolve_y; + private String[] resolve_dx; + private String[] resolve_dy; + + private CharacterPositioningResolver( + CharacterInformation[] result, + String[] resolve_x, + String[] resolve_y, + String[] resolve_dx, + String[] resolve_dy) { + this.result = result; + this.resolve_x = resolve_x; + this.resolve_y = resolve_y; + this.resolve_dx = resolve_dx; + this.resolve_dy = resolve_dy; + } + + private void resolveCharacterPositioning(TextView node) { + /* + If node is a ‘text’ or ‘tspan’ node: + */ + if (node.getClass() == TextView.class || node.getClass() == TSpanView.class) { + /* + Let index equal the "global index number" of the + first character in the node. + */ + int index = global; + /* + Let x, y, dx, dy + and rotate be the lists of values from the + TODO corresponding attributes on node, or empty + lists if the corresponding attribute was not specified + or was invalid. + */ + // https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute + String[] x = new String[] {}; + + // https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute + String[] y = new String[] {}; + + // Current SVGLengthList + // https://www.w3.org/TR/SVG/types.html#DataTypeLengths + + // https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute + String[] dx = new String[] {}; + + // https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute + String[] dy = new String[] {}; + + // Current SVGLengthList + // https://www.w3.org/TR/SVG/types.html#DataTypeNumbers + + // https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute + double[] rotate = new double[] {}; + /* + + If "in_text_path" flag is false: + Let new_chunk_count + = max(length of x, length of y). + */ + int new_chunk_count; + if (!in_text_path) { + new_chunk_count = Math.max(x.length, y.length); + /* + + Else: + */ + } else { + /* + If the "horizontal" flag is true: + + Let new_chunk_count = length of x. + */ + if (horizontal) { + new_chunk_count = x.length; + /* + + Else: + + Let new_chunk_count = length of y. + */ + } else { + new_chunk_count = y.length; + } + } + /* + + Let length be the number of DOM characters in the + subtree rooted at node. + */ + String content = ((TSpanView) node).mContent; + int length = content == null ? 0 : content.length(); + /* + Let i = 0 and j = 0. + + i is an index of addressable characters in the node; + j is an index of all characters in the node. + */ + int i = 0; + int j = 0; + /* + While j < length, do: + */ + while (j < length) { + /* + This loop applies the ‘x’, ‘y’, + ‘dx’, ‘dy’ and ‘rotate’ + attributes to the content inside node. + If the "addressable" flag of result[index + + j] is true, then: + */ + if (result[index + j].addressable) { + /* + If i < TODO new_check_count, then (typo) + set the "anchored chunk" flag of + result[index + j] to + true. Else set the flag to false. + + Setting the flag to false ensures that ‘x’ + and ‘y’ attributes set in a ‘text’ + element don't create anchored chunk in a ‘textPath’ + element when they should not. + */ + result[index + j].anchoredChunk = i < new_chunk_count; + /* + + If i < length of x, + then set resolve_x[index + + j] to x[i]. + */ + if (i < x.length) { + resolve_x[index + j] = x[i]; + } + /* + + If "in_text_path" flag is true and the "horizontal" + flag is false, unset + resolve_x[index]. + + The ‘x’ attribute is ignored for + vertical text on a path. + */ + if (in_text_path && !horizontal) { + resolve_x[index] = ""; + } + /* + + If i < length of y, + then set resolve_y[index + + j] to y[i]. + */ + if (i < y.length) { + resolve_y[index + j] = y[i]; + } + /* + If "in_text_path" flag is true and the "horizontal" + flag is true, unset + resolve_y[index]. + + The ‘y’ attribute is ignored for + horizontal text on a path. + */ + if (in_text_path && horizontal) { + resolve_y[index] = ""; + } + /* + If i < length of dx, + then set resolve_dx[index + + j] to TODO dy[i]. (typo) + */ + if (i < dx.length) { + resolve_dx[index + j] = dx[i]; + } + /* + If i < length of dy, + then set resolve_dy[index + + j] to dy[i]. + */ + if (i < dy.length) { + resolve_dy[index + j] = dy[i]; + } + /* + If i < length of rotate, + then set the angle value of result[index + + j] to rotate[i]. + Otherwise, if rotate is not empty, then + set result[index + j] + to result[index + j − 1]. + */ + if (i < rotate.length) { + result[index + j].rotate = rotate[i]; + } else if (rotate.length != 0) { + result[index + j].rotate = result[index + j - 1].rotate; + } + /* + Set i = i + 1. + Set j = j + 1. + */ + } + i++; + j++; + } + /* + If node is a ‘textPath’ node: + + Let index equal the global index number of the + first character in the node (including descendant nodes). + */ + } else if (node.getClass() == TextPathView.class) { + int index = global; + /* + Set the "anchored chunk" flag of result[index] + to true. + + A ‘textPath’ element always creates an anchored chunk. + */ + result[index].anchoredChunk = true; + /* + Set in_text_path flag true. + */ + in_text_path = true; + /* + For each child node child of node: + Resolve glyph + positioning of child. + */ + for (int child = 0; child < node.getChildCount(); child++) { + resolveCharacterPositioning((TextView) node.getChildAt(child)); + } + /* + If node is a ‘textPath’ node: + + Set "in_text_path" flag false. + + */ + if (node instanceof TextPathView) { + in_text_path = false; + } + } + } + } + + CharacterPositioningResolver resolver = + new CharacterPositioningResolver(result, resolve_x, resolve_y, resolve_dx, resolve_dy); + /* + Adjust positions: dx, dy + + The ‘dx’ and ‘dy’ adjustments are applied + before adjustments due to the ‘textLength’ attribute while + the ‘x’, ‘y’ and ‘rotate’ + adjustments are applied after. + + Let shift be the cumulative x and + y shifts due to ‘x’ and ‘y’ + attributes, initialized to (0,0). + */ + PointF shift = new PointF(0, 0); + /* + For each array element with index i in result: + */ + for (int i = 0; i < count; i++) { + /* + If resolve_x[i] is unspecified, set it to 0. + If resolve_y[i] is unspecified, set it to 0. + */ + if (resolve_x[i].equals("")) { + resolve_x[i] = "0"; + } + if (resolve_y[i].equals("")) { + resolve_y[i] = "0"; + } + /* + Let shift.x = shift.x + resolve_x[i] + and shift.y = shift.y + resolve_y[i]. + */ + shift.x = shift.x + Float.parseFloat(resolve_x[i]); + shift.y = shift.y + Float.parseFloat(resolve_y[i]); + /* + Let result[i].x = CSS_positions[i].x + shift.x + and result[i].y = CSS_positions[i].y + shift.y. + */ + result[i].x = CSS_positions[i].x + shift.x; + result[i].y = CSS_positions[i].y + shift.y; + } + /* + TODO Apply ‘textLength’ attribute + + Set up: + + Define resolved descendant node as a + descendant of node with a valid ‘textLength’ + attribute that is not itself a descendant node of a + descendant node that has a valid ‘textLength’ + attribute. + + Call the following procedure with the ‘text’ element + node. + + Procedure: resolve text length: + + A recursive procedure that takes as input + a node and whose steps are as follows: + For each child node child of node: + + Resolve text length of child. + + Child nodes are adjusted before parent nodes. + */ + class TextLengthResolver { + int global; + + private void resolveTextLength(TextView node) { + /* + + If node is a ‘text’ or ‘tspan’ node + and if the node has a valid ‘textLength’ attribute value: + */ + final Class nodeClass = node.getClass(); + final boolean validTextLength = node.mTextLength != null; + if ((nodeClass == TSpanView.class) && validTextLength) { + /* + Let a = +∞ and b = −∞. + */ + double a = Double.POSITIVE_INFINITY; + double b = Double.NEGATIVE_INFINITY; + /* + + + Let i and j be the global + index of the first character and last characters + in node, respectively. + */ + String content = ((TSpanView) node).mContent; + int i = global; + int j = i + (content == null ? 0 : content.length()); + /* + For each index k in the range + [i, j] where the "addressable" flag + of result[k] is true: + + This loop finds the left-(top-) most and + right-(bottom-) most extents of the typographic characters within the node and checks for + forced line breaks. + */ + for (int k = i; k <= j; k++) { + if (!result[i].addressable) { + continue; + } + /* + If the character at k is a linefeed + or carriage return, return. No adjustments due to + ‘textLength’ are made to a node with + a forced line break. + */ + switch (result[i].character) { + case '\n': + case '\r': + return; + } + /* + Let pos = the x coordinate of the position + in result[k], if the "horizontal" + flag is true, and the y coordinate otherwise. + */ + double pos = horizontal ? result[k].x : result[k].y; + /* + Let advance = the advance of + the typographic character corresponding to + character k. [NOTE: This advance will be + negative for RTL horizontal text.] + */ + double advance = result[k].advance; + /* + Set a = + min(a, pos, pos + + advance). + + + Set b = + max(b, pos, pos + + advance). + */ + a = Math.min(a, Math.min(pos, pos + advance)); + b = Math.max(b, Math.max(pos, pos + advance)); + } + /* + + If a ≠ +∞ then: + + */ + if (a != Double.POSITIVE_INFINITY) { + /* + + Find the distance delta = ‘textLength’ + computed value − (b − a). + */ + double delta = node.mTextLength.value - (b - a); + /* + + User agents are required to shift the last + typographic character in the node by + delta, in the positive x direction + if the "horizontal" flag is true and if + direction is + lrt, in the + negative x direction if the "horizontal" flag + is true and direction is + rtl, or in the + positive y direction otherwise. User agents + are free to adjust intermediate + typographic characters for optimal + typography. The next steps indicate one way to + adjust typographic characters when + the value of ‘lengthAdjust’ is + spacing. + + Find n, the total number of + typographic characters in this node + TODO including any descendant nodes that are not resolved + descendant nodes or within a resolved descendant + node. + */ + int n = 0; + int resolvedDescendantNodes = 0; + for (int c = 0; c < node.getChildCount(); c++) { + if (((TextPathView) node.getChildAt(c)).mTextLength == null) { + String ccontent = ((TSpanView) node).mContent; + n += ccontent == null ? 0 : ccontent.length(); + } else { + result[n].firstCharacterInResolvedDescendant = true; + resolvedDescendantNodes++; + } + } + /* + Let n = n + number of + resolved descendant nodes − 1. + */ + n += resolvedDescendantNodes - 1; + /* + Each resolved descendant node is treated as if it + were a single + typographic character in this + context. + + Find the per-character adjustment δ + = delta/n. + + Let shift = 0. + */ + double perCharacterAdjustment = delta / n; + double shift = 0; + /* + For each index k in the range [i,j]: + */ + for (int k = i; k <= j; k++) { + /* + Add shift to the x coordinate of the + position in result[k], if the "horizontal" + flag is true, and to the y coordinate + otherwise. + */ + if (horizontal) { + result[k].x += shift; + } else { + result[k].y += shift; + } + /* + If the "middle" flag for result[k] + is not true and k is not a character in + a resolved descendant node other than the first + character then shift = shift + + δ. + */ + if (!result[k].middle + && (!result[k].resolved || result[k].firstCharacterInResolvedDescendant)) { + shift += perCharacterAdjustment; + } + } + } + } + } + } + TextLengthResolver lengthResolver = new TextLengthResolver(); + lengthResolver.resolveTextLength(text); + /* + + Adjust positions: x, y + + This loop applies ‘x’ and ‘y’ values, + and ensures that text-anchor chunks do not start in + the middle of a typographic character. + + Let shift be the current adjustment due to + the ‘x’ and ‘y’ attributes, + initialized to (0,0). + + Set index = 1. + */ + shift.set(0, 0); + int index = 1; + /* + While index < count: + */ + while (index < count) { + /* + TODO If resolved_x[index] is set, then let (typo) + shift.x = + resolved_x[index] − + result.x[index]. + */ + if (resolve_x[index] != null) { + shift.x = (float) (Double.parseDouble(resolve_x[index]) - result[index].x); + } + /* + TODO If resolved_y[index] is set, then let (typo) + shift.y = + resolved_y[index] − + result.y[index]. + */ + if (resolve_y[index] != null) { + shift.y = (float) (Double.parseDouble(resolve_y[index]) - result[index].y); + } + /* + Let result.x[index] = + result.x[index] + shift.x + and result.y[index] = + result.y[index] + shift.y. + */ + result[index].x += shift.x; + result[index].y += shift.y; + /* + If the "middle" and "anchored chunk" flags + of result[index] are both true, then: + */ + if (result[index].middle && result[index].anchoredChunk) { + /* + Set the "anchored chunk" flag + of result[index] to false. + */ + result[index].anchoredChunk = false; + } + /* + + If index + 1 < count, then set + the "anchored chunk" flag + of result[index + 1] to true. + */ + if (index + 1 < count) { + result[index + 1].anchoredChunk = true; + } + /* + Set index to index + 1. + */ + index++; + } + /* + + Apply anchoring + + TODO For each slice result[i..j] + (inclusive of both i and j), where: + + the "anchored chunk" flag of result[i] + is true, + + the "anchored chunk" flags + of result[k] where i + < k ≤ j are false, and + + j = count − 1 or the "anchored + chunk" flag of result[j + 1] is + true; + do: + + This loops over each anchored chunk. + + Let a = +∞ and b = −∞. + + For each index k in the range + [i, j] where the "addressable" flag + of result[k] is true: + + This loop finds the left-(top-) most and + right-(bottom-) most extents of the typographic character within the anchored chunk. + */ + int i = 0; + double a = Double.POSITIVE_INFINITY; + double b = Double.NEGATIVE_INFINITY; + double prevA = Double.POSITIVE_INFINITY; + double prevB = Double.NEGATIVE_INFINITY; + for (int k = 0; k < count; k++) { + if (!result[k].addressable) { + continue; + } + if (result[k].anchoredChunk) { + prevA = a; + prevB = b; + a = Double.POSITIVE_INFINITY; + b = Double.NEGATIVE_INFINITY; + } + /* + Let pos = the x coordinate of the position + in result[k], if the "horizontal" flag + is true, and the y coordinate otherwise. + + Let advance = the advance of + the typographic character corresponding to + character k. [NOTE: This advance will be + negative for RTL horizontal text.] + + Set a = + min(a, pos, pos + + advance). + + Set b = + max(b, pos, pos + + advance). + */ + double pos = horizontal ? result[k].x : result[k].y; + double advance = result[k].advance; + a = Math.min(a, Math.min(pos, pos + advance)); + b = Math.max(b, Math.max(pos, pos + advance)); + /* + If a ≠ +∞, then: + + Here we perform the text anchoring. + + Let shift be the x coordinate of + result[i], if the "horizontal" flag + is true, and the y coordinate otherwise. + + TODO Adjust shift based on the value of text-anchor + TODO and direction of the element the character at + index i is in: + + (start, ltr) or (end, rtl) + Set shift = shift − a. + (start, rtl) or (end, ltr) + Set shift = shift − b. + (middle, ltr) or (middle, rtl) + Set shift = shift − (a + b) / 2. + */ + if ((k > 0 && result[k].anchoredChunk && prevA != Double.POSITIVE_INFINITY) + || k == count - 1) { + TextAnchor anchor = TextAnchor.start; + Direction direction = Direction.ltr; + + if (k == count - 1) { + prevA = a; + prevB = b; + } + + double anchorShift = horizontal ? result[i].x : result[i].y; + switch (anchor) { + case start: + if (direction == Direction.ltr) { + anchorShift = anchorShift - prevA; + } else { + anchorShift = anchorShift - prevB; + } + break; + + case middle: + if (direction == Direction.ltr) { + anchorShift = anchorShift - (prevA + prevB) / 2; + } else { + anchorShift = anchorShift - (prevA + prevB) / 2; + } + break; + + case end: + if (direction == Direction.ltr) { + anchorShift = anchorShift - prevB; + } else { + anchorShift = anchorShift - prevA; + } + break; + } + /* + For each index k in the range [i, j]: + + Add shift to the x coordinate of the position + in result[k], if the "horizontal" + flag is true, and to the y coordinate otherwise. + */ + int j = k == count - 1 ? k : k - 1; + for (int r = i; r <= j; r++) { + if (horizontal) { + result[r].x += anchorShift; + } else { + result[r].y += anchorShift; + } + } + + i = k; + } + } + /* + + Position on path + + Set index = 0. + + Set the "in path" flag to false. + + Set the "after path" flag to false. + + Let path_end be an offset for characters that follow + a ‘textPath’ element. Set path_end to (0,0). + + While index < count: + */ + index = 0; + boolean inPath = false; + boolean afterPath = false; + PointF path_end = new PointF(0, 0); + Path textPath = null; + PathMeasure pm = new PathMeasure(); + while (index < count) { + /* + If the character at index i is within a + ‘textPath’ element and corresponds to a typographic character, then: + + Set "in path" flag to true. + */ + final TextPathView textPathView = inTextPath.get(index); + if (textPathView != null && result[index].addressable) { + textPath = textPathView.getTextPath(null, null); + inPath = true; + /* + + If the "middle" flag of + result[index] is false, then: + */ + if (!result[index].middle) { + /* + Here we apply ‘textPath’ positioning. + + Let path be the equivalent path of + the basic shape element referenced by + the ‘textPath’ element, or an empty path if + the reference is invalid. + + If the ‘side’ attribute of + the ‘textPath’ element is + 'right', then + TODO reverse path. + */ + Path path = textPath; + if (textPathView.getSide() == TextPathSide.right) {} + + /* + Let length be the length + of path. + */ + pm.setPath(path, false); + double length = pm.getLength(); + /* + Let offset be the value of the + ‘textPath’ element's + ‘startOffset’ attribute, adjusted + due to any ‘pathLength’ attribute on the + referenced element (if the referenced element is + a ‘path’ element). + */ + double offset = textPathView.getStartOffset().value; + /* + Let advance = the advance of + the typographic character corresponding + to character TODO k. (typo) [NOTE: This advance will + be negative for RTL horizontal text.] + */ + double advance = result[index].advance; + /* + Let (x, y) + and angle be the position and angle + in result[index]. + */ + double x = result[index].x; + double y = result[index].y; + double angle = result[index].rotate; + /* + + Let mid be a coordinate value depending + on the value of the "horizontal" flag: + + true + mid is x + advance / 2 + + offset + false + mid is y + advance / 2 + + offset + */ + double mid = (horizontal ? x : y) + advance / 2 + offset; + /* + + The user agent is free to make any additional adjustments to + mid necessary to ensure high quality typesetting + TODO due to a ‘spacing’ value of + 'auto' or a + ‘method’ value of + 'stretch'. + + If path is not a closed subpath and + mid < 0 or mid > length, + set the "hidden" flag of result[index] to true. + */ + if (!pm.isClosed() && (mid < 0 || mid > length)) { + result[index].hidden = true; + } + /* + If path is a closed subpath depending on + the values of text-anchor and direction of + the element the character at index is in: + */ + if (pm.isClosed()) { + /* + This implements the special wrapping criteria for single + closed subpaths. + + (start, ltr) or (end, rtl) + + If mid−offset < 0 + or mid−offset > length, + set the "hidden" flag of result[index] to true. + + (middle, ltr) or (middle, rtl) + + If + If mid−offset < −length/2 + or mid−offset > length/2, + set the "hidden" flag of result[index] to true. + + (start, rtl) or (end, ltr) + + If mid−offset < −length + or mid−offset > 0, + set the "hidden" flag of result[index] to true. + */ + TextAnchor anchor = TextAnchor.start; + Direction direction = Direction.ltr; + + double anchorShift = horizontal ? result[i].x : result[i].y; + switch (anchor) { + case start: + if (direction == Direction.ltr) { + if (mid < 0 || mid > length) { + result[index].hidden = true; + } + } else { + if (mid < -length || mid > 0) { + result[index].hidden = true; + } + } + break; + + case middle: + if (mid < -length / 2 || mid > length / 2) { + result[index].hidden = true; + } + break; + + case end: + if (direction == Direction.ltr) { + if (mid < -length || mid > 0) { + result[index].hidden = true; + } + } else { + if (mid < 0 || mid > length) { + result[index].hidden = true; + } + } + break; + } + } + /* + Set mid = mid mod length. + */ + mid %= length; + /* + If the hidden flag is false: + */ + if (!result[index].hidden) { + /* + Let point be the position and + t be the unit vector tangent to + the point mid distance + along path. + */ + float[] point = new float[2]; + float[] t = new float[2]; + pm.getPosTan((float) mid, point, t); + final double tau = 2 * Math.PI; + final double radToDeg = 360 / tau; + final double r = Math.atan2(t[1], t[0]) * radToDeg; + /* + If the "horizontal" flag is + */ + if (horizontal) { + /* + true + + Let n be the normal unit vector + pointing in the direction t + 90°. + */ + double normAngle = r + 90; + double[] n = new double[] {Math.cos(normAngle), Math.sin(normAngle)}; + /* + Let o be the horizontal distance from the + TODO vertical center line of the glyph to the alignment point. + */ + double o = 0; + /* + Then set the position in + result[index] to + point - + o×t + + y×n. + + Let r be the angle from + the positive x-axis to the tangent. + + Set the angle value + in result[index] + to angle + r. + */ + result[index].rotate += r; + } else { + /* + false + + Let n be the normal unit vector + pointing in the direction t - 90°. + */ + double normAngle = r - 90; + double[] n = new double[] {Math.cos(normAngle), Math.sin(normAngle)}; + /* + Let o be the vertical distance from the + TODO horizontal center line of the glyph to the alignment point. + */ + double o = 0; + /* + + Then set the position in + result[index] to + point - + o×t + + x×n. + + Let r be the angle from + the positive y-axis to the tangent. + + Set the angle value + in result[index] + to angle + r. + */ + result[index].rotate += r; + } + } + /* + + Otherwise, the "middle" flag + of result[index] is true: + + Set the position and angle values + of result[index] to those + in result[index − 1]. + */ + } else { + result[index].x = result[index - 1].x; + result[index].y = result[index - 1].y; + result[index].rotate = result[index - 1].rotate; + } + } + /* + If the character at index i is not within a + ‘textPath’ element and corresponds to a typographic character, then: + + This sets the starting point for rendering any characters that + occur after a ‘textPath’ element to the end of the path. + */ + if (textPathView == null && result[index].addressable) { + /* + If the "in path" flag is true: + + Set the "in path" flag to false. + + Set the "after path" flag to true. + + Set path_end equal to the end point of the path + referenced by ‘textPath’ − the position of + result[index]. + */ + if (inPath) { + inPath = false; + afterPath = true; + pm.setPath(textPath, false); + float[] pos = new float[2]; + pm.getPosTan(pm.getLength(), pos, null); + path_end.set(pos[0], pos[1]); + } + /* + + If the "after path" is true. + + If anchored chunk of + result[index] is true, set the + "after path" flag to false. + + Else, + let result.x[index] = + result.x[index] + path_end.x + and result.y[index] = + result.y[index] + path_end.y. + */ + if (afterPath) { + if (result[index].anchoredChunk) { + afterPath = false; + } else { + result[index].x += path_end.x; + result[index].y += path_end.y; + } + } + } + /* + + Set index = index + 1. + */ + index++; + } + /* + Return result + */ + return result; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextPathView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextPathView.java new file mode 100644 index 00000000000000..6365c6ad997df1 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextPathView.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.horcrux.svg.TextProperties.*; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class TextPathView extends TextView { + + private String mHref; + private TextPathSide mSide; + private TextPathMidLine mMidLine; + private @Nullable SVGLength mStartOffset; + private TextPathMethod mMethod = TextPathMethod.align; + private TextPathSpacing mSpacing = TextPathSpacing.exact; + + public TextPathView(ReactContext reactContext) { + super(reactContext); + } + + public void setHref(String href) { + mHref = href; + invalidate(); + } + + public void setStartOffset(Dynamic startOffset) { + mStartOffset = SVGLength.from(startOffset); + invalidate(); + } + + public void setStartOffset(String startOffset) { + mStartOffset = SVGLength.from(startOffset); + invalidate(); + } + + public void setStartOffset(Double startOffset) { + mStartOffset = SVGLength.from(startOffset); + invalidate(); + } + + public void setMethod(@Nullable String method) { + mMethod = TextPathMethod.valueOf(method); + invalidate(); + } + + public void setSpacing(@Nullable String spacing) { + mSpacing = TextPathSpacing.valueOf(spacing); + invalidate(); + } + + public void setSide(@Nullable String side) { + mSide = TextPathSide.valueOf(side); + invalidate(); + } + + public void setSharp(@Nullable String midLine) { + mMidLine = TextPathMidLine.valueOf(midLine); + invalidate(); + } + + @SuppressWarnings("unused") + TextPathMethod getMethod() { + return mMethod; + } + + @SuppressWarnings("unused") + TextPathSpacing getSpacing() { + return mSpacing; + } + + TextPathSide getSide() { + return mSide; + } + + TextPathMidLine getMidLine() { + return mMidLine; + } + + SVGLength getStartOffset() { + return mStartOffset; + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + drawGroup(canvas, paint, opacity); + } + + Path getTextPath(Canvas canvas, Paint paint) { + SvgView svg = getSvgView(); + VirtualView template = svg.getDefinedTemplate(mHref); + + if (!(template instanceof RenderableView)) { + // warning about this. + return null; + } + + RenderableView view = (RenderableView) template; + return view.getPath(canvas, paint); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + return getGroupPath(canvas, paint); + } + + @Override + void pushGlyphContext() { + // do nothing + } + + @Override + void popGlyphContext() { + // do nothing + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextProperties.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextProperties.java new file mode 100644 index 00000000000000..3e407f94a54f61 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextProperties.java @@ -0,0 +1,219 @@ +package abi49_0_0.com.horcrux.svg; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nonnull; + +class TextProperties { + + /* + https://drafts.csswg.org/css-inline/#propdef-alignment-baseline + 2.2.1. Alignment Point: alignment-baseline longhand + + Name: alignment-baseline + Value: baseline | text-bottom | alphabetic | ideographic | middle | central | mathematical | text-top | bottom | center | top + Initial: baseline + Applies to: inline-level boxes, flex items, grid items, table cells + Inherited: no + Percentages: N/A + Media: visual + Computed value: as specified + Canonical order: per grammar + Animation type: discrete + */ + enum AlignmentBaseline { + baseline("baseline"), + textBottom("text-bottom"), + alphabetic("alphabetic"), + ideographic("ideographic"), + middle("middle"), + central("central"), + mathematical("mathematical"), + textTop("text-top"), + bottom("bottom"), + center("center"), + top("top"), + /* + SVG implementations may support the following aliases in order to support legacy content: + + text-before-edge = text-top + text-after-edge = text-bottom + */ + textBeforeEdge("text-before-edge"), + textAfterEdge("text-after-edge"), + // SVG 1.1 + beforeEdge("before-edge"), + afterEdge("after-edge"), + hanging("hanging"), + ; + + private final String alignment; + + AlignmentBaseline(String alignment) { + this.alignment = alignment; + } + + static AlignmentBaseline getEnum(String strVal) { + if (!alignmentToEnum.containsKey(strVal)) { + throw new IllegalArgumentException("Unknown String Value: " + strVal); + } + return alignmentToEnum.get(strVal); + } + + private static final Map alignmentToEnum = new HashMap<>(); + + static { + for (final AlignmentBaseline en : AlignmentBaseline.values()) { + alignmentToEnum.put(en.alignment, en); + } + } + + @Nonnull + @Override + public String toString() { + return alignment; + } + } + + // TODO implement rtl + @SuppressWarnings("unused") + enum Direction { + ltr, + rtl + } + + enum FontVariantLigatures { + normal, + @SuppressWarnings("unused") + none + } + + enum FontStyle { + normal, + italic, + @SuppressWarnings("unused") + oblique + } + + enum FontWeight { + // Absolute + Normal("normal"), + Bold("bold"), + w100("100"), + w200("200"), + w300("300"), + w400("400"), + w500("500"), + w600("600"), + w700("700"), + w800("800"), + w900("900"), + // Relative + Bolder("bolder"), + Lighter("lighter"); + + private final String weight; + + FontWeight(String weight) { + this.weight = weight; + } + + static boolean hasEnum(String strVal) { + return weightToEnum.containsKey(strVal); + } + + static FontWeight get(String strVal) { + return weightToEnum.get(strVal); + } + + private static final Map weightToEnum = new HashMap<>(); + + static { + for (final FontWeight en : FontWeight.values()) { + weightToEnum.put(en.weight, en); + } + } + + @Nonnull + @Override + public String toString() { + return weight; + } + } + + enum TextAnchor { + start, + middle, + end + } + + enum TextDecoration { + None("none"), + Underline("underline"), + Overline("overline"), + LineThrough("line-through"), + Blink("blink"); + + private final String decoration; + + TextDecoration(String decoration) { + this.decoration = decoration; + } + + static TextDecoration getEnum(String strVal) { + if (!decorationToEnum.containsKey(strVal)) { + throw new IllegalArgumentException("Unknown String Value: " + strVal); + } + return decorationToEnum.get(strVal); + } + + private static final Map decorationToEnum = new HashMap<>(); + + static { + for (final TextDecoration en : TextDecoration.values()) { + decorationToEnum.put(en.decoration, en); + } + } + + @Nonnull + @Override + public String toString() { + return decoration; + } + } + + enum TextLengthAdjust { + spacing, + spacingAndGlyphs + } + + enum TextPathMethod { + align, + @SuppressWarnings("unused") + stretch + } + + /* + TODO suggest adding a compatibility mid-line rendering attribute to textPath, + for a chrome/firefox/opera/safari compatible sharp text path rendering, + which doesn't bend text smoothly along a right angle curve, (like Edge does) + but keeps the mid-line orthogonal to the mid-point tangent at all times instead. + */ + enum TextPathMidLine { + sharp, + @SuppressWarnings("unused") + smooth + } + + enum TextPathSide { + @SuppressWarnings("unused") + left, + right + } + + enum TextPathSpacing { + @SuppressWarnings("unused") + auto, + exact + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextView.java new file mode 100644 index 00000000000000..a3212e8f3da3bc --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/TextView.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.horcrux.svg.TextProperties.AlignmentBaseline; +import static abi49_0_0.com.horcrux.svg.TextProperties.TextLengthAdjust; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Region; +import android.view.View; +import android.view.ViewParent; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import java.util.ArrayList; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +class TextView extends GroupView { + SVGLength mInlineSize = null; + SVGLength mTextLength = null; + private String mBaselineShift = null; + TextLengthAdjust mLengthAdjust = TextLengthAdjust.spacing; + private AlignmentBaseline mAlignmentBaseline; + @Nullable private ArrayList mPositionX; + @Nullable private ArrayList mPositionY; + @Nullable private ArrayList mRotate; + @Nullable private ArrayList mDeltaX; + @Nullable private ArrayList mDeltaY; + double cachedAdvance = Double.NaN; + + public TextView(ReactContext reactContext) { + super(reactContext); + } + + @Override + public void invalidate() { + if (mPath == null) { + return; + } + super.invalidate(); + getTextContainer().clearChildCache(); + } + + void clearCache() { + cachedAdvance = Double.NaN; + super.clearCache(); + } + + public void setInlineSize(Dynamic inlineSize) { + mInlineSize = SVGLength.from(inlineSize); + invalidate(); + } + + public void setInlineSize(String inlineSize) { + mInlineSize = SVGLength.from(inlineSize); + invalidate(); + } + + public void setInlineSize(Double inlineSize) { + mInlineSize = SVGLength.from(inlineSize); + invalidate(); + } + + public void setTextLength(Dynamic length) { + mTextLength = SVGLength.from(length); + invalidate(); + } + + public void setTextLength(String length) { + mTextLength = SVGLength.from(length); + invalidate(); + } + + public void setTextLength(Double length) { + mTextLength = SVGLength.from(length); + invalidate(); + } + + public void setLengthAdjust(@Nullable String adjustment) { + mLengthAdjust = TextLengthAdjust.valueOf(adjustment); + invalidate(); + } + + public void setMethod(@Nullable String alignment) { + mAlignmentBaseline = AlignmentBaseline.getEnum(alignment); + invalidate(); + } + + public void setBaselineShift(Dynamic baselineShift) { + mBaselineShift = SVGLength.toString(baselineShift); + invalidate(); + } + + public void setBaselineShift(String baselineShift) { + mBaselineShift = baselineShift; + invalidate(); + } + + public void setBaselineShift(Double baselineShift) { + mBaselineShift = String.valueOf(baselineShift); + invalidate(); + } + + public void setVerticalAlign(@Nullable String verticalAlign) { + if (verticalAlign != null) { + verticalAlign = verticalAlign.trim(); + int i = verticalAlign.lastIndexOf(' '); + try { + mAlignmentBaseline = AlignmentBaseline.getEnum(verticalAlign.substring(i)); + } catch (IllegalArgumentException e) { + mAlignmentBaseline = AlignmentBaseline.baseline; + } + try { + mBaselineShift = verticalAlign.substring(0, i); + } catch (IndexOutOfBoundsException e) { + mBaselineShift = null; + } + } else { + mAlignmentBaseline = AlignmentBaseline.baseline; + mBaselineShift = null; + } + invalidate(); + } + + public void setRotate(Dynamic rotate) { + mRotate = SVGLength.arrayFrom(rotate); + invalidate(); + } + + public void setRotate(ReadableArray rotate) { + mRotate = SVGLength.arrayFrom(rotate); + invalidate(); + } + + public void setDeltaX(Dynamic deltaX) { + mDeltaX = SVGLength.arrayFrom(deltaX); + invalidate(); + } + + public void setDeltaX(ReadableArray deltaX) { + mDeltaX = SVGLength.arrayFrom(deltaX); + invalidate(); + } + + public void setDeltaY(Dynamic deltaY) { + mDeltaY = SVGLength.arrayFrom(deltaY); + invalidate(); + } + + public void setDeltaY(ReadableArray deltaY) { + mDeltaY = SVGLength.arrayFrom(deltaY); + invalidate(); + } + + public void setPositionX(Dynamic positionX) { + mPositionX = SVGLength.arrayFrom(positionX); + invalidate(); + } + + public void setPositionX(ReadableArray positionX) { + mPositionX = SVGLength.arrayFrom(positionX); + invalidate(); + } + + public void setPositionY(Dynamic positionY) { + mPositionY = SVGLength.arrayFrom(positionY); + invalidate(); + } + + public void setPositionY(ReadableArray positionY) { + mPositionY = SVGLength.arrayFrom(positionY); + invalidate(); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + setupGlyphContext(canvas); + clip(canvas, paint); + getGroupPath(canvas, paint); + pushGlyphContext(); + drawGroup(canvas, paint, opacity); + popGlyphContext(); + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + if (mPath != null) { + return mPath; + } + setupGlyphContext(canvas); + return getGroupPath(canvas, paint); + } + + @Override + Path getPath(Canvas canvas, Paint paint, Region.Op op) { + return getPath(canvas, paint); + } + + AlignmentBaseline getAlignmentBaseline() { + if (mAlignmentBaseline == null) { + ViewParent parent = this.getParent(); + while (parent != null) { + if (parent instanceof TextView) { + TextView node = (TextView) parent; + final AlignmentBaseline baseline = node.mAlignmentBaseline; + if (baseline != null) { + mAlignmentBaseline = baseline; + return baseline; + } + } + parent = parent.getParent(); + } + } + if (mAlignmentBaseline == null) { + mAlignmentBaseline = AlignmentBaseline.baseline; + } + return mAlignmentBaseline; + } + + String getBaselineShift() { + if (mBaselineShift == null) { + ViewParent parent = this.getParent(); + while (parent != null) { + if (parent instanceof TextView) { + TextView node = (TextView) parent; + final String baselineShift = node.mBaselineShift; + if (baselineShift != null) { + mBaselineShift = baselineShift; + return baselineShift; + } + } + parent = parent.getParent(); + } + } + return mBaselineShift; + } + + Path getGroupPath(Canvas canvas, Paint paint) { + if (mPath != null) { + return mPath; + } + pushGlyphContext(); + mPath = super.getPath(canvas, paint); + popGlyphContext(); + + return mPath; + } + + @Override + void pushGlyphContext() { + boolean isTextNode = !(this instanceof TextPathView) && !(this instanceof TSpanView); + getTextRootGlyphContext() + .pushContext(isTextNode, this, mFont, mPositionX, mPositionY, mDeltaX, mDeltaY, mRotate); + } + + TextView getTextAnchorRoot() { + GlyphContext gc = getTextRootGlyphContext(); + ArrayList font = gc.mFontContext; + TextView node = this; + ViewParent parent = this.getParent(); + for (int i = font.size() - 1; i >= 0; i--) { + if (!(parent instanceof TextView) + || font.get(i).textAnchor == TextProperties.TextAnchor.start + || node.mPositionX != null) { + return node; + } + node = (TextView) parent; + parent = node.getParent(); + } + return node; + } + + double getSubtreeTextChunksTotalAdvance(Paint paint) { + if (!Double.isNaN(cachedAdvance)) { + return cachedAdvance; + } + double advance = 0; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof TextView) { + TextView text = (TextView) child; + advance += text.getSubtreeTextChunksTotalAdvance(paint); + } + } + cachedAdvance = advance; + return advance; + } + + TextView getTextContainer() { + TextView node = this; + ViewParent parent = this.getParent(); + while (parent instanceof TextView) { + node = (TextView) parent; + parent = node.getParent(); + } + return node; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/UseView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/UseView.java new file mode 100644 index 00000000000000..451a078dcd1700 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/UseView.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.common.ReactConstants; + +@SuppressLint("ViewConstructor") +class UseView extends RenderableView { + private String mHref; + private SVGLength mX; + private SVGLength mY; + private SVGLength mW; + private SVGLength mH; + + public UseView(ReactContext reactContext) { + super(reactContext); + } + + public void setHref(String href) { + mHref = href; + invalidate(); + } + + public void setX(Dynamic x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(String x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setX(Double x) { + mX = SVGLength.from(x); + invalidate(); + } + + public void setY(Dynamic y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(String y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setY(Double y) { + mY = SVGLength.from(y); + invalidate(); + } + + public void setWidth(Dynamic width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(String width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setWidth(Double width) { + mW = SVGLength.from(width); + invalidate(); + } + + public void setHeight(Dynamic height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(String height) { + mH = SVGLength.from(height); + invalidate(); + } + + public void setHeight(Double height) { + mH = SVGLength.from(height); + invalidate(); + } + + @Override + void draw(Canvas canvas, Paint paint, float opacity) { + VirtualView template = getSvgView().getDefinedTemplate(mHref); + + if (template == null) { + FLog.w( + ReactConstants.TAG, + "`Use` element expected a pre-defined svg template as `href` prop, " + + "template named: " + + mHref + + " is not defined."); + return; + } + + template.clearCache(); + canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY)); + if (template instanceof RenderableView) { + ((RenderableView) template).mergeProperties(this); + } + + int count = template.saveAndSetupCanvas(canvas, mCTM); + clip(canvas, paint); + + if (template instanceof SymbolView) { + SymbolView symbol = (SymbolView) template; + symbol.drawSymbol( + canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH)); + } else { + template.draw(canvas, paint, opacity * mOpacity); + } + + this.setClientRect(template.getClientRect()); + + template.restoreCanvas(canvas, count); + if (template instanceof RenderableView) { + ((RenderableView) template).resetProperties(); + } + } + + @Override + int hitTest(float[] src) { + if (!mInvertible || !mTransformInvertible) { + return -1; + } + + float[] dst = new float[2]; + mInvMatrix.mapPoints(dst, src); + mInvTransform.mapPoints(dst); + + VirtualView template = getSvgView().getDefinedTemplate(mHref); + if (template == null) { + FLog.w( + ReactConstants.TAG, + "`Use` element expected a pre-defined svg template as `href` prop, " + + "template named: " + + mHref + + " is not defined."); + return -1; + } + + int hitChild = template.hitTest(dst); + if (hitChild != -1) { + return (template.isResponsible() || hitChild != template.getId()) ? hitChild : getId(); + } + + return -1; + } + + @Override + Path getPath(Canvas canvas, Paint paint) { + VirtualView template = getSvgView().getDefinedTemplate(mHref); + if (template == null) { + FLog.w( + ReactConstants.TAG, + "`Use` element expected a pre-defined svg template as `href` prop, " + + "template named: " + + mHref + + " is not defined."); + return null; + } + Path path = template.getPath(canvas, paint); + Path use = new Path(); + Matrix m = new Matrix(); + m.setTranslate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY)); + path.transform(m, use); + return use; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ViewBox.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ViewBox.java new file mode 100644 index 00000000000000..236369c13ba554 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/ViewBox.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package abi49_0_0.com.horcrux.svg; + +import android.graphics.Matrix; +import android.graphics.RectF; + +class ViewBox { + + private static final int MOS_MEET = 0; + private static final int MOS_SLICE = 1; + private static final int MOS_NONE = 2; + + static Matrix getTransform(RectF vbRect, RectF eRect, String align, int meetOrSlice) { + // based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform + + // Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the + // viewBox attribute respectively. + double vbX = vbRect.left; + double vbY = vbRect.top; + double vbWidth = vbRect.width(); + double vbHeight = vbRect.height(); + + // Let e-x, e-y, e-width, e-height be the position and size of the element respectively. + double eX = eRect.left; + double eY = eRect.top; + double eWidth = eRect.width(); + double eHeight = eRect.height(); + + // Initialize scale-x to e-width/vb-width. + double scaleX = eWidth / vbWidth; + + // Initialize scale-y to e-height/vb-height. + double scaleY = eHeight / vbHeight; + + // Initialize translate-x to e-x - (vb-x * scale-x). + // Initialize translate-y to e-y - (vb-y * scale-y). + double translateX = eX - (vbX * scaleX); + double translateY = eY - (vbY * scaleY); + + // If align is 'none' + if (meetOrSlice == MOS_NONE) { + // Let scale be set the smaller value of scale-x and scale-y. + // Assign scale-x and scale-y to scale. + double scale = scaleX = scaleY = Math.min(scaleX, scaleY); + + // If scale is greater than 1 + if (scale > 1) { + // Minus translateX by (eWidth / scale - vbWidth) / 2 + // Minus translateY by (eHeight / scale - vbHeight) / 2 + translateX -= (eWidth / scale - vbWidth) / 2; + translateY -= (eHeight / scale - vbHeight) / 2; + } else { + translateX -= (eWidth - vbWidth * scale) / 2; + translateY -= (eHeight - vbHeight * scale) / 2; + } + } else { + // If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to + // the smaller. + // Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x + // and scale-y to the larger. + + if (!align.equals("none") && meetOrSlice == MOS_MEET) { + scaleX = scaleY = Math.min(scaleX, scaleY); + } else if (!align.equals("none") && meetOrSlice == MOS_SLICE) { + scaleX = scaleY = Math.max(scaleX, scaleY); + } + + // If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x. + if (align.contains("xMid")) { + translateX += (eWidth - vbWidth * scaleX) / 2.0d; + } + + // If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x. + if (align.contains("xMax")) { + translateX += (eWidth - vbWidth * scaleX); + } + + // If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y. + if (align.contains("YMid")) { + translateY += (eHeight - vbHeight * scaleY) / 2.0d; + } + + // If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y. + if (align.contains("YMax")) { + translateY += (eHeight - vbHeight * scaleY); + } + } + + // The transform applied to content contained by the element is given by + // translate(translate-x, translate-y) scale(scale-x, scale-y). + Matrix transform = new Matrix(); + transform.postTranslate((float) translateX, (float) translateY); + transform.preScale((float) scaleX, (float) scaleY); + return transform; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/VirtualView.java b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/VirtualView.java new file mode 100644 index 00000000000000..a818cf91c0de54 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/main/java/abi49_0_0/com/horcrux/svg/VirtualView.java @@ -0,0 +1,610 @@ +package abi49_0_0.com.horcrux.svg; + +import static abi49_0_0.com.horcrux.svg.FontData.DEFAULT_FONT_SIZE; + +import android.annotation.SuppressLint; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.view.View; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityNodeInfo; +import com.facebook.common.logging.FLog; +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableType; +import abi49_0_0.com.facebook.react.common.ReactConstants; +import abi49_0_0.com.facebook.react.uimanager.DisplayMetricsHolder; +import abi49_0_0.com.facebook.react.uimanager.OnLayoutEvent; +import abi49_0_0.com.facebook.react.uimanager.PointerEvents; +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher; +import abi49_0_0.com.facebook.react.views.view.ReactViewGroup; +import java.util.ArrayList; +import javax.annotation.Nullable; + +@SuppressLint("ViewConstructor") +public abstract class VirtualView extends ReactViewGroup { + final ReactContext mContext; + + VirtualView(ReactContext reactContext) { + super(reactContext); + mContext = reactContext; + mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density; + } + + /* + N[1/Sqrt[2], 36] + The inverse of the square root of 2. + Provide enough digits for the 128-bit IEEE quad (36 significant digits). + */ + private static final double M_SQRT1_2l = 0.707106781186547524400844362104849039; + + private static final float[] sRawMatrix = + new float[] { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }; + float mOpacity = 1f; + Matrix mCTM = new Matrix(); + Matrix mMatrix = new Matrix(); + Matrix mTransform = new Matrix(); + Matrix mInvCTM = new Matrix(); + Matrix mInvMatrix = new Matrix(); + final Matrix mInvTransform = new Matrix(); + boolean mInvertible = true; + boolean mCTMInvertible = true; + boolean mTransformInvertible = true; + private RectF mClientRect; + + int mClipRule; + private @Nullable String mClipPath; + @Nullable String mMask; + @Nullable String mMarkerStart; + @Nullable String mMarkerMid; + @Nullable String mMarkerEnd; + + private static final int CLIP_RULE_EVENODD = 0; + static final int CLIP_RULE_NONZERO = 1; + + final float mScale; + private boolean mResponsible; + String mDisplay; + String mName; + + private SvgView svgView; + private Path mCachedClipPath; + private GroupView mTextRoot; + private double fontSize = -1; + private double canvasDiagonal = -1; + private float canvasHeight = -1; + private float canvasWidth = -1; + private GlyphContext glyphContext; + + Path mPath; + Path mFillPath; + Path mStrokePath; + Path mMarkerPath; + Path mClipRegionPath; + RectF mBox; + RectF mFillBounds; + RectF mStrokeBounds; + RectF mMarkerBounds; + RectF mClipBounds; + Region mRegion; + Region mMarkerRegion; + Region mStrokeRegion; + Region mClipRegion; + ArrayList elements; + PointerEvents mPointerEvents; + + void setPointerEvents(PointerEvents pointerEvents) { + mPointerEvents = pointerEvents; + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + if (mClientRect != null) { + + SvgView root = getSvgView(); + + int[] rootPositionOnScreen = new int[2]; + getSvgView().getLocationOnScreen(rootPositionOnScreen); + Rect infoBoundsInScreen = new Rect(); + infoBoundsInScreen.left = rootPositionOnScreen[0] + (int) Math.floor(mClientRect.left); + infoBoundsInScreen.top = rootPositionOnScreen[1] + (int) Math.floor(mClientRect.top); + infoBoundsInScreen.right = infoBoundsInScreen.left + (int) Math.ceil(mClientRect.width()); + infoBoundsInScreen.bottom = infoBoundsInScreen.top + (int) Math.ceil(mClientRect.height()); + + Rect rootVisibleRect = new Rect(); + boolean isRootVisible = root.getGlobalVisibleRect(rootVisibleRect); + boolean infoIsVisibleToUser = isRootVisible && infoBoundsInScreen.intersect(rootVisibleRect); + + String infoClassName = this.getClass().getCanonicalName(); + info.setBoundsInScreen(infoBoundsInScreen); + info.setClassName(infoClassName); + info.setVisibleToUser(infoIsVisibleToUser); + } + } + + @Override + public void invalidate() { + if (this instanceof RenderableView && mPath == null) { + return; + } + clearCache(); + clearParentCache(); + super.invalidate(); + } + + void clearCache() { + canvasDiagonal = -1; + canvasHeight = -1; + canvasWidth = -1; + fontSize = -1; + mStrokeRegion = null; + mMarkerRegion = null; + mRegion = null; + mPath = null; + } + + void clearChildCache() { + clearCache(); + for (int i = 0; i < getChildCount(); i++) { + View node = getChildAt(i); + if (node instanceof VirtualView) { + ((VirtualView) node).clearChildCache(); + } + } + } + + private void clearParentCache() { + VirtualView node = this; + while (true) { + ViewParent parent = node.getParent(); + if (!(parent instanceof VirtualView)) { + return; + } + node = (VirtualView) parent; + if (node.mPath == null) { + return; + } + node.clearCache(); + } + } + + @Nullable + GroupView getTextRoot() { + VirtualView node = this; + if (mTextRoot == null) { + while (node != null) { + if (node instanceof GroupView && ((GroupView) node).getGlyphContext() != null) { + mTextRoot = (GroupView) node; + break; + } + + ViewParent parent = node.getParent(); + + if (!(parent instanceof VirtualView)) { + node = null; + } else { + node = (VirtualView) parent; + } + } + } + + return mTextRoot; + } + + @Nullable + GroupView getParentTextRoot() { + ViewParent parent = this.getParent(); + if (!(parent instanceof VirtualView)) { + return null; + } else { + return ((VirtualView) parent).getTextRoot(); + } + } + + private double getFontSizeFromContext() { + if (fontSize != -1) { + return fontSize; + } + GroupView root = getTextRoot(); + if (root == null) { + return DEFAULT_FONT_SIZE; + } + + if (glyphContext == null) { + glyphContext = root.getGlyphContext(); + } + + fontSize = glyphContext.getFontSize(); + + return fontSize; + } + + abstract void draw(Canvas canvas, Paint paint, float opacity); + + void render(Canvas canvas, Paint paint, float opacity) { + draw(canvas, paint, opacity); + } + + /** + * Sets up the transform matrix on the canvas before an element is drawn. + * + *

NB: for perf reasons this does not apply opacity, as that would mean creating a new canvas + * layer (which allocates an offscreen bitmap) and having it composited afterwards. Instead, the + * drawing code should apply opacity recursively. + * + * @param canvas the canvas to set up + * @param ctm current transformation matrix + */ + int saveAndSetupCanvas(Canvas canvas, Matrix ctm) { + int count = canvas.save(); + mCTM.setConcat(mMatrix, mTransform); + canvas.concat(mCTM); + mCTM.preConcat(ctm); + mCTMInvertible = mCTM.invert(mInvCTM); + return count; + } + + /** + * Restore the canvas after an element was drawn. This is always called in mirror with {@link + * #saveAndSetupCanvas}. + * + * @param canvas the canvas to restore + */ + void restoreCanvas(Canvas canvas, int count) { + canvas.restoreToCount(count); + } + + public void setName(String name) { + mName = name; + invalidate(); + } + + public void setDisplay(String display) { + mDisplay = display; + invalidate(); + } + + public void setMask(String mask) { + mMask = mask; + invalidate(); + } + + public void setMarkerStart(String markerStart) { + mMarkerStart = markerStart; + invalidate(); + } + + public void setMarkerMid(String markerMid) { + mMarkerMid = markerMid; + invalidate(); + } + + public void setMarkerEnd(String markerEnd) { + mMarkerEnd = markerEnd; + invalidate(); + } + + public void setClipPath(String clipPath) { + mCachedClipPath = null; + mClipPath = clipPath; + invalidate(); + } + + public void setClipRule(int clipRule) { + mClipRule = clipRule; + invalidate(); + } + + public void setOpacity(float opacity) { + mOpacity = opacity; + invalidate(); + } + + public void setMatrix(Dynamic matrixArray) { + boolean isArrayType = !matrixArray.isNull() && matrixArray.getType().equals(ReadableType.Array); + setMatrix(isArrayType ? matrixArray.asArray() : null); + } + + public void setMatrix(@Nullable ReadableArray matrixArray) { + if (matrixArray != null) { + int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); + if (matrixSize == 6) { + if (mMatrix == null) { + mMatrix = new Matrix(); + mInvMatrix = new Matrix(); + } + mMatrix.setValues(sRawMatrix); + mInvertible = mMatrix.invert(mInvMatrix); + } else if (matrixSize != -1) { + FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); + } + } else { + mMatrix.reset(); + mInvMatrix.reset(); + mInvertible = true; + } + super.invalidate(); + clearParentCache(); + } + + public void setResponsible(boolean responsible) { + mResponsible = responsible; + invalidate(); + } + + @Nullable + Path getClipPath() { + return mCachedClipPath; + } + + @Nullable + Path getClipPath(Canvas canvas, Paint paint) { + if (mClipPath != null) { + ClipPathView mClipNode = (ClipPathView) getSvgView().getDefinedClipPath(mClipPath); + + if (mClipNode != null) { + Path clipPath = + mClipRule == CLIP_RULE_EVENODD + ? mClipNode.getPath(canvas, paint) + : mClipNode.getPath(canvas, paint, Region.Op.UNION); + clipPath.transform(mClipNode.mMatrix); + clipPath.transform(mClipNode.mTransform); + switch (mClipRule) { + case CLIP_RULE_EVENODD: + clipPath.setFillType(Path.FillType.EVEN_ODD); + break; + case CLIP_RULE_NONZERO: + break; + default: + FLog.w(ReactConstants.TAG, "RNSVG: clipRule: " + mClipRule + " unrecognized"); + } + mCachedClipPath = clipPath; + } else { + FLog.w(ReactConstants.TAG, "RNSVG: Undefined clipPath: " + mClipPath); + } + } + + return getClipPath(); + } + + void clip(Canvas canvas, Paint paint) { + Path clip = getClipPath(canvas, paint); + + if (clip != null) { + canvas.clipPath(clip); + } + } + + abstract int hitTest(final float[] point); + + boolean isResponsible() { + return mResponsible; + } + + abstract Path getPath(Canvas canvas, Paint paint); + + @Nullable + SvgView getSvgView() { + if (svgView != null) { + return svgView; + } + + ViewParent parent = getParent(); + + if (parent == null) { + return null; + } else if (parent instanceof SvgView) { + svgView = (SvgView) parent; + } else if (parent instanceof VirtualView) { + svgView = ((VirtualView) parent).getSvgView(); + } else { + FLog.e( + ReactConstants.TAG, + "RNSVG: " + getClass().getName() + " should be descendant of a SvgView."); + } + + return svgView; + } + + double relativeOnWidth(SVGLength length) { + SVGLength.UnitType unit = length.unit; + if (unit == SVGLength.UnitType.NUMBER) { + return length.value * mScale; + } else if (unit == SVGLength.UnitType.PERCENTAGE) { + return length.value / 100 * getCanvasWidth(); + } + return fromRelativeFast(length); + } + + double relativeOnHeight(SVGLength length) { + SVGLength.UnitType unit = length.unit; + if (unit == SVGLength.UnitType.NUMBER) { + return length.value * mScale; + } else if (unit == SVGLength.UnitType.PERCENTAGE) { + return length.value / 100 * getCanvasHeight(); + } + return fromRelativeFast(length); + } + + double relativeOnOther(SVGLength length) { + SVGLength.UnitType unit = length.unit; + if (unit == SVGLength.UnitType.NUMBER) { + return length.value * mScale; + } else if (unit == SVGLength.UnitType.PERCENTAGE) { + return length.value / 100 * getCanvasDiagonal(); + } + return fromRelativeFast(length); + } + + /** + * Converts SVGLength into px / user units in the current user coordinate system + * + * @param length length string + * @return value in the current user coordinate system + */ + private double fromRelativeFast(SVGLength length) { + double unit; + switch (length.unit) { + case EMS: + unit = getFontSizeFromContext(); + break; + case EXS: + unit = getFontSizeFromContext() / 2; + break; + + case CM: + unit = 35.43307; + break; + case MM: + unit = 3.543307; + break; + case IN: + unit = 90; + break; + case PT: + unit = 1.25; + break; + case PC: + unit = 15; + break; + + default: + unit = 1; + } + return length.value * unit * mScale; + } + + private float getCanvasWidth() { + if (canvasWidth != -1) { + return canvasWidth; + } + GroupView root = getTextRoot(); + if (root == null) { + canvasWidth = getSvgView().getCanvasBounds().width(); + } else { + canvasWidth = root.getGlyphContext().getWidth(); + } + + return canvasWidth; + } + + private float getCanvasHeight() { + if (canvasHeight != -1) { + return canvasHeight; + } + GroupView root = getTextRoot(); + if (root == null) { + canvasHeight = getSvgView().getCanvasBounds().height(); + } else { + canvasHeight = root.getGlyphContext().getHeight(); + } + + return canvasHeight; + } + + private double getCanvasDiagonal() { + if (canvasDiagonal != -1) { + return canvasDiagonal; + } + double powX = Math.pow((getCanvasWidth()), 2); + double powY = Math.pow((getCanvasHeight()), 2); + canvasDiagonal = Math.sqrt(powX + powY) * M_SQRT1_2l; + return canvasDiagonal; + } + + void saveDefinition() { + if (mName != null) { + getSvgView().defineTemplate(this, mName); + } + } + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = + mClientRect != null + ? (int) Math.ceil(mClientRect.width()) + : getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); + + int height = + mClientRect != null + ? (int) Math.ceil(mClientRect.height()) + : getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); + + setMeasuredDimension(width, height); + } + + /** + * Called from layout when this view should assign a size and position to each of its children. + * + *

Derived classes with children should override this method and call layout on each of their + * children. + * + * @param changed This is a new size or position for this view + * @param pleft Left position, relative to parent + * @param ptop Top position, relative to parent + * @param pright Right position, relative to parent + * @param pbottom Bottom position, relative to parent + */ + protected void onLayout(boolean changed, int pleft, int ptop, int pright, int pbottom) { + if (mClientRect == null) { + return; + } + + if (!(this instanceof GroupView)) { + int left = (int) Math.floor(mClientRect.left); + int top = (int) Math.floor(mClientRect.top); + int right = (int) Math.ceil(mClientRect.right); + int bottom = (int) Math.ceil(mClientRect.bottom); + setLeft(left); + setTop(top); + setRight(right); + setBottom(bottom); + } + int width = (int) Math.ceil(mClientRect.width()); + int height = (int) Math.ceil(mClientRect.height()); + setMeasuredDimension(width, height); + } + + void setClientRect(RectF rect) { + if (mClientRect != null && mClientRect.equals(rect)) { + return; + } + mClientRect = rect; + if (mClientRect == null) { + return; + } + int width = (int) Math.ceil(mClientRect.width()); + int height = (int) Math.ceil(mClientRect.height()); + int left = (int) Math.floor(mClientRect.left); + int top = (int) Math.floor(mClientRect.top); + int right = (int) Math.ceil(mClientRect.right); + int bottom = (int) Math.ceil(mClientRect.bottom); + setMeasuredDimension(width, height); + if (!(this instanceof GroupView)) { + setLeft(left); + setTop(top); + setRight(right); + setBottom(bottom); + } + EventDispatcher eventDispatcher = + UIManagerHelper.getEventDispatcherForReactTag(mContext, getId()); + if (eventDispatcher != null) { + eventDispatcher.dispatchEvent(OnLayoutEvent.obtain(this.getId(), left, top, width, height)); + } + } + + RectF getClientRect() { + return mClientRect; + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java new file mode 100644 index 00000000000000..b7f32502178af0 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java @@ -0,0 +1,138 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGCircleManagerDelegate & RNSVGCircleManagerInterface> extends BaseViewManagerDelegate { + public RNSVGCircleManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "cx": + if (value instanceof String) { + mViewManager.setCx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setCx(view, (Double) value); + } else { + mViewManager.setCx(view, (Double) null); + } + break; + case "cy": + if (value instanceof String) { + mViewManager.setCy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setCy(view, (Double) value); + } else { + mViewManager.setCy(view, (Double) null); + } + break; + case "r": + if (value instanceof String) { + mViewManager.setR(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setR(view, (Double) value); + } else { + mViewManager.setR(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGCircleManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGCircleManagerInterface.java new file mode 100644 index 00000000000000..05c68c09faac06 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGCircleManagerInterface.java @@ -0,0 +1,50 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGCircleManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setCx(T view, @Nullable String value); + void setCx(T view, @Nullable Double value); + void setCy(T view, @Nullable String value); + void setCy(T view, @Nullable Double value); + void setR(T view, @Nullable String value); + void setR(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java new file mode 100644 index 00000000000000..ae3f4a9620d5cc --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java @@ -0,0 +1,132 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGClipPathManagerDelegate & RNSVGClipPathManagerInterface> extends BaseViewManagerDelegate { + public RNSVGClipPathManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGClipPathManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGClipPathManagerInterface.java new file mode 100644 index 00000000000000..eb211ae3445760 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGClipPathManagerInterface.java @@ -0,0 +1,49 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGClipPathManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGDefsManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGDefsManagerDelegate.java new file mode 100644 index 00000000000000..3ec2f3962f55dc --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGDefsManagerDelegate.java @@ -0,0 +1,65 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGDefsManagerDelegate & RNSVGDefsManagerInterface> extends BaseViewManagerDelegate { + public RNSVGDefsManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGDefsManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGDefsManagerInterface.java new file mode 100644 index 00000000000000..23122143935ee0 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGDefsManagerInterface.java @@ -0,0 +1,29 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; + +public interface RNSVGDefsManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java new file mode 100644 index 00000000000000..4baeab599317de --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java @@ -0,0 +1,147 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGEllipseManagerDelegate & RNSVGEllipseManagerInterface> extends BaseViewManagerDelegate { + public RNSVGEllipseManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "cx": + if (value instanceof String) { + mViewManager.setCx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setCx(view, (Double) value); + } else { + mViewManager.setCx(view, (Double) null); + } + break; + case "cy": + if (value instanceof String) { + mViewManager.setCy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setCy(view, (Double) value); + } else { + mViewManager.setCy(view, (Double) null); + } + break; + case "rx": + if (value instanceof String) { + mViewManager.setRx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRx(view, (Double) value); + } else { + mViewManager.setRx(view, (Double) null); + } + break; + case "ry": + if (value instanceof String) { + mViewManager.setRy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRy(view, (Double) value); + } else { + mViewManager.setRy(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGEllipseManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGEllipseManagerInterface.java new file mode 100644 index 00000000000000..99c744dfd28d07 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGEllipseManagerInterface.java @@ -0,0 +1,52 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGEllipseManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setCx(T view, @Nullable String value); + void setCx(T view, @Nullable Double value); + void setCy(T view, @Nullable String value); + void setCy(T view, @Nullable Double value); + void setRx(T view, @Nullable String value); + void setRx(T view, @Nullable Double value); + void setRy(T view, @Nullable String value); + void setRy(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java new file mode 100644 index 00000000000000..98820c2e553f32 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java @@ -0,0 +1,168 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGForeignObjectManagerDelegate & RNSVGForeignObjectManagerInterface> extends BaseViewManagerDelegate { + public RNSVGForeignObjectManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "x": + if (value instanceof String) { + mViewManager.setX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX(view, (Double) value); + } else { + mViewManager.setX(view, (Double) null); + } + break; + case "y": + if (value instanceof String) { + mViewManager.setY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY(view, (Double) value); + } else { + mViewManager.setY(view, (Double) null); + } + break; + case "height": + if (value instanceof String) { + mViewManager.setHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setHeight(view, (Double) value); + } else { + mViewManager.setHeight(view, (Double) null); + } + break; + case "width": + if (value instanceof String) { + mViewManager.setWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setWidth(view, (Double) value); + } else { + mViewManager.setWidth(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerInterface.java new file mode 100644 index 00000000000000..a6283f50391133 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerInterface.java @@ -0,0 +1,57 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGForeignObjectManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setX(T view, @Nullable String value); + void setX(T view, @Nullable Double value); + void setY(T view, @Nullable String value); + void setY(T view, @Nullable Double value); + void setHeight(T view, @Nullable String value); + void setHeight(T view, @Nullable Double value); + void setWidth(T view, @Nullable String value); + void setWidth(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java new file mode 100644 index 00000000000000..6602ccacd32ea0 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java @@ -0,0 +1,132 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGGroupManagerDelegate & RNSVGGroupManagerInterface> extends BaseViewManagerDelegate { + public RNSVGGroupManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGGroupManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGGroupManagerInterface.java new file mode 100644 index 00000000000000..59e0bf6f713253 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGGroupManagerInterface.java @@ -0,0 +1,49 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGGroupManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java new file mode 100644 index 00000000000000..9b44117b1669da --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java @@ -0,0 +1,156 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGImageManagerDelegate & RNSVGImageManagerInterface> extends BaseViewManagerDelegate { + public RNSVGImageManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "x": + if (value instanceof String) { + mViewManager.setX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX(view, (Double) value); + } else { + mViewManager.setX(view, (Double) null); + } + break; + case "y": + if (value instanceof String) { + mViewManager.setY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY(view, (Double) value); + } else { + mViewManager.setY(view, (Double) null); + } + break; + case "height": + if (value instanceof String) { + mViewManager.setHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setHeight(view, (Double) value); + } else { + mViewManager.setHeight(view, (Double) null); + } + break; + case "width": + if (value instanceof String) { + mViewManager.setWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setWidth(view, (Double) value); + } else { + mViewManager.setWidth(view, (Double) null); + } + break; + case "src": + mViewManager.setSrc(view, (ReadableMap) value); + break; + case "align": + mViewManager.setAlign(view, value == null ? null : (String) value); + break; + case "meetOrSlice": + mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGImageManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGImageManagerInterface.java new file mode 100644 index 00000000000000..1bd95b6fa0724e --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGImageManagerInterface.java @@ -0,0 +1,55 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGImageManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setX(T view, @Nullable String value); + void setX(T view, @Nullable Double value); + void setY(T view, @Nullable String value); + void setY(T view, @Nullable Double value); + void setWidth(T view, @Nullable String value); + void setWidth(T view, @Nullable Double value); + void setHeight(T view, @Nullable String value); + void setHeight(T view, @Nullable Double value); + void setSrc(T view, @Nullable ReadableMap value); + void setAlign(T view, @Nullable String value); + void setMeetOrSlice(T view, int value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java new file mode 100644 index 00000000000000..23653da113989f --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java @@ -0,0 +1,147 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGLineManagerDelegate & RNSVGLineManagerInterface> extends BaseViewManagerDelegate { + public RNSVGLineManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "x1": + if (value instanceof String) { + mViewManager.setX1(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX1(view, (Double) value); + } else { + mViewManager.setX1(view, (Double) null); + } + break; + case "y1": + if (value instanceof String) { + mViewManager.setY1(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY1(view, (Double) value); + } else { + mViewManager.setY1(view, (Double) null); + } + break; + case "x2": + if (value instanceof String) { + mViewManager.setX2(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX2(view, (Double) value); + } else { + mViewManager.setX2(view, (Double) null); + } + break; + case "y2": + if (value instanceof String) { + mViewManager.setY2(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY2(view, (Double) value); + } else { + mViewManager.setY2(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLineManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLineManagerInterface.java new file mode 100644 index 00000000000000..b8c5c29eb65774 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLineManagerInterface.java @@ -0,0 +1,52 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGLineManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setX1(T view, @Nullable String value); + void setX1(T view, @Nullable Double value); + void setY1(T view, @Nullable String value); + void setY1(T view, @Nullable Double value); + void setX2(T view, @Nullable String value); + void setX2(T view, @Nullable Double value); + void setY2(T view, @Nullable String value); + void setY2(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerDelegate.java new file mode 100644 index 00000000000000..c28f52054d1a78 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerDelegate.java @@ -0,0 +1,110 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGLinearGradientManagerDelegate & RNSVGLinearGradientManagerInterface> extends BaseViewManagerDelegate { + public RNSVGLinearGradientManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "x1": + if (value instanceof String) { + mViewManager.setX1(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX1(view, (Double) value); + } else { + mViewManager.setX1(view, (Double) null); + } + break; + case "y1": + if (value instanceof String) { + mViewManager.setY1(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY1(view, (Double) value); + } else { + mViewManager.setY1(view, (Double) null); + } + break; + case "x2": + if (value instanceof String) { + mViewManager.setX2(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX2(view, (Double) value); + } else { + mViewManager.setX2(view, (Double) null); + } + break; + case "y2": + if (value instanceof String) { + mViewManager.setY2(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY2(view, (Double) value); + } else { + mViewManager.setY2(view, (Double) null); + } + break; + case "gradient": + mViewManager.setGradient(view, (ReadableArray) value); + break; + case "gradientUnits": + mViewManager.setGradientUnits(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "gradientTransform": + mViewManager.setGradientTransform(view, (ReadableArray) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerInterface.java new file mode 100644 index 00000000000000..86847bd393c566 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerInterface.java @@ -0,0 +1,40 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; + +public interface RNSVGLinearGradientManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setX1(T view, @Nullable String value); + void setX1(T view, @Nullable Double value); + void setY1(T view, @Nullable String value); + void setY1(T view, @Nullable Double value); + void setX2(T view, @Nullable String value); + void setX2(T view, @Nullable Double value); + void setY2(T view, @Nullable String value); + void setY2(T view, @Nullable Double value); + void setGradient(T view, @Nullable ReadableArray value); + void setGradientUnits(T view, int value); + void setGradientTransform(T view, @Nullable ReadableArray value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java new file mode 100644 index 00000000000000..fd88283c5cb2b0 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java @@ -0,0 +1,192 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGMarkerManagerDelegate & RNSVGMarkerManagerInterface> extends BaseViewManagerDelegate { + public RNSVGMarkerManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "refX": + if (value instanceof String) { + mViewManager.setRefX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRefX(view, (Double) value); + } else { + mViewManager.setRefX(view, (Double) null); + } + break; + case "refY": + if (value instanceof String) { + mViewManager.setRefY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRefY(view, (Double) value); + } else { + mViewManager.setRefY(view, (Double) null); + } + break; + case "markerHeight": + if (value instanceof String) { + mViewManager.setMarkerHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setMarkerHeight(view, (Double) value); + } else { + mViewManager.setMarkerHeight(view, (Double) null); + } + break; + case "markerWidth": + if (value instanceof String) { + mViewManager.setMarkerWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setMarkerWidth(view, (Double) value); + } else { + mViewManager.setMarkerWidth(view, (Double) null); + } + break; + case "markerUnits": + mViewManager.setMarkerUnits(view, value == null ? null : (String) value); + break; + case "orient": + mViewManager.setOrient(view, value == null ? null : (String) value); + break; + case "minX": + mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "minY": + mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vbWidth": + mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vbHeight": + mViewManager.setVbHeight(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "align": + mViewManager.setAlign(view, value == null ? null : (String) value); + break; + case "meetOrSlice": + mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMarkerManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMarkerManagerInterface.java new file mode 100644 index 00000000000000..1ccc2986a3b185 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMarkerManagerInterface.java @@ -0,0 +1,65 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGMarkerManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setRefX(T view, @Nullable String value); + void setRefX(T view, @Nullable Double value); + void setRefY(T view, @Nullable String value); + void setRefY(T view, @Nullable Double value); + void setMarkerHeight(T view, @Nullable String value); + void setMarkerHeight(T view, @Nullable Double value); + void setMarkerWidth(T view, @Nullable String value); + void setMarkerWidth(T view, @Nullable Double value); + void setMarkerUnits(T view, @Nullable String value); + void setOrient(T view, @Nullable String value); + void setMinX(T view, float value); + void setMinY(T view, float value); + void setVbWidth(T view, float value); + void setVbHeight(T view, float value); + void setAlign(T view, @Nullable String value); + void setMeetOrSlice(T view, int value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java new file mode 100644 index 00000000000000..67c9bbcf6c3454 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java @@ -0,0 +1,174 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGMaskManagerDelegate & RNSVGMaskManagerInterface> extends BaseViewManagerDelegate { + public RNSVGMaskManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "x": + if (value instanceof String) { + mViewManager.setX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX(view, (Double) value); + } else { + mViewManager.setX(view, (Double) null); + } + break; + case "y": + if (value instanceof String) { + mViewManager.setY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY(view, (Double) value); + } else { + mViewManager.setY(view, (Double) null); + } + break; + case "height": + if (value instanceof String) { + mViewManager.setHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setHeight(view, (Double) value); + } else { + mViewManager.setHeight(view, (Double) null); + } + break; + case "width": + if (value instanceof String) { + mViewManager.setWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setWidth(view, (Double) value); + } else { + mViewManager.setWidth(view, (Double) null); + } + break; + case "maskUnits": + mViewManager.setMaskUnits(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "maskContentUnits": + mViewManager.setMaskContentUnits(view, value == null ? 0 : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMaskManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMaskManagerInterface.java new file mode 100644 index 00000000000000..07a1a02427ba48 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGMaskManagerInterface.java @@ -0,0 +1,59 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGMaskManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setX(T view, @Nullable String value); + void setX(T view, @Nullable Double value); + void setY(T view, @Nullable String value); + void setY(T view, @Nullable Double value); + void setHeight(T view, @Nullable String value); + void setHeight(T view, @Nullable Double value); + void setWidth(T view, @Nullable String value); + void setWidth(T view, @Nullable Double value); + void setMaskUnits(T view, int value); + void setMaskContentUnits(T view, int value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java new file mode 100644 index 00000000000000..3ed523c6228b86 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java @@ -0,0 +1,114 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGPathManagerDelegate & RNSVGPathManagerInterface> extends BaseViewManagerDelegate { + public RNSVGPathManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "d": + mViewManager.setD(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPathManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPathManagerInterface.java new file mode 100644 index 00000000000000..5473fa502719fe --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPathManagerInterface.java @@ -0,0 +1,45 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGPathManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setD(T view, @Nullable String value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java new file mode 100644 index 00000000000000..a9a059c1701d7f --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java @@ -0,0 +1,195 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGPatternManagerDelegate & RNSVGPatternManagerInterface> extends BaseViewManagerDelegate { + public RNSVGPatternManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "x": + if (value instanceof String) { + mViewManager.setX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX(view, (Double) value); + } else { + mViewManager.setX(view, (Double) null); + } + break; + case "y": + if (value instanceof String) { + mViewManager.setY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY(view, (Double) value); + } else { + mViewManager.setY(view, (Double) null); + } + break; + case "height": + if (value instanceof String) { + mViewManager.setHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setHeight(view, (Double) value); + } else { + mViewManager.setHeight(view, (Double) null); + } + break; + case "width": + if (value instanceof String) { + mViewManager.setWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setWidth(view, (Double) value); + } else { + mViewManager.setWidth(view, (Double) null); + } + break; + case "patternUnits": + mViewManager.setPatternUnits(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "patternContentUnits": + mViewManager.setPatternContentUnits(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "patternTransform": + mViewManager.setPatternTransform(view, (ReadableArray) value); + break; + case "minX": + mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "minY": + mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vbWidth": + mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vbHeight": + mViewManager.setVbHeight(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "align": + mViewManager.setAlign(view, value == null ? null : (String) value); + break; + case "meetOrSlice": + mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPatternManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPatternManagerInterface.java new file mode 100644 index 00000000000000..784de613bce54b --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGPatternManagerInterface.java @@ -0,0 +1,66 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGPatternManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setX(T view, @Nullable String value); + void setX(T view, @Nullable Double value); + void setY(T view, @Nullable String value); + void setY(T view, @Nullable Double value); + void setHeight(T view, @Nullable String value); + void setHeight(T view, @Nullable Double value); + void setWidth(T view, @Nullable String value); + void setWidth(T view, @Nullable Double value); + void setPatternUnits(T view, int value); + void setPatternContentUnits(T view, int value); + void setPatternTransform(T view, @Nullable ReadableArray value); + void setMinX(T view, float value); + void setMinY(T view, float value); + void setVbWidth(T view, float value); + void setVbHeight(T view, float value); + void setAlign(T view, @Nullable String value); + void setMeetOrSlice(T view, int value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerDelegate.java new file mode 100644 index 00000000000000..21a6a06b5faf49 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerDelegate.java @@ -0,0 +1,128 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGRadialGradientManagerDelegate & RNSVGRadialGradientManagerInterface> extends BaseViewManagerDelegate { + public RNSVGRadialGradientManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fx": + if (value instanceof String) { + mViewManager.setFx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFx(view, (Double) value); + } else { + mViewManager.setFx(view, (Double) null); + } + break; + case "fy": + if (value instanceof String) { + mViewManager.setFy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFy(view, (Double) value); + } else { + mViewManager.setFy(view, (Double) null); + } + break; + case "cx": + if (value instanceof String) { + mViewManager.setCx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setCx(view, (Double) value); + } else { + mViewManager.setCx(view, (Double) null); + } + break; + case "cy": + if (value instanceof String) { + mViewManager.setCy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setCy(view, (Double) value); + } else { + mViewManager.setCy(view, (Double) null); + } + break; + case "rx": + if (value instanceof String) { + mViewManager.setRx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRx(view, (Double) value); + } else { + mViewManager.setRx(view, (Double) null); + } + break; + case "ry": + if (value instanceof String) { + mViewManager.setRy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRy(view, (Double) value); + } else { + mViewManager.setRy(view, (Double) null); + } + break; + case "gradient": + mViewManager.setGradient(view, (ReadableArray) value); + break; + case "gradientUnits": + mViewManager.setGradientUnits(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "gradientTransform": + mViewManager.setGradientTransform(view, (ReadableArray) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerInterface.java new file mode 100644 index 00000000000000..5e6a7f4224e406 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerInterface.java @@ -0,0 +1,44 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; + +public interface RNSVGRadialGradientManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFx(T view, @Nullable String value); + void setFx(T view, @Nullable Double value); + void setFy(T view, @Nullable String value); + void setFy(T view, @Nullable Double value); + void setCx(T view, @Nullable String value); + void setCx(T view, @Nullable Double value); + void setCy(T view, @Nullable String value); + void setCy(T view, @Nullable Double value); + void setRx(T view, @Nullable String value); + void setRx(T view, @Nullable Double value); + void setRy(T view, @Nullable String value); + void setRy(T view, @Nullable Double value); + void setGradient(T view, @Nullable ReadableArray value); + void setGradientUnits(T view, int value); + void setGradientTransform(T view, @Nullable ReadableArray value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java new file mode 100644 index 00000000000000..4a3cac82a14a0f --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java @@ -0,0 +1,165 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGRectManagerDelegate & RNSVGRectManagerInterface> extends BaseViewManagerDelegate { + public RNSVGRectManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "x": + if (value instanceof String) { + mViewManager.setX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX(view, (Double) value); + } else { + mViewManager.setX(view, (Double) null); + } + break; + case "y": + if (value instanceof String) { + mViewManager.setY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY(view, (Double) value); + } else { + mViewManager.setY(view, (Double) null); + } + break; + case "height": + if (value instanceof String) { + mViewManager.setHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setHeight(view, (Double) value); + } else { + mViewManager.setHeight(view, (Double) null); + } + break; + case "width": + if (value instanceof String) { + mViewManager.setWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setWidth(view, (Double) value); + } else { + mViewManager.setWidth(view, (Double) null); + } + break; + case "rx": + if (value instanceof String) { + mViewManager.setRx(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRx(view, (Double) value); + } else { + mViewManager.setRx(view, (Double) null); + } + break; + case "ry": + if (value instanceof String) { + mViewManager.setRy(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setRy(view, (Double) value); + } else { + mViewManager.setRy(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRectManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRectManagerInterface.java new file mode 100644 index 00000000000000..47fb8a3413b2da --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGRectManagerInterface.java @@ -0,0 +1,56 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGRectManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setX(T view, @Nullable String value); + void setX(T view, @Nullable Double value); + void setY(T view, @Nullable String value); + void setY(T view, @Nullable Double value); + void setHeight(T view, @Nullable String value); + void setHeight(T view, @Nullable Double value); + void setWidth(T view, @Nullable String value); + void setWidth(T view, @Nullable Double value); + void setRx(T view, @Nullable String value); + void setRx(T view, @Nullable Double value); + void setRy(T view, @Nullable String value); + void setRy(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerDelegate.java new file mode 100644 index 00000000000000..1d55f5514c2eab --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerDelegate.java @@ -0,0 +1,168 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ColorPropConverter; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGSvgViewAndroidManagerDelegate & RNSVGSvgViewAndroidManagerInterface> extends BaseViewManagerDelegate { + public RNSVGSvgViewAndroidManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "bbWidth": + if (value instanceof String) { + mViewManager.setBbWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setBbWidth(view, (Double) value); + } else { + mViewManager.setBbWidth(view, (Double) null); + } + break; + case "bbHeight": + if (value instanceof String) { + mViewManager.setBbHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setBbHeight(view, (Double) value); + } else { + mViewManager.setBbHeight(view, (Double) null); + } + break; + case "minX": + mViewManager.setMinX(view, value == null ? Float.NaN : ((Double) value).floatValue()); + break; + case "minY": + mViewManager.setMinY(view, value == null ? Float.NaN : ((Double) value).floatValue()); + break; + case "vbWidth": + mViewManager.setVbWidth(view, value == null ? Float.NaN : ((Double) value).floatValue()); + break; + case "vbHeight": + mViewManager.setVbHeight(view, value == null ? Float.NaN : ((Double) value).floatValue()); + break; + case "align": + mViewManager.setAlign(view, value == null ? null : (String) value); + break; + case "meetOrSlice": + mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "tintColor": + mViewManager.setTintColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "color": + mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "hasTVPreferredFocus": + mViewManager.setHasTVPreferredFocus(view, value == null ? false : (boolean) value); + break; + case "borderTopEndRadius": + mViewManager.setBorderTopEndRadius(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "borderBottomStartRadius": + mViewManager.setBorderBottomStartRadius(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "borderBottomColor": + mViewManager.setBorderBottomColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "nextFocusDown": + mViewManager.setNextFocusDown(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "borderRightColor": + mViewManager.setBorderRightColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "nextFocusRight": + mViewManager.setNextFocusRight(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "borderLeftColor": + mViewManager.setBorderLeftColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "borderColor": + mViewManager.setBorderColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "removeClippedSubviews": + mViewManager.setRemoveClippedSubviews(view, value == null ? false : (boolean) value); + break; + case "nextFocusForward": + mViewManager.setNextFocusForward(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "nextFocusUp": + mViewManager.setNextFocusUp(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "accessible": + mViewManager.setAccessible(view, value == null ? false : (boolean) value); + break; + case "borderStartColor": + mViewManager.setBorderStartColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "borderBottomEndRadius": + mViewManager.setBorderBottomEndRadius(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "borderEndColor": + mViewManager.setBorderEndColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "focusable": + mViewManager.setFocusable(view, value == null ? false : (boolean) value); + break; + case "nativeBackgroundAndroid": + mViewManager.setNativeBackgroundAndroid(view, (ReadableMap) value); + break; + case "borderTopStartRadius": + mViewManager.setBorderTopStartRadius(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "nativeForegroundAndroid": + mViewManager.setNativeForegroundAndroid(view, (ReadableMap) value); + break; + case "backfaceVisibility": + mViewManager.setBackfaceVisibility(view, value == null ? null : (String) value); + break; + case "borderStyle": + mViewManager.setBorderStyle(view, value == null ? null : (String) value); + break; + case "needsOffscreenAlphaCompositing": + mViewManager.setNeedsOffscreenAlphaCompositing(view, value == null ? false : (boolean) value); + break; + case "hitSlop": + mViewManager.setHitSlop(view, (ReadableMap) value); + break; + case "borderTopColor": + mViewManager.setBorderTopColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "nextFocusLeft": + mViewManager.setNextFocusLeft(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "borderTopRightRadius": + mViewManager.setBorderTopRightRadius(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + case "borderBottomRightRadius": + mViewManager.setBorderBottomRightRadius(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + case "borderRadius": + mViewManager.setBorderRadius(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + case "borderBottomLeftRadius": + mViewManager.setBorderBottomLeftRadius(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + case "borderTopLeftRadius": + mViewManager.setBorderTopLeftRadius(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerInterface.java new file mode 100644 index 00000000000000..9e473fe7413dc8 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerInterface.java @@ -0,0 +1,61 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGSvgViewAndroidManagerInterface { + void setBbWidth(T view, @Nullable String value); + void setBbWidth(T view, @Nullable Double value); + void setBbHeight(T view, @Nullable String value); + void setBbHeight(T view, @Nullable Double value); + void setMinX(T view, float value); + void setMinY(T view, float value); + void setVbWidth(T view, float value); + void setVbHeight(T view, float value); + void setAlign(T view, @Nullable String value); + void setMeetOrSlice(T view, int value); + void setTintColor(T view, @Nullable Integer value); + void setColor(T view, @Nullable Integer value); + void setPointerEvents(T view, @Nullable String value); + void setHasTVPreferredFocus(T view, boolean value); + void setBorderTopEndRadius(T view, float value); + void setBorderBottomStartRadius(T view, float value); + void setBorderBottomColor(T view, @Nullable Integer value); + void setNextFocusDown(T view, int value); + void setBorderRightColor(T view, @Nullable Integer value); + void setNextFocusRight(T view, int value); + void setBorderLeftColor(T view, @Nullable Integer value); + void setBorderColor(T view, @Nullable Integer value); + void setRemoveClippedSubviews(T view, boolean value); + void setNextFocusForward(T view, int value); + void setNextFocusUp(T view, int value); + void setAccessible(T view, boolean value); + void setBorderStartColor(T view, @Nullable Integer value); + void setBorderBottomEndRadius(T view, float value); + void setBorderEndColor(T view, @Nullable Integer value); + void setFocusable(T view, boolean value); + void setNativeBackgroundAndroid(T view, @Nullable ReadableMap value); + void setBorderTopStartRadius(T view, float value); + void setNativeForegroundAndroid(T view, @Nullable ReadableMap value); + void setBackfaceVisibility(T view, @Nullable String value); + void setBorderStyle(T view, @Nullable String value); + void setNeedsOffscreenAlphaCompositing(T view, boolean value); + void setHitSlop(T view, @Nullable ReadableMap value); + void setBorderTopColor(T view, @Nullable Integer value); + void setNextFocusLeft(T view, int value); + void setBorderTopRightRadius(T view, double value); + void setBorderBottomRightRadius(T view, double value); + void setBorderRadius(T view, double value); + void setBorderBottomLeftRadius(T view, double value); + void setBorderTopLeftRadius(T view, double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java new file mode 100644 index 00000000000000..ca452fc08d67d7 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java @@ -0,0 +1,150 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGSymbolManagerDelegate & RNSVGSymbolManagerInterface> extends BaseViewManagerDelegate { + public RNSVGSymbolManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "minX": + mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "minY": + mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vbWidth": + mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vbHeight": + mViewManager.setVbHeight(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "align": + mViewManager.setAlign(view, value == null ? null : (String) value); + break; + case "meetOrSlice": + mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSymbolManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSymbolManagerInterface.java new file mode 100644 index 00000000000000..c32ccd4a3573d1 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGSymbolManagerInterface.java @@ -0,0 +1,55 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGSymbolManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setMinX(T view, float value); + void setMinY(T view, float value); + void setVbWidth(T view, float value); + void setVbHeight(T view, float value); + void setAlign(T view, @Nullable String value); + void setMeetOrSlice(T view, int value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java new file mode 100644 index 00000000000000..d90ed5b8635c6c --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java @@ -0,0 +1,186 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGTSpanManagerDelegate & RNSVGTSpanManagerInterface> extends BaseViewManagerDelegate { + public RNSVGTSpanManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "dx": + mViewManager.setDx(view, (ReadableArray) value); + break; + case "dy": + mViewManager.setDy(view, (ReadableArray) value); + break; + case "x": + mViewManager.setX(view, (ReadableArray) value); + break; + case "y": + mViewManager.setY(view, (ReadableArray) value); + break; + case "rotate": + mViewManager.setRotate(view, (ReadableArray) value); + break; + case "inlineSize": + if (value instanceof String) { + mViewManager.setInlineSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setInlineSize(view, (Double) value); + } else { + mViewManager.setInlineSize(view, (Double) null); + } + break; + case "textLength": + if (value instanceof String) { + mViewManager.setTextLength(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setTextLength(view, (Double) value); + } else { + mViewManager.setTextLength(view, (Double) null); + } + break; + case "baselineShift": + if (value instanceof String) { + mViewManager.setBaselineShift(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setBaselineShift(view, (Double) value); + } else { + mViewManager.setBaselineShift(view, (Double) null); + } + break; + case "lengthAdjust": + mViewManager.setLengthAdjust(view, value == null ? null : (String) value); + break; + case "alignmentBaseline": + mViewManager.setAlignmentBaseline(view, value == null ? null : (String) value); + break; + case "verticalAlign": + mViewManager.setVerticalAlign(view, value == null ? null : (String) value); + break; + case "content": + mViewManager.setContent(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTSpanManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTSpanManagerInterface.java new file mode 100644 index 00000000000000..df9568a82d63e1 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTSpanManagerInterface.java @@ -0,0 +1,64 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGTSpanManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setDx(T view, @Nullable ReadableArray value); + void setDy(T view, @Nullable ReadableArray value); + void setX(T view, @Nullable ReadableArray value); + void setY(T view, @Nullable ReadableArray value); + void setRotate(T view, @Nullable ReadableArray value); + void setInlineSize(T view, @Nullable String value); + void setInlineSize(T view, @Nullable Double value); + void setTextLength(T view, @Nullable String value); + void setTextLength(T view, @Nullable Double value); + void setBaselineShift(T view, @Nullable String value); + void setBaselineShift(T view, @Nullable Double value); + void setLengthAdjust(T view, @Nullable String value); + void setAlignmentBaseline(T view, @Nullable String value); + void setVerticalAlign(T view, @Nullable String value); + void setContent(T view, @Nullable String value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java new file mode 100644 index 00000000000000..d44811a415e0f4 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java @@ -0,0 +1,183 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGTextManagerDelegate & RNSVGTextManagerInterface> extends BaseViewManagerDelegate { + public RNSVGTextManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "dx": + mViewManager.setDx(view, (ReadableArray) value); + break; + case "dy": + mViewManager.setDy(view, (ReadableArray) value); + break; + case "x": + mViewManager.setX(view, (ReadableArray) value); + break; + case "y": + mViewManager.setY(view, (ReadableArray) value); + break; + case "rotate": + mViewManager.setRotate(view, (ReadableArray) value); + break; + case "inlineSize": + if (value instanceof String) { + mViewManager.setInlineSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setInlineSize(view, (Double) value); + } else { + mViewManager.setInlineSize(view, (Double) null); + } + break; + case "textLength": + if (value instanceof String) { + mViewManager.setTextLength(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setTextLength(view, (Double) value); + } else { + mViewManager.setTextLength(view, (Double) null); + } + break; + case "baselineShift": + if (value instanceof String) { + mViewManager.setBaselineShift(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setBaselineShift(view, (Double) value); + } else { + mViewManager.setBaselineShift(view, (Double) null); + } + break; + case "lengthAdjust": + mViewManager.setLengthAdjust(view, value == null ? null : (String) value); + break; + case "alignmentBaseline": + mViewManager.setAlignmentBaseline(view, value == null ? null : (String) value); + break; + case "verticalAlign": + mViewManager.setVerticalAlign(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextManagerInterface.java new file mode 100644 index 00000000000000..eca3270ad92c54 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextManagerInterface.java @@ -0,0 +1,63 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGTextManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setDx(T view, @Nullable ReadableArray value); + void setDy(T view, @Nullable ReadableArray value); + void setX(T view, @Nullable ReadableArray value); + void setY(T view, @Nullable ReadableArray value); + void setRotate(T view, @Nullable ReadableArray value); + void setInlineSize(T view, @Nullable String value); + void setInlineSize(T view, @Nullable Double value); + void setTextLength(T view, @Nullable String value); + void setTextLength(T view, @Nullable Double value); + void setBaselineShift(T view, @Nullable String value); + void setBaselineShift(T view, @Nullable Double value); + void setLengthAdjust(T view, @Nullable String value); + void setAlignmentBaseline(T view, @Nullable String value); + void setVerticalAlign(T view, @Nullable String value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java new file mode 100644 index 00000000000000..1fb365bee462e7 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java @@ -0,0 +1,207 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGTextPathManagerDelegate & RNSVGTextPathManagerInterface> extends BaseViewManagerDelegate { + public RNSVGTextPathManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "fontSize": + if (value instanceof String) { + mViewManager.setFontSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontSize(view, (Double) value); + } else { + mViewManager.setFontSize(view, (Double) null); + } + break; + case "fontWeight": + if (value instanceof String) { + mViewManager.setFontWeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setFontWeight(view, (Double) value); + } else { + mViewManager.setFontWeight(view, (Double) null); + } + break; + case "font": + mViewManager.setFont(view, (ReadableMap) value); + break; + case "dx": + mViewManager.setDx(view, (ReadableArray) value); + break; + case "dy": + mViewManager.setDy(view, (ReadableArray) value); + break; + case "x": + mViewManager.setX(view, (ReadableArray) value); + break; + case "y": + mViewManager.setY(view, (ReadableArray) value); + break; + case "rotate": + mViewManager.setRotate(view, (ReadableArray) value); + break; + case "inlineSize": + if (value instanceof String) { + mViewManager.setInlineSize(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setInlineSize(view, (Double) value); + } else { + mViewManager.setInlineSize(view, (Double) null); + } + break; + case "textLength": + if (value instanceof String) { + mViewManager.setTextLength(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setTextLength(view, (Double) value); + } else { + mViewManager.setTextLength(view, (Double) null); + } + break; + case "baselineShift": + if (value instanceof String) { + mViewManager.setBaselineShift(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setBaselineShift(view, (Double) value); + } else { + mViewManager.setBaselineShift(view, (Double) null); + } + break; + case "lengthAdjust": + mViewManager.setLengthAdjust(view, value == null ? null : (String) value); + break; + case "alignmentBaseline": + mViewManager.setAlignmentBaseline(view, value == null ? null : (String) value); + break; + case "verticalAlign": + mViewManager.setVerticalAlign(view, value == null ? null : (String) value); + break; + case "href": + mViewManager.setHref(view, value == null ? null : (String) value); + break; + case "side": + mViewManager.setSide(view, value == null ? null : (String) value); + break; + case "method": + mViewManager.setMethod(view, value == null ? null : (String) value); + break; + case "midLine": + mViewManager.setMidLine(view, value == null ? null : (String) value); + break; + case "spacing": + mViewManager.setSpacing(view, value == null ? null : (String) value); + break; + case "startOffset": + if (value instanceof String) { + mViewManager.setStartOffset(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStartOffset(view, (Double) value); + } else { + mViewManager.setStartOffset(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextPathManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextPathManagerInterface.java new file mode 100644 index 00000000000000..2e4887e90f088b --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGTextPathManagerInterface.java @@ -0,0 +1,70 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGTextPathManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setFontSize(T view, @Nullable String value); + void setFontSize(T view, @Nullable Double value); + void setFontWeight(T view, @Nullable String value); + void setFontWeight(T view, @Nullable Double value); + void setFont(T view, @Nullable ReadableMap value); + void setDx(T view, @Nullable ReadableArray value); + void setDy(T view, @Nullable ReadableArray value); + void setX(T view, @Nullable ReadableArray value); + void setY(T view, @Nullable ReadableArray value); + void setRotate(T view, @Nullable ReadableArray value); + void setInlineSize(T view, @Nullable String value); + void setInlineSize(T view, @Nullable Double value); + void setTextLength(T view, @Nullable String value); + void setTextLength(T view, @Nullable Double value); + void setBaselineShift(T view, @Nullable String value); + void setBaselineShift(T view, @Nullable Double value); + void setLengthAdjust(T view, @Nullable String value); + void setAlignmentBaseline(T view, @Nullable String value); + void setVerticalAlign(T view, @Nullable String value); + void setHref(T view, @Nullable String value); + void setSide(T view, @Nullable String value); + void setMethod(T view, @Nullable String value); + void setMidLine(T view, @Nullable String value); + void setSpacing(T view, @Nullable String value); + void setStartOffset(T view, @Nullable String value); + void setStartOffset(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java new file mode 100644 index 00000000000000..f91d39a7cad942 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java @@ -0,0 +1,150 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerDelegate; +import abi49_0_0.com.facebook.react.uimanager.BaseViewManagerInterface; + +public class RNSVGUseManagerDelegate & RNSVGUseManagerInterface> extends BaseViewManagerDelegate { + public RNSVGUseManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? null : (String) value); + break; + case "opacity": + mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "matrix": + mViewManager.setMatrix(view, (ReadableArray) value); + break; + case "mask": + mViewManager.setMask(view, value == null ? null : (String) value); + break; + case "markerStart": + mViewManager.setMarkerStart(view, value == null ? null : (String) value); + break; + case "markerMid": + mViewManager.setMarkerMid(view, value == null ? null : (String) value); + break; + case "markerEnd": + mViewManager.setMarkerEnd(view, value == null ? null : (String) value); + break; + case "clipPath": + mViewManager.setClipPath(view, value == null ? null : (String) value); + break; + case "clipRule": + mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "responsible": + mViewManager.setResponsible(view, value == null ? false : (boolean) value); + break; + case "display": + mViewManager.setDisplay(view, value == null ? null : (String) value); + break; + case "pointerEvents": + mViewManager.setPointerEvents(view, value == null ? null : (String) value); + break; + case "fill": + mViewManager.setFill(view, (ReadableMap) value); + break; + case "fillOpacity": + mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "fillRule": + mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "stroke": + mViewManager.setStroke(view, (ReadableMap) value); + break; + case "strokeOpacity": + mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "strokeWidth": + if (value instanceof String) { + mViewManager.setStrokeWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setStrokeWidth(view, (Double) value); + } else { + mViewManager.setStrokeWidth(view, "1"); + } + break; + case "strokeLinecap": + mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeLinejoin": + mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "strokeDasharray": + mViewManager.setStrokeDasharray(view, (ReadableArray) value); + break; + case "strokeDashoffset": + mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "strokeMiterlimit": + mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "vectorEffect": + mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "propList": + mViewManager.setPropList(view, (ReadableArray) value); + break; + case "href": + mViewManager.setHref(view, value == null ? null : (String) value); + break; + case "x": + if (value instanceof String) { + mViewManager.setX(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setX(view, (Double) value); + } else { + mViewManager.setX(view, (Double) null); + } + break; + case "y": + if (value instanceof String) { + mViewManager.setY(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setY(view, (Double) value); + } else { + mViewManager.setY(view, (Double) null); + } + break; + case "height": + if (value instanceof String) { + mViewManager.setHeight(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setHeight(view, (Double) value); + } else { + mViewManager.setHeight(view, (Double) null); + } + break; + case "width": + if (value instanceof String) { + mViewManager.setWidth(view, (String) value); + } else if (value instanceof Double) { + mViewManager.setWidth(view, (Double) value); + } else { + mViewManager.setWidth(view, (Double) null); + } + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGUseManagerInterface.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGUseManagerInterface.java new file mode 100644 index 00000000000000..afd6ede379bd45 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/facebook/react/viewmanagers/RNSVGUseManagerInterface.java @@ -0,0 +1,53 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package abi49_0_0.com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public interface RNSVGUseManagerInterface { + void setName(T view, @Nullable String value); + void setOpacity(T view, float value); + void setMatrix(T view, @Nullable ReadableArray value); + void setMask(T view, @Nullable String value); + void setMarkerStart(T view, @Nullable String value); + void setMarkerMid(T view, @Nullable String value); + void setMarkerEnd(T view, @Nullable String value); + void setClipPath(T view, @Nullable String value); + void setClipRule(T view, int value); + void setResponsible(T view, boolean value); + void setDisplay(T view, @Nullable String value); + void setPointerEvents(T view, @Nullable String value); + void setFill(T view, @Nullable ReadableMap value); + void setFillOpacity(T view, float value); + void setFillRule(T view, int value); + void setStroke(T view, @Nullable ReadableMap value); + void setStrokeOpacity(T view, float value); + void setStrokeWidth(T view, @Nullable String value); + void setStrokeWidth(T view, @Nullable Double value); + void setStrokeLinecap(T view, int value); + void setStrokeLinejoin(T view, int value); + void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDashoffset(T view, float value); + void setStrokeMiterlimit(T view, float value); + void setVectorEffect(T view, int value); + void setPropList(T view, @Nullable ReadableArray value); + void setHref(T view, @Nullable String value); + void setX(T view, @Nullable String value); + void setX(T view, @Nullable Double value); + void setY(T view, @Nullable String value); + void setY(T view, @Nullable Double value); + void setHeight(T view, @Nullable String value); + void setHeight(T view, @Nullable Double value); + void setWidth(T view, @Nullable String value); + void setWidth(T view, @Nullable Double value); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/horcrux/svg/NativeSvgRenderableModuleSpec.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/horcrux/svg/NativeSvgRenderableModuleSpec.java new file mode 100644 index 00000000000000..b552c4ce1987bc --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/horcrux/svg/NativeSvgRenderableModuleSpec.java @@ -0,0 +1,57 @@ +/** + * This code was generated by + * [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + *

Do not edit this file as changes may cause incorrect behavior and will be lost once the code + * is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * @nolint + */ +package abi49_0_0.com.horcrux.rnsvg; + +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.Promise; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.WritableMap; + +public abstract class NativeSvgRenderableModuleSpec extends ReactContextBaseJavaModule { + public NativeSvgRenderableModuleSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract boolean isPointInFill(Double tag, ReadableMap options); + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract boolean isPointInStroke(Double tag, ReadableMap options); + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract double getTotalLength(Double tag); + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract WritableMap getPointAtLength(Double tag, ReadableMap options); + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract WritableMap getBBox(Double tag, ReadableMap options); + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract WritableMap getCTM(Double tag); + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract WritableMap getScreenCTM(Double tag); + + @ReactMethod + @DoNotStrip + public abstract void getRawResource(String name, Promise promise); +} diff --git a/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/horcrux/svg/NativeSvgViewModuleSpec.java b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/horcrux/svg/NativeSvgViewModuleSpec.java new file mode 100644 index 00000000000000..5dc0c558ad86f9 --- /dev/null +++ b/android/vendored/sdk49/react-native-svg/android/src/paper/java/abi49_0_0/com/horcrux/svg/NativeSvgViewModuleSpec.java @@ -0,0 +1,28 @@ +/** + * This code was generated by + * [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + *

Do not edit this file as changes may cause incorrect behavior and will be lost once the code + * is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * @nolint + */ +package abi49_0_0.com.horcrux.rnsvg; + +import com.facebook.proguard.annotations.DoNotStrip; +import abi49_0_0.com.facebook.react.bridge.Callback; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; + +public abstract class NativeSvgViewModuleSpec extends ReactContextBaseJavaModule { + public NativeSvgViewModuleSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @ReactMethod + @DoNotStrip + public abstract void toDataURL(Double tag, ReadableMap options, Callback callback); +} diff --git a/android/versioned-abis/expoview-abi49_0_0/build.gradle b/android/versioned-abis/expoview-abi49_0_0/build.gradle new file mode 100644 index 00000000000000..b958250c065a06 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/build.gradle @@ -0,0 +1,233 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'maven-publish' +apply plugin: 'de.undercouch.download' +apply plugin: 'kotlin-kapt' +apply from: new File(rootDir, "versioning_linking.gradle") + +def reactProperties = new Properties() +file("${project(':packages:react-native:ReactAndroid').projectDir}/gradle.properties").withInputStream { reactProperties.load(it) } + + +def prebuiltHermesDir = findProperty("expo.prebuiltHermesDir") ?: file("${rootDir}/prebuiltHermes") +def prebuiltHermesVersion = file("${prebuiltHermesDir}/.hermesversion").exists() ? file("${prebuiltHermesDir}/.hermesversion").text : null +def currentHermesVersion = file("${project(':packages:react-native:ReactAndroid').projectDir}/../sdks/.hermesversion").exists() ? file("${project(':packages:react-native:ReactAndroid').projectDir}/../sdks/.hermesversion").text : null +def buildHermesSource = currentHermesVersion != prebuiltHermesVersion +logger.info(":expoview - buildHermesSource[${buildHermesSource}]") + +buildscript { + // Simple helper that allows the root project to override versions declared by this library. + ext.safeExtGet = { prop, fallback -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback + } + + repositories { + mavenCentral() + google() + maven { url "https://jitpack.io" } + } + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.6.10')}") + } +} + +repositories { + mavenCentral() + maven { url "https://jitpack.io" } +} + +android { + compileSdkVersion safeExtGet("compileSdkVersion", 33) + + // Used to override the NDK path/version on internal CI or by allowing + // users to customize the NDK path/version from their root project (e.g. for M1 support) + if (rootProject.hasProperty("ndkPath")) { + ndkPath rootProject.ext.ndkPath + } + if (rootProject.hasProperty("ndkVersion")) { + ndkVersion rootProject.ext.ndkVersion + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.majorVersion + } + + buildFeatures { + viewBinding true + } + + defaultConfig { + minSdkVersion safeExtGet("minSdkVersion", 21) + targetSdkVersion safeExtGet("targetSdkVersion", 33) + versionCode 1 + versionName "1.0" + + missingDimensionStrategy('versioning', 'versioned') + + } + + buildTypes { + release { + consumerProguardFiles('proguard-rules.pro') + } + } + + + // use `versionedRelease` configuration when publishing to maven + defaultPublishConfig "versionedRelease" + + publishing { + singleVariant("release") { + withSourcesJar() + } + } +} + + +dependencies { + api fileTree(dir: 'libs', include: ['*.jar']) + api 'androidx.multidex:multidex:2.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" + + testImplementation 'junit:junit:4.13.2' + + implementation project(":expoview") + + + // React native dependencies + api("androidx.appcompat:appcompat-resources:${reactProperties.getProperty('ANDROIDX_APPCOMPAT_VERSION')}") + api("androidx.appcompat:appcompat:${reactProperties.getProperty('ANDROIDX_APPCOMPAT_VERSION')}") + api("androidx.autofill:autofill:${reactProperties.getProperty('ANDROIDX_AUTOFILL_VERSION')}") + api("androidx.swiperefreshlayout:swiperefreshlayout:${reactProperties.getProperty('SWIPEREFRESH_LAYOUT_VERSION')}") + + api("com.facebook.fbjni:fbjni:${reactProperties.getProperty('FBJNI_VERSION')}") + api("com.facebook.fresco:fresco:${reactProperties.getProperty('FRESCO_VERSION')}") + api("com.facebook.fresco:imagepipeline-okhttp3:${reactProperties.getProperty('FRESCO_VERSION')}") + api("com.facebook.fresco:ui-common:${reactProperties.getProperty('FRESCO_VERSION')}") + api("com.facebook.infer.annotation:infer-annotation:${reactProperties.getProperty('INFER_ANNOTATIONS_VERSION')}") + api("com.facebook.soloader:soloader:${reactProperties.getProperty('SO_LOADER_VERSION')}") + api("com.facebook.yoga:proguard-annotations:${reactProperties.getProperty('PROGUARD_ANNOTATIONS_VERSION')}") + + api("com.google.code.findbugs:jsr305:${reactProperties.getProperty('JSR305_VERSION')}") + api("com.squareup.okhttp3:okhttp-urlconnection:${reactProperties.getProperty('OKHTTP_VERSION')}") + api("com.squareup.okhttp3:okhttp:${reactProperties.getProperty('OKHTTP_VERSION')}") + api("com.squareup.okio:okio:${reactProperties.getProperty('OKIO_VERSION')}") + api("javax.inject:javax.inject:${reactProperties.getProperty('JAVAX_INJECT_VERSION')}") + + // Our dependencies + compileOnly 'org.glassfish:javax.annotation:3.1.1' + api 'de.greenrobot:eventbus:2.4.0' + api 'com.google.firebase:firebase-crashlytics:18.3.6' + api 'com.google.firebase:firebase-crashlytics-ndk:18.3.6' + api "androidx.room:room-runtime:2.1.0" + + api("com.facebook.fresco:animated-gif:${reactProperties.getProperty('FRESCO_VERSION')}") + api("com.facebook.fresco:animated-webp:${reactProperties.getProperty('FRESCO_VERSION')}") + api("com.facebook.fresco:webpsupport:${reactProperties.getProperty('FRESCO_VERSION')}") + + api 'com.squareup.picasso:picasso:2.5.2' + api 'com.google.android.gms:play-services-analytics:17.0.0' + api 'com.google.android.gms:play-services-maps:18.0.1' + api 'com.google.android.gms:play-services-auth:17.0.0' + api 'com.google.android.gms:play-services-location:20.0.0' + api 'com.google.android.gms:play-services-fitness:17.0.0' + api 'com.google.android.gms:play-services-wallet:17.0.0' //may need 10.+ + debugApi 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1' + // debugApi 'com.squareup.leakcanary:leakcanary-android:1.4-beta1' + releaseApi 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1' + api 'commons-io:commons-io:2.6' + api 'me.leolin:ShortcutBadger:1.1.4@aar' + implementation "com.github.CanHub:Android-Image-Cropper:4.3.0" + api 'commons-codec:commons-codec:1.10' + api 'net.openid:appauth:0.7.1' + api 'com.airbnb.android:lottie:3.4.0' + compileOnly 'io.branch.sdk.android:library:4.1.0' + api "androidx.exifinterface:exifinterface:1.0.0" + api "androidx.legacy:legacy-support-v4:1.0.0" + api "androidx.browser:browser:1.0.0" + + // expo-face-detector + implementation 'com.google.mlkit:face-detection:16.1.5' + + // expo-ads-admob + implementation 'com.google.android.gms:play-services-ads:20.5.0' + // For apps targeting Android 12, add WorkManager dependency. + // See more at https://developers.google.com/admob/android/rel-notes + constraints { + implementation('androidx.work:work-runtime:2.7.0') { + because '''androidx.work:work-runtime:2.1.0 pulled from + play-services-ads has a bug using PendingIntent without + FLAG_IMMUTABLE or FLAG_MUTABLE and will fail in Apps + targeting S+.''' + } + } + + api 'com.google.firebase:firebase-core:21.1.0' + api 'com.google.firebase:firebase-messaging:22.0.0' + api 'com.google.maps.android:android-maps-utils:3.4.0' + // Remember to update DetachAppTemplate build.gradle if you add any excludes or transitive = false here! + + // expo-file-system + api 'com.squareup.okhttp3:okhttp:3.10.0' + api 'com.squareup.okhttp3:okhttp-urlconnection:3.10.0' + + // expo-av + // See explanation in expo-av/build.gradle + api 'com.google.android.exoplayer:extension-okhttp:2.18.1' + + // expo-application + api 'com.android.installreferrer:installreferrer:1.0' + + // expo-blur + implementation 'com.github.Dimezis:BlurView:version-2.0.3' + + // expo-modules-core android-annotation + api project(':expo-modules-core$android-annotation') + + // expo-store-review + implementation "com.google.android.play:review:2.0.1" + implementation "com.google.android.play:review-ktx:2.0.0" + + // expo-image + def GLIDE_VERSION = "4.13.2" + implementation "com.github.zjupure:webpdecoder:2.1.${GLIDE_VERSION}" + api "com.github.bumptech.glide:glide:${GLIDE_VERSION}" + kapt "com.github.bumptech.glide:compiler:${GLIDE_VERSION}" + implementation "com.github.bumptech.glide:avif-integration:${GLIDE_VERSION}" + implementation "jp.wasabeef:glide-transformations:4.3.0" + + //dbflow + kapt "com.github.Raizlabs.DBFlow:dbflow-processor:${safeExtGet('dbFlowVersion', '4.2.4')}" + implementation "com.github.Raizlabs.DBFlow:dbflow-core:${safeExtGet('dbFlowVersion', '4.2.4')}" + implementation "com.github.Raizlabs.DBFlow:dbflow:${safeExtGet('dbFlowVersion', '4.2.4')}" + + implementation 'com.cronutils:cron-utils:4.1.3' + + // @react-native-community/viewpager + api 'com.github.troZee:ViewPager2:v1.0.6' + + // stripe-react-native + implementation('com.stripe:stripe-android:20.25.+') + implementation('com.stripe:financial-connections:20.25.+') + compileOnly 'com.stripe:stripe-android-issuing-push-provisioning:1.1.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1" + implementation 'com.google.android.material:material:1.3.0' + + // react-native-webview + implementation "androidx.webkit:webkit:1.4.0" + + // expo-updates + implementation 'org.bouncycastle:bcutil-jdk15to18:1.70' + + // react-native-maps + implementation "androidx.work:work-runtime:2.7.1" +} + +useVendoredModulesForExpoView('sdk49') diff --git a/android/versioned-abis/expoview-abi49_0_0/empty.cpp b/android/versioned-abis/expoview-abi49_0_0/empty.cpp new file mode 100644 index 00000000000000..8d50bb2809009d --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/empty.cpp @@ -0,0 +1 @@ +// required for compilation purpose diff --git a/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/1.0.0/_remote.repositories b/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/1.0.0/_remote.repositories new file mode 100644 index 00000000000000..781e505ce47fe3 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/1.0.0/_remote.repositories @@ -0,0 +1,4 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +#Mon Jun 26 23:41:01 CST 2023 +reactandroid-abi49_0_0-1.0.0.aar>= +reactandroid-abi49_0_0-1.0.0.pom>= diff --git a/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/1.0.0/reactandroid-abi49_0_0-1.0.0.pom b/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/1.0.0/reactandroid-abi49_0_0-1.0.0.pom new file mode 100644 index 00000000000000..ce514e39d9eeac --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/1.0.0/reactandroid-abi49_0_0-1.0.0.pom @@ -0,0 +1,10 @@ + + + 4.0.0 + host.exp + reactandroid-abi49_0_0 + 1.0.0 + aar + POM was created from install:install-file + diff --git a/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/maven-metadata-local.xml b/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/maven-metadata-local.xml new file mode 100644 index 00000000000000..f1567e244c76fb --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/maven/host/exp/reactandroid-abi49_0_0/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + host.exp + reactandroid-abi49_0_0 + + 1.0.0 + + 1.0.0 + + 20230626154101 + + diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/AndroidManifest.xml b/android/versioned-abis/expoview-abi49_0_0/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..c8f26bcef24c39 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/AndroidManifest.xml @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt new file mode 100644 index 00000000000000..b136eca863e027 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt @@ -0,0 +1,10 @@ +package abi49_0_0.com.facebook.react.uimanager + +import abi49_0_0.com.facebook.react.bridge.ReadableMap + +/** + * Access the package private property declared inside of [ReactStylesDiffMap] + */ +fun ReactStylesDiffMap.getBackingMap(): ReadableMap { + return mBackingMap +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/com/facebook/react/views/modal/RNGHModalUtils.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/com/facebook/react/views/modal/RNGHModalUtils.java new file mode 100644 index 00000000000000..62a18f58b5f6b8 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/com/facebook/react/views/modal/RNGHModalUtils.java @@ -0,0 +1,21 @@ +package abi49_0_0.com.facebook.react.views.modal; + +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.view.ViewParent; + +/** + * For handling gestures inside RNGH we need to have access to some methods of + * `ReactModalHostView.DialogRootViewGroup`. This class is not available outside + * package so this file exports important features. + */ + +public class RNGHModalUtils { + public static void dialogRootViewGroupOnChildStartedNativeGesture(ViewGroup modal, MotionEvent androidEvent) { + ((ReactModalHostView.DialogRootViewGroup) modal).onChildStartedNativeGesture(androidEvent); + } + + public static boolean isDialogRootViewGroup(ViewParent modal) { + return modal instanceof ReactModalHostView.DialogRootViewGroup; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ApplicationLifecycleDispatcher.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ApplicationLifecycleDispatcher.kt new file mode 100644 index 00000000000000..60b913f4acbcbf --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ApplicationLifecycleDispatcher.kt @@ -0,0 +1,27 @@ +package abi49_0_0.expo.modules + +import android.app.Application +import android.content.res.Configuration +import androidx.annotation.UiThread +import abi49_0_0.expo.modules.core.interfaces.ApplicationLifecycleListener + +object ApplicationLifecycleDispatcher { + private var listeners: List? = null + + @UiThread + private fun getCachedListeners(application: Application): List { + return listeners ?: ExpoModulesPackage.packageList + .flatMap { it.createApplicationLifecycleListeners(application) } + .also { listeners = it } + } + + @JvmStatic + fun onApplicationCreate(application: Application) { + getCachedListeners(application).forEach { it.onCreate(application) } + } + + @JvmStatic + fun onConfigurationChanged(application: Application, newConfig: Configuration) { + getCachedListeners(application).forEach { it.onConfigurationChanged(newConfig) } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ExpoModulesPackage.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ExpoModulesPackage.kt new file mode 100644 index 00000000000000..ba2ff2cf773cd7 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ExpoModulesPackage.kt @@ -0,0 +1,41 @@ +package abi49_0_0.expo.modules + +import android.util.Log + +import abi49_0_0.com.facebook.react.ReactPackage +import abi49_0_0.com.facebook.react.bridge.NativeModule +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import abi49_0_0.com.facebook.react.uimanager.ViewManager + +import abi49_0_0.expo.modules.adapters.react.ModuleRegistryAdapter +import abi49_0_0.expo.modules.core.ModulePriorities +import abi49_0_0.expo.modules.core.interfaces.Package + +import java.lang.Exception + +class ExpoModulesPackage : ReactPackage { + val moduleRegistryAdapter = ModuleRegistryAdapter(packageList) + + companion object { + @Suppress("unchecked_cast") + val packageList: List by lazy { + try { + val expoModules = Class.forName("expo.modules.ExpoModulesPackageList") + val getPackageList = expoModules.getMethod("getPackageList") + (getPackageList.invoke(null) as List) + .sortedByDescending { ModulePriorities.get(it::class.qualifiedName) } + } catch (e: Exception) { + Log.e("ExpoModulesPackage", "Couldn't get expo package list.", e) + emptyList() + } + } + } + + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return moduleRegistryAdapter.createNativeModules(reactContext) + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return moduleRegistryAdapter.createViewManagers(reactContext) + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ReactActivityDelegateWrapper.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ReactActivityDelegateWrapper.kt new file mode 100644 index 00000000000000..e75f14b94eea9a --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ReactActivityDelegateWrapper.kt @@ -0,0 +1,293 @@ +package abi49_0_0.expo.modules + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.KeyEvent +import android.view.ViewGroup +import androidx.collection.ArrayMap +import abi49_0_0.com.facebook.react.ReactActivity +import abi49_0_0.com.facebook.react.ReactActivityDelegate +import abi49_0_0.com.facebook.react.ReactDelegate +import abi49_0_0.com.facebook.react.ReactInstanceEventListener +import abi49_0_0.com.facebook.react.ReactInstanceManager +import abi49_0_0.com.facebook.react.ReactNativeHost +import abi49_0_0.com.facebook.react.ReactRootView +import abi49_0_0.com.facebook.react.bridge.ReactContext +import abi49_0_0.com.facebook.react.modules.core.PermissionListener +import abi49_0_0.expo.modules.core.interfaces.ReactActivityLifecycleListener +import java.lang.reflect.Field +import java.lang.reflect.Method +import java.lang.reflect.Modifier + +class ReactActivityDelegateWrapper( + private val activity: ReactActivity, + private val isNewArchitectureEnabled: Boolean, + private var delegate: ReactActivityDelegate +) : ReactActivityDelegate(activity, null) { + constructor(activity: ReactActivity, delegate: ReactActivityDelegate) : + this(activity, false, delegate) + + private val reactActivityLifecycleListeners = ExpoModulesPackage.packageList + .flatMap { it.createReactActivityLifecycleListeners(activity) } + private val reactActivityHandlers = ExpoModulesPackage.packageList + .flatMap { it.createReactActivityHandlers(activity) } + private val methodMap: ArrayMap = ArrayMap() + private val host: ReactNativeHost by lazy { + invokeDelegateMethod("getReactNativeHost") + } + /** + * When the app delay for `loadApp`, the ReactInstanceManager's lifecycle will be disrupted. + * This flag indicates we should emit `onResume` after `loadApp`. + */ + private var shouldEmitPendingResume = false + + //region ReactActivityDelegate + + override fun getLaunchOptions(): Bundle? { + return invokeDelegateMethod("getLaunchOptions") + } + + override fun createRootView(): ReactRootView { + val rootView = reactActivityHandlers.asSequence() + .mapNotNull { it.createReactRootView(activity) } + .firstOrNull() ?: invokeDelegateMethod("createRootView") + rootView.setIsFabric(isNewArchitectureEnabled) + return rootView + } + + override fun getReactNativeHost(): ReactNativeHost { + return host + } + + override fun getReactInstanceManager(): ReactInstanceManager { + return delegate.reactInstanceManager + } + + override fun getMainComponentName(): String? { + return delegate.mainComponentName + } + + override fun loadApp(appKey: String?) { + // Give modules a chance to wrap the ReactRootView in a container ViewGroup. If some module + // wants to do this, we override the functionality of `loadApp` and call `setContentView` with + // the new container view instead. + val rootViewContainer = reactActivityHandlers.asSequence() + .mapNotNull { it.createReactRootViewContainer(activity) } + .firstOrNull() + if (rootViewContainer != null) { + val mReactDelegate = ReactActivityDelegate::class.java.getDeclaredField("mReactDelegate") + mReactDelegate.isAccessible = true + val reactDelegate = mReactDelegate[delegate] as ReactDelegate + + reactDelegate.loadApp(appKey) + rootViewContainer.addView(reactDelegate.reactRootView, ViewGroup.LayoutParams.MATCH_PARENT) + activity.setContentView(rootViewContainer) + return + } + + val delayLoadAppHandler = reactActivityHandlers.asSequence() + .mapNotNull { it.getDelayLoadAppHandler(activity, host) } + .firstOrNull() + if (delayLoadAppHandler != null) { + delayLoadAppHandler.whenReady { + invokeDelegateMethod("loadApp", arrayOf(String::class.java), arrayOf(appKey)) + if (shouldEmitPendingResume) { + onResume() + } + } + return + } + + return invokeDelegateMethod("loadApp", arrayOf(String::class.java), arrayOf(appKey)) + } + + override fun onCreate(savedInstanceState: Bundle?) { + // Give handlers a chance as early as possible to replace the wrapped delegate object. + // If they do, we call the new wrapped delegate's `onCreate` instead of overriding it here. + val newDelegate = reactActivityHandlers.asSequence() + .mapNotNull { it.onDidCreateReactActivityDelegate(activity, this) } + .firstOrNull() + if (newDelegate != null && newDelegate != this) { + val mDelegateField = ReactActivity::class.java.getDeclaredField("mDelegate") + mDelegateField.isAccessible = true + val modifiers = Field::class.java.getDeclaredField("accessFlags") + modifiers.isAccessible = true + modifiers.setInt(mDelegateField, mDelegateField.modifiers and Modifier.FINAL.inv()) + mDelegateField.set(activity, newDelegate) + delegate = newDelegate + + invokeDelegateMethod("onCreate", arrayOf(Bundle::class.java), arrayOf(savedInstanceState)) + } else { + // Since we just wrap `ReactActivityDelegate` but not inherit it, in its `onCreate`, + // the calls to `createRootView()` or `getMainComponentName()` have no chances to be our wrapped methods. + // Instead we intercept `ReactActivityDelegate.onCreate` and replace the `mReactDelegate` with our version. + // That's not ideal but works. + val reactDelegate = object : ReactDelegate( + plainActivity, reactNativeHost, mainComponentName, launchOptions + ) { + override fun createRootView(): ReactRootView { + return this@ReactActivityDelegateWrapper.createRootView() + } + } + val mReactDelegate = ReactActivityDelegate::class.java.getDeclaredField("mReactDelegate") + mReactDelegate.isAccessible = true + mReactDelegate.set(delegate, reactDelegate) + if (mainComponentName != null) { + loadApp(mainComponentName) + } + } + + reactActivityLifecycleListeners.forEach { listener -> + listener.onCreate(activity, savedInstanceState) + } + } + + override fun onResume() { + if (!host.hasInstance()) { + shouldEmitPendingResume = true + return + } + invokeDelegateMethod("onResume") + reactActivityLifecycleListeners.forEach { listener -> + listener.onResume(activity) + } + shouldEmitPendingResume = false + } + + override fun onPause() { + // If app is stopped before delayed `loadApp`, we should cancel the pending resume + shouldEmitPendingResume = false + if (!host.hasInstance()) { + return + } + reactActivityLifecycleListeners.forEach { listener -> + listener.onPause(activity) + } + return invokeDelegateMethod("onPause") + } + + override fun onDestroy() { + // If app is stopped before delayed `loadApp`, we should cancel the pending resume + shouldEmitPendingResume = false + if (!host.hasInstance()) { + return + } + reactActivityLifecycleListeners.forEach { listener -> + listener.onDestroy(activity) + } + return invokeDelegateMethod("onDestroy") + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + /** + * Workaround for a problem when results from [onActivityResult] are not properly delivered to modules. + * It happens when Android kills the [Activity] upon low memory scenario and recreates it later on. + * + * In [com.facebook.react.ReactInstanceManager.onActivityResult] you can see that if + * [com.facebook.react.bridge.ReactContext] is null then React would not broadcast the result to the modules + * and thus [expo.modules.kotlin.AppContext] would not be triggered properly. + * + * If [com.facebook.react.bridge.ReactContext] is not available when [onActivityResult] is called then + * let us wait for it and invoke [onActivityResult] once it's available. + * + * TODO (@bbarthec): fix it upstream? + */ + if (delegate.reactInstanceManager.currentReactContext == null) { + val reactContextListener = object : ReactInstanceEventListener { + override fun onReactContextInitialized(context: ReactContext?) { + delegate.reactInstanceManager.removeReactInstanceEventListener(this) + delegate.onActivityResult(requestCode, resultCode, data) + } + } + return delegate.reactInstanceManager.addReactInstanceEventListener(reactContextListener) + } + + delegate.onActivityResult(requestCode, resultCode, data) + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + return delegate.onKeyDown(keyCode, event) + } + + override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { + // if any of the handlers return true, intentionally consume the event instead of passing it + // through to the delegate + return reactActivityHandlers + .map { it.onKeyUp(keyCode, event) } + .fold(false) { accu, current -> accu || current } || delegate.onKeyUp(keyCode, event) + } + + override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean { + return delegate.onKeyLongPress(keyCode, event) + } + + override fun onBackPressed(): Boolean { + val listenerResult = reactActivityLifecycleListeners + .map(ReactActivityLifecycleListener::onBackPressed) + .fold(false) { accu, current -> accu || current } + val delegateResult = delegate.onBackPressed() + return listenerResult || delegateResult + } + + override fun onNewIntent(intent: Intent?): Boolean { + val listenerResult = reactActivityLifecycleListeners + .map { it.onNewIntent(intent) } + .fold(false) { accu, current -> accu || current } + val delegateResult = delegate.onNewIntent(intent) + return listenerResult || delegateResult + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + delegate.onWindowFocusChanged(hasFocus) + } + + override fun requestPermissions(permissions: Array?, requestCode: Int, listener: PermissionListener?) { + delegate.requestPermissions(permissions, requestCode, listener) + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array?, grantResults: IntArray?) { + delegate.onRequestPermissionsResult(requestCode, permissions, grantResults) + } + + override fun getContext(): Context { + return invokeDelegateMethod("getContext") + } + + override fun getPlainActivity(): Activity { + return invokeDelegateMethod("getPlainActivity") + } + + //endregion + + //region Internals + + @Suppress("UNCHECKED_CAST") + private fun invokeDelegateMethod(name: String): T { + var method = methodMap[name] + if (method == null) { + method = ReactActivityDelegate::class.java.getDeclaredMethod(name) + method.isAccessible = true + methodMap[name] = method + } + return method!!.invoke(delegate) as T + } + + @Suppress("UNCHECKED_CAST") + private fun invokeDelegateMethod( + name: String, + argTypes: Array>, + args: Array + ): T { + var method = methodMap[name] + if (method == null) { + method = ReactActivityDelegate::class.java.getDeclaredMethod(name, *argTypes) + method.isAccessible = true + methodMap[name] = method + } + return method!!.invoke(delegate, *args) as T + } + + //endregion +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ReactNativeHostWrapperBase.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ReactNativeHostWrapperBase.kt new file mode 100644 index 00000000000000..0e3cae87490907 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/ReactNativeHostWrapperBase.kt @@ -0,0 +1,119 @@ +package abi49_0_0.expo.modules + +import android.app.Application +import androidx.collection.ArrayMap +import abi49_0_0.com.facebook.react.ReactInstanceManager +import abi49_0_0.com.facebook.react.ReactNativeHost +import abi49_0_0.com.facebook.react.ReactPackage +import abi49_0_0.com.facebook.react.bridge.JSIModule +import abi49_0_0.com.facebook.react.bridge.JSIModulePackage +import abi49_0_0.com.facebook.react.bridge.JSIModuleSpec +import abi49_0_0.com.facebook.react.bridge.JavaScriptContextHolder +import abi49_0_0.com.facebook.react.bridge.JavaScriptExecutorFactory +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext +import java.lang.reflect.Method + +open class ReactNativeHostWrapperBase( + application: Application, + protected val host: ReactNativeHost +) : ReactNativeHost(application) { + internal val reactNativeHostHandlers = ExpoModulesPackage.packageList + .flatMap { it.createReactNativeHostHandlers(application) } + private val methodMap: ArrayMap = ArrayMap() + + override fun createReactInstanceManager(): ReactInstanceManager { + val developerSupport = useDeveloperSupport + reactNativeHostHandlers.forEach { handler -> + handler.onWillCreateReactInstanceManager(developerSupport) + } + + val result = reactNativeHostHandlers.asSequence() + .mapNotNull { it.createReactInstanceManager(developerSupport) } + .firstOrNull() ?: super.createReactInstanceManager() + + reactNativeHostHandlers.forEach { handler -> + handler.onDidCreateReactInstanceManager(result, developerSupport) + } + + injectHostReactInstanceManager(result) + + return result + } + + override fun getJavaScriptExecutorFactory(): JavaScriptExecutorFactory? { + return reactNativeHostHandlers.asSequence() + .mapNotNull { it.javaScriptExecutorFactory } + .firstOrNull() ?: invokeDelegateMethod("getJavaScriptExecutorFactory") + } + + override fun getJSIModulePackage(): JSIModulePackage? { + val userJSIModulePackage = invokeDelegateMethod("getJSIModulePackage") + return JSIModuleContainerPackage(userJSIModulePackage) + } + + override fun getJSMainModuleName(): String { + return invokeDelegateMethod("getJSMainModuleName") + } + + override fun getJSBundleFile(): String? { + return reactNativeHostHandlers.asSequence() + .mapNotNull { it.getJSBundleFile(useDeveloperSupport) } + .firstOrNull() ?: invokeDelegateMethod("getJSBundleFile") + } + + override fun getBundleAssetName(): String? { + return reactNativeHostHandlers.asSequence() + .mapNotNull { it.getBundleAssetName(useDeveloperSupport) } + .firstOrNull() ?: invokeDelegateMethod("getBundleAssetName") + } + + override fun getUseDeveloperSupport(): Boolean { + return reactNativeHostHandlers.asSequence() + .mapNotNull { it.useDeveloperSupport } + .firstOrNull() ?: host.useDeveloperSupport + } + + override fun getPackages(): MutableList { + return invokeDelegateMethod("getPackages") + } + + //endregion + + //region Internals + + inner class JSIModuleContainerPackage(userJSIModulePackage: JSIModulePackage?) : JSIModulePackage { + private val userJSIModulePackage = userJSIModulePackage + override fun getJSIModules( + reactApplicationContext: ReactApplicationContext, + jsContext: JavaScriptContextHolder + ): List> { + reactNativeHostHandlers.forEach { handler -> + handler.onRegisterJSIModules(reactApplicationContext, jsContext, useDeveloperSupport) + } + return userJSIModulePackage?.getJSIModules(reactApplicationContext, jsContext)?.toList() ?: emptyList() + } + } + + @Suppress("UNCHECKED_CAST") + internal fun invokeDelegateMethod(name: String): T { + var method = methodMap[name] + if (method == null) { + method = ReactNativeHost::class.java.getDeclaredMethod(name) + method.isAccessible = true + methodMap[name] = method + } + return method!!.invoke(host) as T + } + + /** + * Inject the @{ReactInstanceManager} from the wrapper to the wrapped host. + * In case the wrapped host to call `getReactInstanceManager` inside its methods. + */ + fun injectHostReactInstanceManager(reactInstanceManager: ReactInstanceManager) { + val mReactInstanceManagerField = ReactNativeHost::class.java.getDeclaredField("mReactInstanceManager") + mReactInstanceManagerField.isAccessible = true + mReactInstanceManagerField.set(host, reactInstanceManager) + } + + //endregion +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ArgumentsHelper.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ArgumentsHelper.java new file mode 100644 index 00000000000000..cba839bd97cd48 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ArgumentsHelper.java @@ -0,0 +1,48 @@ +package abi49_0_0.expo.modules.adapters.react; + +import abi49_0_0.com.facebook.react.bridge.Dynamic; + +import abi49_0_0.expo.modules.core.arguments.MapArguments; +import abi49_0_0.expo.modules.core.arguments.ReadableArguments; + +public class ArgumentsHelper { + public static Object getNativeArgumentForExpectedClass(Dynamic argument, Class expectedArgumentClass) { + switch (argument.getType()) { + case String: + return argument.asString(); + case Map: + if (expectedArgumentClass.isAssignableFrom(ReadableArguments.class)) { + return new MapArguments(argument.asMap().toHashMap()); + } + return argument.asMap().toHashMap(); + case Array: + return argument.asArray().toArrayList(); + case Number: + // Argument of type .Number is remembered as Double by default. + Double doubleArgument = argument.asDouble(); + // We have to provide ExportedModule with proper Number value + if (expectedArgumentClass == byte.class || expectedArgumentClass == Byte.class) { + return doubleArgument.byteValue(); + } else if (expectedArgumentClass == short.class || expectedArgumentClass == Short.class) { + return doubleArgument.shortValue(); + } else if (expectedArgumentClass == int.class || expectedArgumentClass == Integer.class) { + return doubleArgument.intValue(); + } else if (expectedArgumentClass == float.class || expectedArgumentClass == Float.class) { + return doubleArgument.floatValue(); + } else if (expectedArgumentClass == long.class || expectedArgumentClass == Long.class) { + return doubleArgument.longValue(); + } else { + return doubleArgument; + } + case Boolean: + return argument.asBoolean(); + case Null: + return null; + default: + // JS argument is not null, however we can't recognize the type. + throw new RuntimeException( + "Don't know how to convert React Native argument of type " + argument.getType() + " to native." + ); + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/FabricComponentsRegistry.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/FabricComponentsRegistry.kt new file mode 100644 index 00000000000000..c7d9558a16380c --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/FabricComponentsRegistry.kt @@ -0,0 +1,37 @@ +// Copyright 2018-present 650 Industries. All rights reserved. + +package abi49_0_0.expo.modules.adapters.react + +import com.facebook.jni.HybridData +import abi49_0_0.com.facebook.react.uimanager.ViewManager +import com.facebook.soloader.SoLoader +import abi49_0_0.expo.modules.core.interfaces.DoNotStrip + +@Suppress("KotlinJniMissingFunction") +@DoNotStrip +class FabricComponentsRegistry(viewManagerList: List>) { + private val componentNames: List + + @DoNotStrip + private val mHybridData: HybridData + + init { + componentNames = viewManagerList.map { it.name } + mHybridData = initHybrid() + registerComponentsRegistry(componentNames.toTypedArray()) + } + + private external fun initHybrid(): HybridData + private external fun registerComponentsRegistry(componentNames: Array) + + @Throws(Throwable::class) + protected fun finalize() { + mHybridData.resetNative() + } + + companion object { + init { + SoLoader.loadLibrary("expo-modules-core_abi49_0_0") + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ModuleRegistryAdapter.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ModuleRegistryAdapter.java new file mode 100644 index 00000000000000..a1069057754b92 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ModuleRegistryAdapter.java @@ -0,0 +1,139 @@ +package abi49_0_0.expo.modules.adapters.react; + +import abi49_0_0.com.facebook.react.ReactPackage; +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import androidx.annotation.Nullable; +import host.exp.expoview.BuildConfig; +import abi49_0_0.expo.modules.adapters.react.views.SimpleViewManagerAdapter; +import abi49_0_0.expo.modules.adapters.react.views.ViewGroupManagerAdapter; +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.Package; +import abi49_0_0.expo.modules.kotlin.CoreLoggerKt; +import abi49_0_0.expo.modules.kotlin.KotlinInteropModuleRegistry; +import abi49_0_0.expo.modules.kotlin.ModulesProvider; +import abi49_0_0.expo.modules.kotlin.views.ViewWrapperDelegateHolder; + +/** + * An adapter over {@link ModuleRegistry}, compatible with React (implementing {@link ReactPackage}). + * Provides React Native with native modules and view managers, + * which in turn are created by packages provided by {@link ReactModuleRegistryProvider}. + */ +public class ModuleRegistryAdapter implements ReactPackage { + protected ReactModuleRegistryProvider mModuleRegistryProvider; + protected ModulesProvider mModulesProvider; + protected ReactAdapterPackage mReactAdapterPackage = new ReactAdapterPackage(); + private NativeModulesProxy mModulesProxy; + // We need to save all view holders to update them when the new kotlin module registry will be created. + private List mWrapperDelegateHolders = null; + private FabricComponentsRegistry mFabricComponentsRegistry = null; + + public ModuleRegistryAdapter(List packageList) { + mModuleRegistryProvider = new ReactModuleRegistryProvider(packageList, null); + } + + public ModuleRegistryAdapter(ReactModuleRegistryProvider moduleRegistryProvider) { + mModuleRegistryProvider = moduleRegistryProvider; + } + + public ModuleRegistryAdapter(ReactModuleRegistryProvider moduleRegistryProvider, ModulesProvider modulesProvider) { + mModuleRegistryProvider = moduleRegistryProvider; + mModulesProvider = modulesProvider; + } + + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + NativeModulesProxy proxy = getOrCreateNativeModulesProxy(reactContext, null); + ModuleRegistry moduleRegistry = proxy.getModuleRegistry(); + + for (InternalModule internalModule : mReactAdapterPackage.createInternalModules(reactContext)) { + moduleRegistry.registerInternalModule(internalModule); + } + + List nativeModules = getNativeModulesFromModuleRegistry(reactContext, moduleRegistry); + if (mWrapperDelegateHolders != null) { + KotlinInteropModuleRegistry kotlinInteropModuleRegistry = proxy.getKotlinInteropModuleRegistry(); + kotlinInteropModuleRegistry.updateModuleHoldersInViewManagers(mWrapperDelegateHolders); + } + + return nativeModules; + } + + protected List getNativeModulesFromModuleRegistry(ReactApplicationContext reactContext, ModuleRegistry moduleRegistry) { + List nativeModulesList = new ArrayList<>(2); + + nativeModulesList.add(getOrCreateNativeModulesProxy(reactContext, moduleRegistry)); + + // Add listener that will notify abi49_0_0.expo.modules.core.ModuleRegistry when all modules are ready + nativeModulesList.add(new ModuleRegistryReadyNotifier(moduleRegistry)); + + ReactPackagesProvider reactPackagesProvider = moduleRegistry.getModule(ReactPackagesProvider.class); + for (ReactPackage reactPackage : reactPackagesProvider.getReactPackages()) { + nativeModulesList.addAll(reactPackage.createNativeModules(reactContext)); + } + + return nativeModulesList; + } + + @Override + @SuppressWarnings("unchecked") + public List createViewManagers(ReactApplicationContext reactContext) { + List viewManagerList = new ArrayList<>(mModuleRegistryProvider.getReactViewManagers(reactContext)); + + for (abi49_0_0.expo.modules.core.ViewManager viewManager : mModuleRegistryProvider.getViewManagers(reactContext)) { + switch (viewManager.getViewManagerType()) { + case GROUP: + viewManagerList.add(new ViewGroupManagerAdapter(viewManager)); + break; + case SIMPLE: + viewManagerList.add(new SimpleViewManagerAdapter(viewManager)); + break; + } + } + + NativeModulesProxy modulesProxy = Objects.requireNonNull(getOrCreateNativeModulesProxy(reactContext, null)); + KotlinInteropModuleRegistry kotlinInteropModuleRegistry = modulesProxy.getKotlinInteropModuleRegistry(); + List> kViewManager = kotlinInteropModuleRegistry.exportViewManagers(); + // Saves all holders that needs to be in sync with module registry + mWrapperDelegateHolders = kotlinInteropModuleRegistry.extractViewManagersDelegateHolders(kViewManager); + viewManagerList.addAll(kViewManager); + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // Intentionally to only add Sweet API view managers for Fabric support + mFabricComponentsRegistry = new FabricComponentsRegistry(kViewManager); + } + + return viewManagerList; + } + + private synchronized NativeModulesProxy getOrCreateNativeModulesProxy( + ReactApplicationContext reactContext, + @Nullable ModuleRegistry moduleRegistry + ) { + if (mModulesProxy != null && mModulesProxy.getReactContext() != reactContext) { + mModulesProxy = null; + } + if (mModulesProxy == null) { + ModuleRegistry registry = moduleRegistry != null ? moduleRegistry : mModuleRegistryProvider.get(reactContext); + if (mModulesProvider != null) { + mModulesProxy = new NativeModulesProxy(reactContext, registry, mModulesProvider); + } else { + mModulesProxy = new NativeModulesProxy(reactContext, registry); + } + + mModulesProxy.getKotlinInteropModuleRegistry().setLegacyModulesProxy(mModulesProxy); + } + + if (moduleRegistry != null && moduleRegistry != mModulesProxy.getModuleRegistry()) { + CoreLoggerKt.getLogger().error("❌ NativeModuleProxy was configured with a different instance of the modules registry.", null); + } + + return mModulesProxy; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ModuleRegistryReadyNotifier.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ModuleRegistryReadyNotifier.java new file mode 100644 index 00000000000000..474d3325ebc43a --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ModuleRegistryReadyNotifier.java @@ -0,0 +1,30 @@ +package abi49_0_0.expo.modules.adapters.react; + +import abi49_0_0.com.facebook.react.bridge.BaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.NativeModule; + +import abi49_0_0.expo.modules.core.ModuleRegistry; + +/** + * {@link ModuleRegistryReadyNotifier} is exported as a native module + * to React Native and when {@link abi49_0_0.com.facebook.react.ReactInstanceManager} + * notifies {@link abi49_0_0.com.facebook.react.bridge.NativeModule} of being ready + * ({@link NativeModule#initialize()}) it delegates the call to {@link ModuleRegistry}. + */ +public class ModuleRegistryReadyNotifier extends BaseJavaModule { + private ModuleRegistry mModuleRegistry; + + public ModuleRegistryReadyNotifier(ModuleRegistry moduleRegistry) { + mModuleRegistry = moduleRegistry; + } + + @Override + public String getName() { + return null; + } + + @Override + public void initialize() { + mModuleRegistry.ensureIsInitialized(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/NativeModulesProxy.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/NativeModulesProxy.java new file mode 100644 index 00000000000000..21a9c3b2d4539a --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/NativeModulesProxy.java @@ -0,0 +1,274 @@ +package abi49_0_0.expo.modules.adapters.react; + +import android.util.Log; +import android.util.SparseArray; + +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.Promise; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; +import abi49_0_0.com.facebook.react.bridge.ReactContextBaseJavaModule; +import abi49_0_0.com.facebook.react.bridge.ReactMethod; +import abi49_0_0.com.facebook.react.bridge.ReadableArray; +import abi49_0_0.com.facebook.react.bridge.ReadableType; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.annotation.Nullable; + +import abi49_0_0.expo.modules.core.ExportedModule; +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.ViewManager; +import abi49_0_0.expo.modules.core.interfaces.ExpoMethod; +import abi49_0_0.expo.modules.kotlin.CoreLoggerKt; +import abi49_0_0.expo.modules.kotlin.ExpoModulesHelper; +import abi49_0_0.expo.modules.kotlin.KPromiseWrapper; +import abi49_0_0.expo.modules.kotlin.KotlinInteropModuleRegistry; +import abi49_0_0.expo.modules.kotlin.ModulesProvider; + +/** + * A wrapper/proxy for all {@link ExportedModule}s, gets exposed as {@link abi49_0_0.com.facebook.react.bridge.NativeModule}, + * so that JS code can call methods of the internal modules. + */ +public class NativeModulesProxy extends ReactContextBaseJavaModule { + private final static String NAME = "NativeUnimoduleProxy"; + private final static String VIEW_MANAGERS_METADATA_KEY = "viewManagersMetadata"; + private final static String MODULES_CONSTANTS_KEY = "modulesConstants"; + private final static String EXPORTED_METHODS_KEY = "exportedMethods"; + + private final static String METHOD_INFO_KEY = "key"; + private final static String METHOD_INFO_NAME = "name"; + private final static String METHOD_INFO_ARGUMENTS_COUNT = "argumentsCount"; + + private final static String UNEXPECTED_ERROR = "E_UNEXPECTED_ERROR"; + private final static String UNDEFINED_METHOD_ERROR = "E_UNDEFINED_METHOD"; + private final static String ARGS_TYPES_MISMATCH_ERROR = "E_ARGS_TYPES_MISMATCH"; + + private ModuleRegistry mModuleRegistry; + private Map> mExportedMethodsKeys; + private Map> mExportedMethodsReverseKeys; + private KotlinInteropModuleRegistry mKotlinInteropModuleRegistry; + private Map cachedConstants; + + public NativeModulesProxy(ReactApplicationContext context, ModuleRegistry moduleRegistry) { + super(context); + mModuleRegistry = moduleRegistry; + mExportedMethodsKeys = new HashMap<>(); + mExportedMethodsReverseKeys = new HashMap<>(); + + mKotlinInteropModuleRegistry = new KotlinInteropModuleRegistry( + Objects.requireNonNull(ExpoModulesHelper.Companion.getModulesProvider()), + moduleRegistry, + new WeakReference<>(context) + ); + } + + public NativeModulesProxy(ReactApplicationContext context, ModuleRegistry moduleRegistry, ModulesProvider modulesProvider) { + super(context); + mModuleRegistry = moduleRegistry; + mExportedMethodsKeys = new HashMap<>(); + mExportedMethodsReverseKeys = new HashMap<>(); + + mKotlinInteropModuleRegistry = new KotlinInteropModuleRegistry( + Objects.requireNonNull(modulesProvider), + moduleRegistry, + new WeakReference<>(context) + ); + } + + public KotlinInteropModuleRegistry getKotlinInteropModuleRegistry() { + return mKotlinInteropModuleRegistry; + } + + @Override + public String getName() { + return NAME; + } + + @Nullable + @Override + public Map getConstants() { + if (cachedConstants != null) { + return cachedConstants; + } + + mModuleRegistry.ensureIsInitialized(); + getKotlinInteropModuleRegistry().installJSIInterop(); + + Collection exportedModules = mModuleRegistry.getAllExportedModules(); + Collection viewManagers = mModuleRegistry.getAllViewManagers(); + + Map modulesConstants = new HashMap<>(exportedModules.size()); + Map exportedMethodsMap = new HashMap<>(exportedModules.size()); + Map viewManagersMetadata = new HashMap<>(viewManagers.size()); + + for (ExportedModule exportedModule : exportedModules) { + String moduleName = exportedModule.getName(); + modulesConstants.put(moduleName, exportedModule.getConstants()); + + List> exportedMethods = transformExportedMethodsMap(exportedModule.getExportedMethods()); + assignExportedMethodsKeys(moduleName, exportedMethods); + + exportedMethodsMap.put(moduleName, exportedMethods); + } + + modulesConstants.putAll(mKotlinInteropModuleRegistry.exportedModulesConstants()); + exportedMethodsMap.putAll(mKotlinInteropModuleRegistry.exportMethods((name, info) -> { + assignExportedMethodsKeys(name, (List>) info); + return null; + })); + + for (ViewManager viewManager : viewManagers) { + viewManagersMetadata.put(viewManager.getName(), viewManager.getMetadata()); + } + + viewManagersMetadata.putAll(mKotlinInteropModuleRegistry.viewManagersMetadata()); + + Map constants = new HashMap<>(3); + constants.put(MODULES_CONSTANTS_KEY, modulesConstants); + constants.put(EXPORTED_METHODS_KEY, exportedMethodsMap); + constants.put(VIEW_MANAGERS_METADATA_KEY, viewManagersMetadata); + + CoreLoggerKt.getLogger().info("✅ Constants were exported"); + + cachedConstants = constants; + + return constants; + } + + /** + * The only exported {@link ReactMethod}. + * JavaScript can call native modules' exported methods ({@link ExpoMethod}) using this method as a proxy. + * For native {@link ExpoMethod} `void put(String key, int value)` in `NativeDictionary` module + * JavaScript could call `NativeModulesProxy.callMethod("NativeDictionary", "put", ["key", 42])` + * or `NativeModulesProxy.callMethod("NativeDictionary", 2, ["key", 42])`, where the second argument + * is a method's constant key. + */ + @ReactMethod + public void callMethod(String moduleName, Dynamic methodKeyOrName, ReadableArray arguments, final Promise promise) { + String methodName; + if (methodKeyOrName.getType() == ReadableType.String) { + methodName = methodKeyOrName.asString(); + } else if (methodKeyOrName.getType() == ReadableType.Number) { + methodName = mExportedMethodsReverseKeys.get(moduleName).get(methodKeyOrName.asInt()); + } else { + promise.reject(UNEXPECTED_ERROR, "Method key is neither a String nor an Integer -- don't know how to map it to method name."); + return; + } + + callMethod(moduleName, methodName, arguments, promise); + } + + public void callMethod(String moduleName, String methodName, ReadableArray arguments, final Promise promise) { + if (mKotlinInteropModuleRegistry.hasModule(moduleName)) { + mKotlinInteropModuleRegistry.callMethod(moduleName, methodName, arguments, new KPromiseWrapper(promise)); + return; + } + + try { + List nativeArguments = getNativeArgumentsForMethod(arguments, mModuleRegistry.getExportedModule(moduleName).getExportedMethodInfos().get(methodName)); + nativeArguments.add(new PromiseWrapper(promise)); + + mModuleRegistry.getExportedModule(moduleName).invokeExportedMethod(methodName, nativeArguments); + } catch (IllegalArgumentException e) { + promise.reject(ARGS_TYPES_MISMATCH_ERROR, e.getMessage(), e); + } catch (RuntimeException e) { + promise.reject(UNEXPECTED_ERROR, "Encountered an exception while calling native method: " + e.getMessage(), e); + } catch (NoSuchMethodException e) { + promise.reject( + UNDEFINED_METHOD_ERROR, + "Method " + methodName + " of Java module " + moduleName + " is undefined.", + e + ); + } + } + + /** + * Converts {@link ReadableArray} of arguments into a list of Java Objects. + * Throws {@link RuntimeException} if it can't convert some {@link ReadableType} to Object. + * Method is used when converting Double to proper argument. + */ + private static List getNativeArgumentsForMethod(ReadableArray arguments, ExportedModule.MethodInfo methodInfo) { + List nativeArguments = new ArrayList<>(); + + for (int i = 0; i < arguments.size(); i++) { + nativeArguments.add(ArgumentsHelper.getNativeArgumentForExpectedClass(arguments.getDynamic(i), methodInfo.getParameterTypes()[i])); + } + return nativeArguments; + } + + /** + * Transforms exportedMethodsMap to a map of methodInfos + */ + private List> transformExportedMethodsMap(Map exportedMethods) { + List> methods = new ArrayList<>(exportedMethods.size()); + for (Map.Entry entry : exportedMethods.entrySet()) { + methods.add(getMethodInfo(entry.getKey(), entry.getValue())); + } + return methods; + } + + /** + * Returns methodInfo Map (a Map containing a value for key argumentsCount). + */ + private Map getMethodInfo(String name, Method method) { + Map info = new HashMap<>(2); + info.put(METHOD_INFO_NAME, name); + info.put(METHOD_INFO_ARGUMENTS_COUNT, method.getParameterTypes().length - 1); // - 1 is for the Promise + return info; + } + + /** + * Assigns keys to exported method infos and updates {@link #mExportedMethodsKeys} and {@link #mExportedMethodsReverseKeys}. + * Mutates maps in provided list. + */ + private void assignExportedMethodsKeys(String moduleName, List> exportedMethodsInfos) { + if (mExportedMethodsKeys.get(moduleName) == null) { + mExportedMethodsKeys.put(moduleName, new HashMap()); + } + + if (mExportedMethodsReverseKeys.get(moduleName) == null) { + mExportedMethodsReverseKeys.put(moduleName, new SparseArray()); + } + + for (int i = 0; i < exportedMethodsInfos.size(); i++) { + Map methodInfo = exportedMethodsInfos.get(i); + + if (methodInfo.get(METHOD_INFO_NAME) == null || !(methodInfo.get(METHOD_INFO_NAME) instanceof String)) { + throw new RuntimeException("No method name in MethodInfo - " + methodInfo.toString()); + } + + String methodName = (String) methodInfo.get(METHOD_INFO_NAME); + Integer maybePreviousIndex = mExportedMethodsKeys.get(moduleName).get(methodName); + if (maybePreviousIndex == null) { + int key = mExportedMethodsKeys.get(moduleName).values().size(); + methodInfo.put(METHOD_INFO_KEY, key); + mExportedMethodsKeys.get(moduleName).put(methodName, key); + mExportedMethodsReverseKeys.get(moduleName).put(key, methodName); + } else { + int key = maybePreviousIndex; + methodInfo.put(METHOD_INFO_KEY, key); + } + } + } + + @Override + public void onCatalystInstanceDestroy() { + mModuleRegistry.onDestroy(); + mKotlinInteropModuleRegistry.onDestroy(); + } + + ModuleRegistry getModuleRegistry() { + return mModuleRegistry; + } + + /* package */ ReactApplicationContext getReactContext() { + return getReactApplicationContext(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/PromiseWrapper.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/PromiseWrapper.java new file mode 100644 index 00000000000000..063b4687d73b13 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/PromiseWrapper.java @@ -0,0 +1,38 @@ +package abi49_0_0.expo.modules.adapters.react; + +import android.os.Bundle; + +import abi49_0_0.com.facebook.react.bridge.Arguments; + +import abi49_0_0.expo.modules.core.Promise; + +import java.util.List; + +import javax.annotation.Nullable; + +/** + * Decorator for {@link abi49_0_0.com.facebook.react.bridge.Promise}, + * so we don't have to implement these inline in {@link NativeModulesProxy}. + */ +/* package */ class PromiseWrapper implements Promise { + private abi49_0_0.com.facebook.react.bridge.Promise mPromise; + + /* package */ PromiseWrapper(abi49_0_0.com.facebook.react.bridge.Promise promise) { + super(); + mPromise = promise; + } + + public void resolve(@Nullable Object value) { + if (value instanceof Bundle) { + mPromise.resolve(Arguments.fromBundle((Bundle) value)); + } else if (value instanceof List) { + mPromise.resolve(Arguments.fromList((List) value)); + } else { + mPromise.resolve(value); + } + } + + public void reject(String code, String message, Throwable e) { + mPromise.reject(code, message, e); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactAdapterPackage.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactAdapterPackage.java new file mode 100644 index 00000000000000..d4879c269aae93 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactAdapterPackage.java @@ -0,0 +1,38 @@ +package abi49_0_0.expo.modules.adapters.react; + +import android.content.Context; + +import abi49_0_0.com.facebook.react.bridge.ReactContext; + +import abi49_0_0.expo.modules.adapters.react.permissions.PermissionsService; +import abi49_0_0.expo.modules.adapters.react.services.CookieManagerModule; +import abi49_0_0.expo.modules.adapters.react.services.EventEmitterModule; +import abi49_0_0.expo.modules.adapters.react.services.FontManagerModule; +import abi49_0_0.expo.modules.adapters.react.services.RuntimeEnvironmentModule; +import abi49_0_0.expo.modules.adapters.react.services.UIManagerModuleWrapper; +import abi49_0_0.expo.modules.core.BasePackage; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.Package; + +import java.util.Arrays; +import java.util.List; + +/** + * A {@link Package} creating modules provided with the @unimodules/react-native-adapter package. + */ +public class ReactAdapterPackage extends BasePackage { + + @Override + public List createInternalModules(Context context) { + // We can force-cast here, because this package will only be used in React Native context. + ReactContext reactContext = (ReactContext) context; + return Arrays.asList( + new CookieManagerModule(reactContext), + new UIManagerModuleWrapper(reactContext), + new EventEmitterModule(reactContext), + new FontManagerModule(), + new RuntimeEnvironmentModule(), + new PermissionsService(reactContext) + ); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactModuleRegistryProvider.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactModuleRegistryProvider.java new file mode 100644 index 00000000000000..ef7a07c83f026c --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactModuleRegistryProvider.java @@ -0,0 +1,102 @@ +package abi49_0_0.expo.modules.adapters.react; + +import android.content.Context; + +import abi49_0_0.com.facebook.react.ReactPackage; +import abi49_0_0.com.facebook.react.bridge.ReactApplicationContext; + +import abi49_0_0.expo.modules.core.ExportedModule; +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.ModuleRegistryProvider; +import abi49_0_0.expo.modules.core.ViewManager; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.Package; +import expo.modules.core.interfaces.SingletonModule; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +/** + * Since React Native v0.55, {@link abi49_0_0.com.facebook.react.ReactPackage#createViewManagers(ReactApplicationContext)} + * gets called only once per lifetime of {@link abi49_0_0.com.facebook.react.ReactInstanceManager}. + *

+ * To make @unimodules/react-native-adapter compatible with this change we have to remember view managers collection + * which is returned in {@link ModuleRegistryAdapter#createViewManagers(ReactApplicationContext)} + * only once (and managers returned this one time will persist "forever"). + */ +public class ReactModuleRegistryProvider extends ModuleRegistryProvider { + private Collection mViewManagers; + private Collection mReactViewManagers; + private Collection mSingletonModules; + + public ReactModuleRegistryProvider(List initialPackages) { + this(initialPackages, null); + } + + public ReactModuleRegistryProvider(List initialPackages, List singletonModules) { + super(initialPackages); + mSingletonModules = singletonModules; + } + + @Override + public ModuleRegistry get(Context context) { + Collection internalModules = new ArrayList<>(); + Collection exportedModules = new ArrayList<>(); + + ReactPackagesProvider reactPackagesProvider = new ReactPackagesProvider(); + + for (Package pkg : getPackages()) { + internalModules.addAll(pkg.createInternalModules(context)); + exportedModules.addAll(pkg.createExportedModules(context)); + + if (pkg instanceof ReactPackage) { + reactPackagesProvider.addPackage((ReactPackage) pkg); + } + } + internalModules.add(reactPackagesProvider); + + return new ModuleRegistry(internalModules, exportedModules, getViewManagers(context), getSingletonModules(context)); + } + + private Collection getSingletonModules(Context context) { + // If singleton modules were provided to registry provider, then just pass them to module registry. + + if (mSingletonModules != null) { + return mSingletonModules; + } + Collection singletonModules = new ArrayList<>(); + + for (Package pkg : getPackages()) { + singletonModules.addAll(pkg.createSingletonModules(context)); + } + return singletonModules; + } + + // TODO: change access to package private when react-native-adapter was removed. + public Collection getViewManagers(Context context) { + if (mViewManagers != null) { + return mViewManagers; + } + + mViewManagers = new HashSet<>(); + mViewManagers.addAll(createViewManagers(context)); + return mViewManagers; + } + + // TODO: change access to package private when react-native-adapter was removed. + public Collection getReactViewManagers(ReactApplicationContext context) { + if (mReactViewManagers != null) { + return mReactViewManagers; + } + + mReactViewManagers = new HashSet<>(); + for (Package pkg : getPackages()) { + if (pkg instanceof ReactPackage) { + mReactViewManagers.addAll(((ReactPackage) pkg).createViewManagers(context)); + } + } + return mReactViewManagers; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactPackagesProvider.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactPackagesProvider.java new file mode 100644 index 00000000000000..d126d7a706ed7f --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/ReactPackagesProvider.java @@ -0,0 +1,39 @@ +package abi49_0_0.expo.modules.adapters.react; + +import abi49_0_0.com.facebook.react.ReactPackage; + +import abi49_0_0.expo.modules.core.interfaces.InternalModule; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Holder for ReactPackages -- visible only to the adapter. + *

+ * We want to be able to create platform-specific unimodules. + * Thus, we need a way to pass in ReactPackages via unimodules infrastructure. + * This internal module is populated with ReactPackages by ReactModuleRegistryProvider + * and is used by ModuleRegistryAdapter when it creates native modules list. + */ +public class ReactPackagesProvider implements InternalModule { + private Collection mReactPackages; + + @Override + public List getExportedInterfaces() { + return Collections.singletonList(ReactPackagesProvider.class); + } + + public ReactPackagesProvider() { + mReactPackages = new ArrayList<>(); + } + + public void addPackage(ReactPackage reactPackage) { + mReactPackages.add(reactPackage); + } + + public Collection getReactPackages() { + return mReactPackages; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/apploader/HeadlessAppLoaderNotifier.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/apploader/HeadlessAppLoaderNotifier.kt new file mode 100644 index 00000000000000..a1d656647d8674 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/apploader/HeadlessAppLoaderNotifier.kt @@ -0,0 +1,31 @@ +package abi49_0_0.expo.modules.adapters.react.apploader + +import java.lang.ref.WeakReference + +interface HeadlessAppLoaderListener { + + fun appLoaded(appScopeKey: String) + + fun appDestroyed(appScopeKey: String) +} + +object HeadlessAppLoaderNotifier { + + val listeners: MutableSet> = mutableSetOf() + + fun registerListener(listener: HeadlessAppLoaderListener) { + listeners.add(WeakReference(listener)) + } + + fun notifyAppLoaded(appScopeKey: String?) { + if (appScopeKey != null) { + listeners.forEach { it.get()?.appLoaded(appScopeKey) } + } + } + + fun notifyAppDestroyed(appScopeKey: String?) { + if (appScopeKey != null) { + listeners.forEach { it.get()?.appDestroyed(appScopeKey) } + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt new file mode 100644 index 00000000000000..05c3a56d0891cf --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt @@ -0,0 +1,66 @@ +package abi49_0_0.expo.modules.adapters.react.apploader + +import android.content.Context +import abi49_0_0.com.facebook.react.ReactApplication +import abi49_0_0.com.facebook.react.ReactInstanceManager +import abi49_0_0.com.facebook.react.common.LifecycleState +import expo.modules.apploader.HeadlessAppLoader +import expo.modules.core.interfaces.Consumer +import abi49_0_0.expo.modules.core.interfaces.DoNotStrip + +private val appRecords: MutableMap = mutableMapOf() + +class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context) : HeadlessAppLoader { + + //region HeadlessAppLoader + + override fun loadApp(context: Context, params: HeadlessAppLoader.Params?, alreadyRunning: Runnable?, callback: Consumer?) { + if (params == null || params.appScopeKey == null) { + throw IllegalArgumentException("Params must be set with appScopeKey!") + } + + if (context.applicationContext is ReactApplication) { + val reactInstanceManager = (context.applicationContext as ReactApplication).reactNativeHost.reactInstanceManager + if (!appRecords.containsKey(params.appScopeKey)) { + reactInstanceManager.addReactInstanceEventListener { + HeadlessAppLoaderNotifier.notifyAppLoaded(params.appScopeKey) + callback?.apply(true) + } + appRecords[params.appScopeKey] = reactInstanceManager + if (reactInstanceManager.hasStartedCreatingInitialContext()) { + reactInstanceManager.recreateReactContextInBackground() + } else { + reactInstanceManager.createReactContextInBackground() + } + } else { + alreadyRunning?.run() + } + } else { + throw IllegalStateException("Your application must implement ReactApplication") + } + } + + override fun invalidateApp(appScopeKey: String?): Boolean { + return if (appRecords.containsKey(appScopeKey) && appRecords[appScopeKey] != null) { + val appRecord: ReactInstanceManager = appRecords[appScopeKey]!! + android.os.Handler(context.mainLooper).post { + // Only destroy the `ReactInstanceManager` if it does not bind with an Activity. + // And The Activity would take over the ownership of `ReactInstanceManager`. + // This case happens when a user clicks a background task triggered notification immediately. + if (appRecord.lifecycleState == LifecycleState.BEFORE_CREATE) { + appRecord.destroy() + } + HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey) + appRecords.remove(appScopeKey) + } + true + } else { + false + } + } + + override fun isRunning(appScopeKey: String?): Boolean = + appRecords.contains(appScopeKey) && appRecords[appScopeKey]!!.hasStartedCreatingInitialContext() + + //endregion HeadlessAppLoader +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/permissions/PermissionsService.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/permissions/PermissionsService.kt new file mode 100644 index 00000000000000..1a7d2a64592c46 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/permissions/PermissionsService.kt @@ -0,0 +1,354 @@ +package abi49_0_0.expo.modules.adapters.react.permissions + +import android.Manifest +import android.annotation.TargetApi +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import abi49_0_0.com.facebook.react.modules.core.PermissionAwareActivity +import abi49_0_0.com.facebook.react.modules.core.PermissionListener +import abi49_0_0.expo.modules.interfaces.permissions.Permissions +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsResponse +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsResponseListener +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsStatus +import abi49_0_0.expo.modules.core.ModuleRegistry +import abi49_0_0.expo.modules.core.Promise +import abi49_0_0.expo.modules.core.interfaces.ActivityProvider +import abi49_0_0.expo.modules.core.interfaces.InternalModule +import abi49_0_0.expo.modules.core.interfaces.LifecycleEventListener +import abi49_0_0.expo.modules.core.interfaces.services.UIManager +import java.util.* +import kotlin.collections.HashMap + +private const val PERMISSIONS_REQUEST: Int = 13 +private const val PREFERENCE_FILENAME = "expo.modules.permissions.asked" + +open class PermissionsService(val context: Context) : InternalModule, Permissions, LifecycleEventListener { + private var mActivityProvider: ActivityProvider? = null + + // state holders for asking for writing permissions + private var mWriteSettingsPermissionBeingAsked = false // change this directly before calling corresponding startActivity + private var mAskAsyncListener: PermissionsResponseListener? = null + private var mAskAsyncRequestedPermissions: Array? = null + + private val mPendingPermissionCalls: Queue, PermissionsResponseListener>> = LinkedList() + private var mCurrentPermissionListener: PermissionsResponseListener? = null + + private lateinit var mAskedPermissionsCache: SharedPreferences + + private fun didAsk(permission: String): Boolean = mAskedPermissionsCache.getBoolean(permission, false) + + private fun addToAskedPermissionsCache(permissions: Array) { + with(mAskedPermissionsCache.edit()) { + permissions.forEach { putBoolean(it, true) } + apply() + } + } + + override fun getExportedInterfaces(): List> = listOf(Permissions::class.java) + + @Throws(IllegalStateException::class) + override fun onCreate(moduleRegistry: ModuleRegistry) { + mActivityProvider = moduleRegistry.getModule(ActivityProvider::class.java) + ?: throw IllegalStateException("Couldn't find implementation for ActivityProvider.") + moduleRegistry.getModule(UIManager::class.java).registerLifecycleEventListener(this) + mAskedPermissionsCache = context.applicationContext.getSharedPreferences(PREFERENCE_FILENAME, Context.MODE_PRIVATE) + } + + override fun getPermissionsWithPromise(promise: Promise, vararg permissions: String) { + getPermissions( + PermissionsResponseListener { permissionsMap: MutableMap -> + val areAllGranted = permissionsMap.all { (_, response) -> response.status == PermissionsStatus.GRANTED } + val areAllDenied = permissionsMap.all { (_, response) -> response.status == PermissionsStatus.DENIED } + val canAskAgain = permissionsMap.all { (_, response) -> response.canAskAgain } + + promise.resolve( + Bundle().apply { + putString(PermissionsResponse.EXPIRES_KEY, PermissionsResponse.PERMISSION_EXPIRES_NEVER) + putString( + PermissionsResponse.STATUS_KEY, + when { + areAllGranted -> PermissionsStatus.GRANTED.status + areAllDenied -> PermissionsStatus.DENIED.status + else -> PermissionsStatus.UNDETERMINED.status + } + ) + putBoolean(PermissionsResponse.CAN_ASK_AGAIN_KEY, canAskAgain) + putBoolean(PermissionsResponse.GRANTED_KEY, areAllGranted) + } + ) + }, + *permissions + ) + } + + override fun askForPermissionsWithPromise(promise: Promise, vararg permissions: String) { + askForPermissions( + PermissionsResponseListener { + getPermissionsWithPromise(promise, *permissions) + }, + *permissions + ) + } + + override fun getPermissions(responseListener: PermissionsResponseListener, vararg permissions: String) { + responseListener.onResult( + parseNativeResult( + permissions, + permissions.map { + if (isPermissionGranted(it)) { + PackageManager.PERMISSION_GRANTED + } else { + PackageManager.PERMISSION_DENIED + } + }.toIntArray() + ) + ) + } + + @Throws(IllegalStateException::class) + override fun askForPermissions(responseListener: PermissionsResponseListener, vararg permissions: String) { + if (permissions.contains(Manifest.permission.WRITE_SETTINGS) && isRuntimePermissionsAvailable()) { + val permissionsToAsk = permissions.toMutableList().apply { remove(Manifest.permission.WRITE_SETTINGS) }.toTypedArray() + val newListener = PermissionsResponseListener { + val status = if (hasWriteSettingsPermission()) { + PackageManager.PERMISSION_GRANTED + } else { + PackageManager.PERMISSION_DENIED + } + + it[Manifest.permission.WRITE_SETTINGS] = getPermissionResponseFromNativeResponse(Manifest.permission.WRITE_SETTINGS, status) + responseListener.onResult(it) + } + + if (!hasWriteSettingsPermission()) { + if (mAskAsyncListener != null) { + throw IllegalStateException("Another permissions request is in progress. Await the old request and then try again.") + } + mAskAsyncListener = newListener + mAskAsyncRequestedPermissions = permissionsToAsk + + addToAskedPermissionsCache(arrayOf(Manifest.permission.WRITE_SETTINGS)) + askForWriteSettingsPermissionFirst() + } else { + askForManifestPermissions(permissionsToAsk, newListener) + } + } else { + askForManifestPermissions(permissions, responseListener) + } + } + + override fun hasGrantedPermissions(vararg permissions: String): Boolean { + return permissions.all { isPermissionGranted(it) } + } + + /** + * Checks whether given permission is present in AndroidManifest or not. + */ + override fun isPermissionPresentInManifest(permission: String): Boolean { + try { + context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)?.run { + return requestedPermissions.contains(permission) + } + return false + } catch (e: PackageManager.NameNotFoundException) { + return false + } + } + + /** + * Checks status for Android built-in permission + * + * @param permission [android.Manifest.permission] + */ + private fun isPermissionGranted(permission: String): Boolean { + return when (permission) { + // we need to handle this permission in different way + Manifest.permission.WRITE_SETTINGS -> hasWriteSettingsPermission() + else -> getManifestPermission(permission) == PackageManager.PERMISSION_GRANTED + } + } + + /** + * Gets status for Android built-in permission + * + * @param permission [android.Manifest.permission] + */ + private fun getManifestPermission(permission: String): Int { + mActivityProvider?.currentActivity?.let { + if (it is PermissionAwareActivity) { + return ContextCompat.checkSelfPermission(it, permission) + } + } + + // We are in the headless mode. So, we ask current context. + return getManifestPermissionFromContext(permission) + } + + protected open fun getManifestPermissionFromContext(permission: String): Int { + return ContextCompat.checkSelfPermission(context, permission) + } + + private fun canAskAgain(permission: String): Boolean { + return mActivityProvider?.currentActivity?.let { + ActivityCompat.shouldShowRequestPermissionRationale(it, permission) + } ?: false + } + + private fun parseNativeResult(permissionsString: Array, grantResults: IntArray): Map { + return HashMap().apply { + grantResults.zip(permissionsString).forEach { (result, permission) -> + this[permission] = getPermissionResponseFromNativeResponse(permission, result) + } + } + } + + private fun getPermissionResponseFromNativeResponse(permission: String, result: Int): PermissionsResponse { + val status = when { + result == PackageManager.PERMISSION_GRANTED -> PermissionsStatus.GRANTED + didAsk(permission) -> PermissionsStatus.DENIED + else -> PermissionsStatus.UNDETERMINED + } + return PermissionsResponse( + status, + if (status == PermissionsStatus.DENIED) { + canAskAgain(permission) + } else { + true + } + ) + } + + protected open fun askForManifestPermissions(permissions: Array, listener: PermissionsResponseListener) { + if (!isRuntimePermissionsAvailable()) { + // It's not possible to ask for the permissions in the runtime. + // We return to the user the permissions status, which was granted during installation. + addToAskedPermissionsCache(permissions) + val permissionsResult = permissions.map { getManifestPermission(it) }.toIntArray() + listener.onResult(parseNativeResult(permissions, permissionsResult)) + return + } + + delegateRequestToActivity(permissions, listener) + } + + /** + * Asks for Android built-in permission + * According to Android documentation [android.Manifest.permission.WRITE_SETTINGS] need to be handled in different way + * + * @param permissions [android.Manifest.permission] + */ + protected fun delegateRequestToActivity(permissions: Array, listener: PermissionsResponseListener) { + addToAskedPermissionsCache(permissions) + + val currentActivity = mActivityProvider?.currentActivity + if (currentActivity is PermissionAwareActivity) { + synchronized(this@PermissionsService) { + if (mCurrentPermissionListener != null) { + mPendingPermissionCalls.add(permissions to listener) + } else { + mCurrentPermissionListener = listener + currentActivity.requestPermissions(permissions, PERMISSIONS_REQUEST, createListenerWithPendingPermissionsRequest()) + } + } + } else { + listener.onResult(parseNativeResult(permissions, IntArray(permissions.size) { PackageManager.PERMISSION_DENIED })) + } + } + + private fun createListenerWithPendingPermissionsRequest(): PermissionListener { + return PermissionListener { requestCode, receivePermissions, grantResults -> + if (requestCode == PERMISSIONS_REQUEST) { + synchronized(this@PermissionsService) { + val currentListener = requireNotNull(mCurrentPermissionListener) + currentListener.onResult(parseNativeResult(receivePermissions, grantResults)) + mCurrentPermissionListener = null + + mPendingPermissionCalls.poll()?.let { pendingCall -> + val activity = mActivityProvider?.currentActivity as? PermissionAwareActivity + if (activity == null) { + // clear all pending calls, because we don't have access to the activity instance + pendingCall.second.onResult(parseNativeResult(pendingCall.first, IntArray(pendingCall.first.size) { PackageManager.PERMISSION_DENIED })) + mPendingPermissionCalls.forEach { + it.second.onResult(parseNativeResult(it.first, IntArray(it.first.size) { PackageManager.PERMISSION_DENIED })) + } + mPendingPermissionCalls.clear() + return@let + } + + mCurrentPermissionListener = pendingCall.second + activity.requestPermissions(pendingCall.first, PERMISSIONS_REQUEST, createListenerWithPendingPermissionsRequest()) + return@PermissionListener false + } + + return@PermissionListener true + } + } + return@PermissionListener false + } + } + + /** + * Asking for [android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS] via separate activity + * WARNING: has to be asked first among all permissions being asked in request + * Scenario that forces this order: + * 1. user asks for "systemBrightness" (actual [android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS]) and for some other permission (e.g. [android.Manifest.permission.CAMERA]) + * 2. first goes ACTION_MANAGE_WRITE_SETTINGS that moves app into background and launches system-specific fullscreen activity + * 3. upon user action system resumes app and [onHostResume] is being called for the first time and logic for other permission is invoked + * 4. other permission invokes other system-specific activity that is visible as dialog what moves app again into background + * 5. upon user action app is restored and [onHostResume] is being called again, but no further action is invoked and promise is resolved + */ + @TargetApi(Build.VERSION_CODES.M) + private fun askForWriteSettingsPermissionFirst() { + Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS).apply { + data = Uri.parse("package:${context.packageName}") + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + }.let { + mWriteSettingsPermissionBeingAsked = true + context.startActivity(it) + } + } + + private fun hasWriteSettingsPermission(): Boolean { + return if (isRuntimePermissionsAvailable()) { + Settings.System.canWrite(context.applicationContext) + } else { + true + } + } + + private fun isRuntimePermissionsAvailable() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + + override fun onHostResume() { + if (!mWriteSettingsPermissionBeingAsked) { + return + } + mWriteSettingsPermissionBeingAsked = false + + // cleanup + val askAsyncListener = mAskAsyncListener!! + val askAsyncRequestedPermissions = mAskAsyncRequestedPermissions!! + + mAskAsyncListener = null + mAskAsyncRequestedPermissions = null + + if (askAsyncRequestedPermissions.isNotEmpty()) { + // invoke actual asking for permissions + askForManifestPermissions(askAsyncRequestedPermissions, askAsyncListener) + } else { + // user asked only for Manifest.permission.WRITE_SETTINGS + askAsyncListener.onResult(mutableMapOf()) + } + } + + override fun onHostPause() = Unit + + override fun onHostDestroy() = Unit +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/CookieManagerModule.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/CookieManagerModule.java new file mode 100644 index 00000000000000..ec9075f8fd54e6 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/CookieManagerModule.java @@ -0,0 +1,53 @@ +package abi49_0_0.expo.modules.adapters.react.services; + +import abi49_0_0.com.facebook.react.bridge.NativeModule; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.modules.network.ForwardingCookieHandler; + +import java.net.CookieHandler; +import java.util.Collections; +import java.util.List; + +import abi49_0_0.expo.modules.core.interfaces.InternalModule; + +public class CookieManagerModule extends ForwardingCookieHandler implements InternalModule, NativeModule { + private static final String TAG = "CookieManagerModule"; + + public CookieManagerModule(ReactContext context) { + super(context); + } + + @Override + public String getName() { + return null; + } + + @Override + public void initialize() { + // do nothing + } + + @Override + public List getExportedInterfaces() { + return Collections.singletonList((Class) CookieHandler.class); + } + + @Override + public boolean canOverrideExistingModule() { + return false; + } + + // `invalidate` replaces `onCatalystInstanceDestroy` in recent RN versions. We can't use + // @Override here since older versions won't have this method. If one of these methods is + // needed make sure to add the code to both as only one of the methods will be called depending + // on the RN version. + // See https://github.com/facebook/react-native/commit/18c8417290823e67e211bde241ae9dde27b72f17 + public void invalidate() { + // do nothing + } + + @Override + public void onCatalystInstanceDestroy() { + // do nothing + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/EventEmitterModule.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/EventEmitterModule.java new file mode 100644 index 00000000000000..8e99f97d921dff --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/EventEmitterModule.java @@ -0,0 +1,92 @@ +package abi49_0_0.expo.modules.adapters.react.services; + +import android.os.Bundle; + +import abi49_0_0.com.facebook.react.bridge.Arguments; +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.modules.core.DeviceEventManagerModule; +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; +import abi49_0_0.com.facebook.react.uimanager.events.EventDispatcher; +import abi49_0_0.com.facebook.react.uimanager.events.RCTEventEmitter; + +import java.util.Collections; +import java.util.List; + +import abi49_0_0.expo.modules.adapters.react.views.ViewManagerAdapterUtils; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.services.EventEmitter; + +public class EventEmitterModule implements EventEmitter, InternalModule { + private ReactContext mReactContext; + + public EventEmitterModule(ReactContext reactContext) { + mReactContext = reactContext; + } + + @Override + public void emit(String eventName, Bundle eventBody) { + mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, Arguments.fromBundle(eventBody)); + } + + @Override + public void emit(final int viewId, final Event event) { + final EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, viewId); + dispatcher.dispatchEvent(getReactEventFromEvent(viewId, event)); + } + + @Override + public void emit(final int viewId, final String eventName, final Bundle eventBody) { + final EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, viewId); + dispatcher.dispatchEvent(new abi49_0_0.com.facebook.react.uimanager.events.Event(viewId) { + @Override + public String getEventName() { + return ViewManagerAdapterUtils.normalizeEventName(eventName); + } + + @Override + public void dispatch(RCTEventEmitter rctEventEmitter) { + rctEventEmitter.receiveEvent(viewId, getEventName(), eventBody != null ? Arguments.fromBundle(eventBody) : null); + } + + @Override + public boolean canCoalesce() { + return false; + } + + @Override + public short getCoalescingKey() { + return 0; + } + }); + } + + @Override + public List getExportedInterfaces() { + return Collections.singletonList((Class) EventEmitter.class); + } + + private static abi49_0_0.com.facebook.react.uimanager.events.Event getReactEventFromEvent(final int viewId, final Event event) { + return new abi49_0_0.com.facebook.react.uimanager.events.Event(viewId) { + @Override + public String getEventName() { + return ViewManagerAdapterUtils.normalizeEventName(event.getEventName()); + } + + @Override + public void dispatch(RCTEventEmitter rctEventEmitter) { + rctEventEmitter.receiveEvent(viewId, getEventName(), Arguments.fromBundle(event.getEventBody())); + } + + @Override + public boolean canCoalesce() { + return event.canCoalesce(); + } + + @Override + public short getCoalescingKey() { + return event.getCoalescingKey(); + } + }; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/FontManagerModule.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/FontManagerModule.java new file mode 100644 index 00000000000000..06732e7a7ce4c3 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/FontManagerModule.java @@ -0,0 +1,24 @@ +package abi49_0_0.expo.modules.adapters.react.services; + +import android.graphics.Typeface; + +import abi49_0_0.com.facebook.react.views.text.ReactFontManager; + +import java.util.Collections; +import java.util.List; + +import abi49_0_0.expo.modules.core.interfaces.InternalModule; + +import abi49_0_0.expo.modules.interfaces.font.FontManagerInterface; + +public class FontManagerModule implements FontManagerInterface, InternalModule { + @Override + public List getExportedInterfaces() { + return Collections.singletonList(FontManagerInterface.class); + } + + @Override + public void setTypeface(String fontFamilyName, int style, Typeface typeface) { + ReactFontManager.getInstance().setTypeface(fontFamilyName, style, typeface); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/RuntimeEnvironmentModule.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/RuntimeEnvironmentModule.java new file mode 100644 index 00000000000000..b83333eda631e3 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/RuntimeEnvironmentModule.java @@ -0,0 +1,50 @@ +package abi49_0_0.expo.modules.adapters.react.services; + +import abi49_0_0.com.facebook.react.modules.systeminfo.ReactNativeVersion; + +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.RuntimeEnvironmentInterface; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class RuntimeEnvironmentModule implements InternalModule, RuntimeEnvironmentInterface { + + @Override + public List getExportedInterfaces() { + return Collections.singletonList(RuntimeEnvironmentInterface.class); + } + + @Override + public String platformName() { + return "React Native"; + } + + @Override + public RuntimeEnvironmentInterface.PlatformVersion platformVersion() { + final Map version = ReactNativeVersion.VERSION; + + return new RuntimeEnvironmentInterface.PlatformVersion() { + @Override + public int major() { + return (int) version.get("major"); + } + + @Override + public int minor() { + return (int) version.get("minor"); + } + + @Override + public int patch() { + return (int) version.get("patch"); + } + + @Override + public String prerelease() { + return (String) version.get("prerelease"); + } + }; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/UIManagerModuleWrapper.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/UIManagerModuleWrapper.java new file mode 100644 index 00000000000000..43d69999e65e09 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/services/UIManagerModuleWrapper.java @@ -0,0 +1,221 @@ +package abi49_0_0.expo.modules.adapters.react.services; + +import android.app.Activity; +import android.content.Intent; +import android.util.Log; +import android.view.View; + +import androidx.annotation.Nullable; + +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.turbomodule.core.CallInvokerHolderImpl; +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException; +import abi49_0_0.com.facebook.react.uimanager.NativeViewHierarchyManager; +import abi49_0_0.com.facebook.react.uimanager.UIManagerHelper; +import abi49_0_0.com.facebook.react.uimanager.UIManagerModule; + +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import abi49_0_0.expo.modules.core.interfaces.ActivityEventListener; +import abi49_0_0.expo.modules.core.interfaces.ActivityProvider; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.JavaScriptContextProvider; +import abi49_0_0.expo.modules.core.interfaces.LifecycleEventListener; +import abi49_0_0.expo.modules.core.interfaces.services.UIManager; + +public class UIManagerModuleWrapper implements + ActivityProvider, + InternalModule, + JavaScriptContextProvider, + UIManager { + private ReactContext mReactContext; + private Map mLifecycleListenersMap = new WeakHashMap<>(); + private Map mActivityEventListenersMap = new WeakHashMap<>(); + + public UIManagerModuleWrapper(ReactContext reactContext) { + mReactContext = reactContext; + } + + protected ReactContext getContext() { + return mReactContext; + } + + @Override + public List getExportedInterfaces() { + return Arrays.asList( + ActivityProvider.class, + JavaScriptContextProvider.class, + UIManager.class + ); + } + + @Override + public void addUIBlock(final int tag, final UIBlock block, final Class tClass) { + getContext().getNativeModule(UIManagerModule.class).addUIBlock(new abi49_0_0.com.facebook.react.uimanager.UIBlock() { + @Override + public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { + View view = nativeViewHierarchyManager.resolveView(tag); + if (view == null) { + block.reject(new IllegalArgumentException("Expected view for this tag not to be null.")); + } else { + try { + if (tClass.isInstance(view)) { + block.resolve(tClass.cast(view)); + } else { + block.reject(new IllegalStateException( + "Expected view to be of " + tClass + "; found " + view.getClass() + " instead")); + } + } catch (Exception e) { + block.reject(e); + } + } + } + }); + } + + @Override + public void addUIBlock(final GroupUIBlock block) { + getContext().getNativeModule(UIManagerModule.class).addUIBlock(new abi49_0_0.com.facebook.react.uimanager.UIBlock() { + @Override + public void execute(final NativeViewHierarchyManager nativeViewHierarchyManager) { + block.execute(new ViewHolder() { + @Override + public View get(Object key) { + if (key instanceof Number) { + try { + return nativeViewHierarchyManager.resolveView(((Number) key).intValue()); + } catch (IllegalViewOperationException e) { + return null; + } + } else { + Log.w("E_INVALID_TAG", "Provided tag is of class " + key.getClass() + " whereas React expects tags to be integers. Are you sure you're providing proper argument to addUIBlock?"); + } + return null; + } + }); + } + }); + } + + @Nullable + @Override + public View resolveView(int viewTag) { + final abi49_0_0.com.facebook.react.bridge.UIManager uiManager = UIManagerHelper.getUIManagerForReactTag(getContext(), viewTag); + if (uiManager == null) { + return null; + } + return uiManager.resolveView(viewTag); + } + + @Override + public void runOnUiQueueThread(Runnable runnable) { + if (getContext().isOnUiQueueThread()) { + runnable.run(); + } else { + getContext().runOnUiQueueThread(runnable); + } + } + + @Override + public void runOnClientCodeQueueThread(Runnable runnable) { + if (getContext().isOnJSQueueThread()) { + runnable.run(); + } else { + getContext().runOnJSQueueThread(runnable); + } + } + + public void runOnNativeModulesQueueThread(Runnable runnable) { + if (mReactContext.isOnNativeModulesQueueThread()) { + runnable.run(); + } else { + mReactContext.runOnNativeModulesQueueThread(runnable); + } + } + + + @Override + public void registerLifecycleEventListener(final LifecycleEventListener listener) { + final WeakReference weakListener = new WeakReference<>(listener); + mLifecycleListenersMap.put(listener, new abi49_0_0.com.facebook.react.bridge.LifecycleEventListener() { + @Override + public void onHostResume() { + LifecycleEventListener listener = weakListener.get(); + if (listener != null) { + listener.onHostResume(); + } + } + + @Override + public void onHostPause() { + LifecycleEventListener listener = weakListener.get(); + if (listener != null) { + listener.onHostPause(); + } + } + + @Override + public void onHostDestroy() { + LifecycleEventListener listener = weakListener.get(); + if (listener != null) { + listener.onHostDestroy(); + } + } + }); + mReactContext.addLifecycleEventListener(mLifecycleListenersMap.get(listener)); + } + + @Override + public void unregisterLifecycleEventListener(LifecycleEventListener listener) { + getContext().removeLifecycleEventListener(mLifecycleListenersMap.get(listener)); + mLifecycleListenersMap.remove(listener); + } + + @Override + public void registerActivityEventListener(final ActivityEventListener activityEventListener) { + final WeakReference weakListener = new WeakReference<>(activityEventListener); + + mActivityEventListenersMap.put(activityEventListener, new abi49_0_0.com.facebook.react.bridge.ActivityEventListener() { + @Override + public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { + ActivityEventListener listener = weakListener.get(); + if (listener != null) { + listener.onActivityResult(activity, requestCode, resultCode, data); + } + } + + @Override + public void onNewIntent(Intent intent) { + ActivityEventListener listener = weakListener.get(); + if (listener != null) { + listener.onNewIntent(intent); + } + } + }); + + mReactContext.addActivityEventListener(mActivityEventListenersMap.get(activityEventListener)); + } + + @Override + public void unregisterActivityEventListener(final ActivityEventListener activityEventListener) { + getContext().removeActivityEventListener(mActivityEventListenersMap.get(activityEventListener)); + mActivityEventListenersMap.remove(activityEventListener); + } + + public long getJavaScriptContextRef() { + return mReactContext.getJavaScriptContextHolder().get(); + } + + public CallInvokerHolderImpl getJSCallInvokerHolder() { + return (CallInvokerHolderImpl) mReactContext.getCatalystInstance().getJSCallInvokerHolder(); + } + + @Override + public Activity getCurrentActivity() { + return getContext().getCurrentActivity(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/SimpleViewManagerAdapter.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/SimpleViewManagerAdapter.java new file mode 100644 index 00000000000000..552a55d565b4c8 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/SimpleViewManagerAdapter.java @@ -0,0 +1,62 @@ +package abi49_0_0.expo.modules.adapters.react.views; + +import android.view.View; + +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import abi49_0_0.com.facebook.react.uimanager.SimpleViewManager; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; + +import java.util.Map; + +import javax.annotation.Nullable; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.ViewManager; +import abi49_0_0.expo.modules.core.interfaces.RegistryLifecycleListener; + +public class SimpleViewManagerAdapter, V extends View> extends SimpleViewManager implements RegistryLifecycleListener { + private M mViewManager; + + public SimpleViewManagerAdapter(M viewManager) { + mViewManager = viewManager; + } + + @Override + protected V createViewInstance(ThemedReactContext reactContext) { + return mViewManager.createViewInstance(reactContext); + } + + @Override + public void onDropViewInstance(V view) { + mViewManager.onDropViewInstance(view); + super.onDropViewInstance(view); + } + + @Nullable + @Override + public Map getConstants() { + return ViewManagerAdapterUtils.getConstants(mViewManager); + } + + @Override + public String getName() { + return ViewManagerAdapterUtils.getViewManagerAdapterName(mViewManager); + } + + @ReactProp(name = "proxiedProperties") + public void setProxiedProperties(V view, ReadableMap proxiedProperties) { + ViewManagerAdapterUtils.setProxiedProperties(getName(), mViewManager, view, proxiedProperties); + } + + @Nullable + @Override + public Map getExportedCustomDirectEventTypeConstants() { + return ViewManagerAdapterUtils.getExportedCustomDirectEventTypeConstants(mViewManager); + } + + @Override + public void onCreate(ModuleRegistry moduleRegistry) { + mViewManager.onCreate(moduleRegistry); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/ViewGroupManagerAdapter.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/ViewGroupManagerAdapter.java new file mode 100644 index 00000000000000..770ea540ef78dd --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/ViewGroupManagerAdapter.java @@ -0,0 +1,62 @@ +package abi49_0_0.expo.modules.adapters.react.views; + +import android.view.ViewGroup; + +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.uimanager.ViewGroupManager; +import abi49_0_0.com.facebook.react.uimanager.ThemedReactContext; +import abi49_0_0.com.facebook.react.uimanager.annotations.ReactProp; + +import java.util.Map; + +import javax.annotation.Nullable; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.ViewManager; +import abi49_0_0.expo.modules.core.interfaces.RegistryLifecycleListener; + +public class ViewGroupManagerAdapter, V extends ViewGroup> extends ViewGroupManager implements RegistryLifecycleListener { + private M mViewManager; + + public ViewGroupManagerAdapter(M viewManager) { + mViewManager = viewManager; + } + + @Override + protected V createViewInstance(ThemedReactContext reactContext) { + return mViewManager.createViewInstance(reactContext); + } + + @Override + public void onDropViewInstance(V view) { + mViewManager.onDropViewInstance(view); + super.onDropViewInstance(view); + } + + @Nullable + @Override + public Map getConstants() { + return ViewManagerAdapterUtils.getConstants(mViewManager); + } + + @Override + public String getName() { + return ViewManagerAdapterUtils.getViewManagerAdapterName(mViewManager); + } + + @ReactProp(name = "proxiedProperties") + public void setProxiedProperties(V view, ReadableMap proxiedProperties) { + ViewManagerAdapterUtils.setProxiedProperties(getName(), mViewManager, view, proxiedProperties); + } + + @Nullable + @Override + public Map getExportedCustomDirectEventTypeConstants() { + return ViewManagerAdapterUtils.getExportedCustomDirectEventTypeConstants(mViewManager); + } + + @Override + public void onCreate(ModuleRegistry moduleRegistry) { + mViewManager.onCreate(moduleRegistry); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/ViewManagerAdapterUtils.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/ViewManagerAdapterUtils.java new file mode 100644 index 00000000000000..9fc267ffae6557 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/adapters/react/views/ViewManagerAdapterUtils.java @@ -0,0 +1,64 @@ +package abi49_0_0.expo.modules.adapters.react.views; + +import android.util.Log; +import android.view.View; + +import abi49_0_0.com.facebook.react.bridge.Dynamic; +import abi49_0_0.com.facebook.react.bridge.ReadableMap; +import abi49_0_0.com.facebook.react.bridge.ReadableMapKeySetIterator; +import abi49_0_0.com.facebook.react.common.MapBuilder; + +import java.util.HashMap; +import java.util.Map; + +import abi49_0_0.expo.modules.adapters.react.ArgumentsHelper; +import abi49_0_0.expo.modules.core.ViewManager; + +public class ViewManagerAdapterUtils { + /* package */ static String getViewManagerAdapterName(ViewManager viewManager) { + return "ViewManagerAdapter_" + viewManager.getName(); + } + + /* package */ static Map getConstants(ViewManager viewManager) { + Map constants = new HashMap<>(); + constants.put("eventNames", viewManager.getExportedEventNames()); + return constants; + } + + /* package */ static Map getExportedCustomDirectEventTypeConstants(ViewManager viewManager) { + MapBuilder.Builder builder = MapBuilder.builder(); + // Somehow Java compiler thinks getExportedEventNames() returns list of Objects. + // ¯\_(ツ)_/¯ + for (Object eventName : viewManager.getExportedEventNames()) { + if (eventName instanceof String) { + builder.put(normalizeEventName((String) eventName), MapBuilder.of("registrationName", eventName)); + } + } + return builder.build(); + } + + /* package */ static void setProxiedProperties(String viewManagerAdapterName, ViewManager viewManager, V view, ReadableMap proxiedProperties) { + ReadableMapKeySetIterator keyIterator = proxiedProperties.keySetIterator(); + while (keyIterator.hasNextKey()) { + String key = keyIterator.nextKey(); + try { + ViewManager.PropSetterInfo propSetterInfo = viewManager.getPropSetterInfos().get(key); + if (propSetterInfo == null) { + throw new IllegalArgumentException("No setter found for prop " + key + " in " + viewManagerAdapterName); + } + Dynamic dynamicPropertyValue = proxiedProperties.getDynamic(key); + Object castPropertyValue = ArgumentsHelper.getNativeArgumentForExpectedClass(dynamicPropertyValue, propSetterInfo.getExpectedValueClass()); + viewManager.updateProp(view, key, castPropertyValue); + } catch (Exception e) { + Log.e(viewManagerAdapterName, "Error when setting prop " + key + ". " + e.getMessage()); + } + } + } + + public static String normalizeEventName(final String eventName) { + if (eventName.startsWith("on")) { + return "top" + eventName.substring(2); + } + return eventName; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/application/ApplicationModule.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/application/ApplicationModule.kt new file mode 100644 index 00000000000000..6928c9d29ba036 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/application/ApplicationModule.kt @@ -0,0 +1,133 @@ +package abi49_0_0.expo.modules.application + +import android.app.Activity +import android.content.Context +import android.content.pm.PackageInfo +import android.content.pm.PackageManager.NameNotFoundException +import android.os.Build +import android.os.RemoteException +import android.provider.Settings +import android.util.Log + +import com.android.installreferrer.api.InstallReferrerClient +import com.android.installreferrer.api.InstallReferrerStateListener + +import abi49_0_0.expo.modules.core.ExportedModule +import abi49_0_0.expo.modules.core.ModuleRegistry +import abi49_0_0.expo.modules.core.Promise +import abi49_0_0.expo.modules.core.interfaces.ActivityProvider +import abi49_0_0.expo.modules.core.interfaces.ExpoMethod +import abi49_0_0.expo.modules.core.interfaces.RegistryLifecycleListener + +import java.util.* + +private const val NAME = "ExpoApplication" +private val TAG = ApplicationModule::class.java.simpleName + +class ApplicationModule(private val mContext: Context) : ExportedModule(mContext), RegistryLifecycleListener { + private var mModuleRegistry: ModuleRegistry? = null + private var mActivityProvider: ActivityProvider? = null + private var mActivity: Activity? = null + + override fun getName(): String { + return NAME + } + + override fun onCreate(moduleRegistry: ModuleRegistry) { + mModuleRegistry = moduleRegistry + mActivityProvider = moduleRegistry.getModule(ActivityProvider::class.java) + mActivity = mActivityProvider?.currentActivity + } + + override fun getConstants(): Map { + val constants = HashMap() + val applicationName = mContext.applicationInfo.loadLabel(mContext.packageManager).toString() + val packageName = mContext.packageName + + constants["applicationName"] = applicationName + constants["applicationId"] = packageName + + val packageManager = mContext.packageManager + try { + val pInfo = packageManager.getPackageInfo(packageName, 0) + constants["nativeApplicationVersion"] = pInfo.versionName + val versionCode = getLongVersionCode(pInfo).toInt() + constants["nativeBuildVersion"] = versionCode.toString() + } catch (e: NameNotFoundException) { + Log.e(TAG, "Exception: ", e) + } + + constants["androidId"] = Settings.Secure.getString(mContext.contentResolver, Settings.Secure.ANDROID_ID) + + return constants + } + + @ExpoMethod + fun getInstallationTimeAsync(promise: Promise) { + val packageManager = mContext.packageManager + val packageName = mContext.packageName + try { + val info = packageManager.getPackageInfo(packageName, 0) + promise.resolve(info.firstInstallTime.toDouble()) + } catch (e: NameNotFoundException) { + Log.e(TAG, "Exception: ", e) + promise.reject("ERR_APPLICATION_PACKAGE_NAME_NOT_FOUND", "Unable to get install time of this application. Could not get package info or package name.", e) + } + } + + @ExpoMethod + fun getLastUpdateTimeAsync(promise: Promise) { + val packageManager = mContext.packageManager + val packageName = mContext.packageName + try { + val info = packageManager.getPackageInfo(packageName, 0) + promise.resolve(info.lastUpdateTime.toDouble()) + } catch (e: NameNotFoundException) { + Log.e(TAG, "Exception: ", e) + promise.reject("ERR_APPLICATION_PACKAGE_NAME_NOT_FOUND", "Unable to get last update time of this application. Could not get package info or package name.", e) + } + } + + @ExpoMethod + fun getInstallReferrerAsync(promise: Promise) { + val installReferrer = StringBuilder() + val referrerClient = InstallReferrerClient.newBuilder(mContext).build() + referrerClient.startConnection(object : InstallReferrerStateListener { + override fun onInstallReferrerSetupFinished(responseCode: Int) { + when (responseCode) { + InstallReferrerClient.InstallReferrerResponse.OK -> { + // Connection established and response received + try { + val response = referrerClient.installReferrer + installReferrer.append(response.installReferrer) + } catch (e: RemoteException) { + Log.e(TAG, "Exception: ", e) + promise.reject("ERR_APPLICATION_INSTALL_REFERRER_REMOTE_EXCEPTION", "RemoteException getting install referrer information. This may happen if the process hosting the remote object is no longer available.", e) + } + promise.resolve(installReferrer.toString()) + } + InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> // API not available in the current Play Store app + promise.reject("ERR_APPLICATION_INSTALL_REFERRER_UNAVAILABLE", "The current Play Store app doesn't provide the installation referrer API, or the Play Store may not be installed.") + InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> // Connection could not be established + promise.reject("ERR_APPLICATION_INSTALL_REFERRER_CONNECTION", "Could not establish a connection to Google Play") + else -> promise.reject("ERR_APPLICATION_INSTALL_REFERRER", "General error retrieving the install referrer: response code $responseCode") + } + referrerClient.endConnection() + } + + override fun onInstallReferrerServiceDisconnected() { + promise.reject("ERR_APPLICATION_INSTALL_REFERRER_SERVICE_DISCONNECTED", "Connection to install referrer service was lost.") + } + }) + } + + companion object { + private fun getLongVersionCode(info: PackageInfo): Long { + return if (Build.VERSION.SDK_INT >= 28) { + info.longVersionCode + } else { + info.versionCode.toLong() + } + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/application/ApplicationPackage.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/application/ApplicationPackage.kt new file mode 100644 index 00000000000000..48bcdc483325e3 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/application/ApplicationPackage.kt @@ -0,0 +1,11 @@ +package abi49_0_0.expo.modules.application + +import android.content.Context +import abi49_0_0.expo.modules.core.BasePackage +import abi49_0_0.expo.modules.core.ExportedModule + +class ApplicationPackage : BasePackage() { + override fun createExportedModules(context: Context): List { + return listOf(ApplicationModule(context) as ExportedModule) + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVManager.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVManager.java new file mode 100644 index 00000000000000..474a6dd23f70d1 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVManager.java @@ -0,0 +1,941 @@ +// Copyright 2015-present 650 Industries. All rights reserved. + +package abi49_0_0.expo.modules.av; + +import android.Manifest; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioDeviceInfo; +import android.media.AudioManager; +import android.media.MediaRecorder; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.SystemClock; +import android.view.View; + +import com.facebook.jni.HybridData; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.Promise; +import abi49_0_0.expo.modules.core.arguments.ReadableArguments; +import abi49_0_0.expo.modules.core.interfaces.DoNotStrip; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.core.interfaces.JavaScriptContextProvider; +import abi49_0_0.expo.modules.core.interfaces.LifecycleEventListener; +import abi49_0_0.expo.modules.core.interfaces.services.EventEmitter; +import abi49_0_0.expo.modules.core.interfaces.services.UIManager; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import abi49_0_0.expo.modules.av.player.PlayerData; +import abi49_0_0.expo.modules.av.video.VideoView; +import abi49_0_0.expo.modules.av.video.VideoViewWrapper; +import abi49_0_0.expo.modules.interfaces.permissions.Permissions; +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsResponseListener; + +import abi49_0_0.com.facebook.react.bridge.ReactContext; +import abi49_0_0.com.facebook.react.turbomodule.core.CallInvokerHolderImpl; + +import static android.media.MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED; + +public class AVManager implements LifecycleEventListener, AudioManager.OnAudioFocusChangeListener, MediaRecorder.OnInfoListener, AVManagerInterface, InternalModule { + static { + System.loadLibrary("expo-av_abi49_0_0"); + } + + private static final String AUDIO_MODE_SHOULD_DUCK_KEY = "shouldDuckAndroid"; + private static final String AUDIO_MODE_INTERRUPTION_MODE_KEY = "interruptionModeAndroid"; + private static final String AUDIO_MODE_PLAY_THROUGH_EARPIECE = "playThroughEarpieceAndroid"; + private static final String AUDIO_MODE_STAYS_ACTIVE_IN_BACKGROUND = "staysActiveInBackground"; + + private static final String RECORDING_OPTION_IS_METERING_ENABLED_KEY = "isMeteringEnabled"; + private static final String RECORDING_OPTIONS_KEY = "android"; + private static final String RECORDING_OPTION_EXTENSION_KEY = "extension"; + private static final String RECORDING_OPTION_OUTPUT_FORMAT_KEY = "outputFormat"; + private static final String RECORDING_OPTION_AUDIO_ENCODER_KEY = "audioEncoder"; + private static final String RECORDING_OPTION_SAMPLE_RATE_KEY = "sampleRate"; + private static final String RECORDING_OPTION_NUMBER_OF_CHANNELS_KEY = "numberOfChannels"; + private static final String RECORDING_OPTION_BIT_RATE_KEY = "bitRate"; + private static final String RECORDING_OPTION_MAX_FILE_SIZE_KEY = "maxFileSize"; + + private static final String RECORDING_INPUT_NAME_KEY = "name"; + private static final String RECORDING_INPUT_TYPE_KEY = "type"; + private static final String RECORDING_INPUT_UID_KEY = "uid"; + + @DoNotStrip + private final HybridData mHybridData; + + private boolean mShouldRouteThroughEarpiece = false; + + private enum AudioInterruptionMode { + DO_NOT_MIX, + DUCK_OTHERS, + } + + private final Context mContext; + + private boolean mEnabled = true; + + private final AudioManager mAudioManager; + private final BroadcastReceiver mNoisyAudioStreamReceiver; + private boolean mAcquiredAudioFocus = false; + + private boolean mAppIsPaused = false; + + private AudioInterruptionMode mAudioInterruptionMode = AudioInterruptionMode.DUCK_OTHERS; + private boolean mShouldDuckAudio = true; + private boolean mIsDuckingAudio = false; + private boolean mStaysActiveInBackground = false; + + private int mSoundMapKeyCount = 0; + // There will never be many PlayerData objects in the map, so HashMap is most efficient. + private final Map mSoundMap = new HashMap<>(); + private final Set mVideoViewSet = new HashSet<>(); + + private MediaRecorder mAudioRecorder = null; + private String mAudioRecordingFilePath = null; + private long mAudioRecorderUptimeOfLastStartResume = 0L; + private long mAudioRecorderDurationAlreadyRecorded = 0L; + private boolean mAudioRecorderIsRecording = false; + private boolean mAudioRecorderIsPaused = false; + private boolean mIsRegistered = false; + private boolean mAudioRecorderIsMeteringEnabled = false; + + private ModuleRegistry mModuleRegistry; + + public AVManager(final Context reactContext) { + mContext = reactContext; + + mAudioManager = (AudioManager) reactContext.getSystemService(Context.AUDIO_SERVICE); + // Implemented because of the suggestion here: + // https://developer.android.com/guide/topics/media-apps/volume-and-earphones.html + mNoisyAudioStreamReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) { + abandonAudioFocus(); + } + } + }; + mContext.registerReceiver(mNoisyAudioStreamReceiver, + new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); + mIsRegistered = true; + + + mHybridData = initHybrid(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + mHybridData.resetNative(); + } + + @SuppressWarnings("JavaJniMissingFunction") + private native HybridData initHybrid(); + @SuppressWarnings("JavaJniMissingFunction") + private native void installJSIBindings(long jsRuntimePointer, CallInvokerHolderImpl jsCallInvokerHolder); + + @SuppressWarnings("unused") + @DoNotStrip + private PlayerData getMediaPlayerById(int id) { + return mSoundMap.get(id); + } + + @Override + public ModuleRegistry getModuleRegistry() { + return mModuleRegistry; + } + + private UIManager getUIManager() { + return mModuleRegistry.getModule(UIManager.class); + } + + @Override + public void onCreate(ModuleRegistry moduleRegistry) { + if (mModuleRegistry != null) { + getUIManager().unregisterLifecycleEventListener(this); + } + mModuleRegistry = moduleRegistry; + if (mModuleRegistry != null) { + final UIManager uiManager = getUIManager(); + + uiManager.registerLifecycleEventListener(this); + uiManager.runOnClientCodeQueueThread(() -> { + final JavaScriptContextProvider jsContextProvider = mModuleRegistry.getModule(JavaScriptContextProvider.class); + final long jsContextRef = jsContextProvider.getJavaScriptContextRef(); + if (jsContextRef != 0) { + installJSIBindings(jsContextRef, jsContextProvider.getJSCallInvokerHolder()); + } + }); + } + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public List getExportedInterfaces() { + return Collections.singletonList((Class) AVManagerInterface.class); + } + + private void sendEvent(String eventName, Bundle params) { + if (mModuleRegistry != null) { + EventEmitter eventEmitter = mModuleRegistry.getModule(EventEmitter.class); + if (eventEmitter != null) { + eventEmitter.emit(eventName, params); + } + } + } + + // LifecycleEventListener + + @Override + public void onHostResume() { + if (mAppIsPaused) { + mAppIsPaused = false; + if (!mStaysActiveInBackground) { + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + handler.onResume(); + } + if (mShouldRouteThroughEarpiece) { + updatePlaySoundThroughEarpiece(true); + } + } + } + } + + @Override + public void onHostPause() { + if (!mAppIsPaused) { + mAppIsPaused = true; + if (!mStaysActiveInBackground) { + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + handler.onPause(); + } + abandonAudioFocus(); + + if (mShouldRouteThroughEarpiece) { + updatePlaySoundThroughEarpiece(false); + } + } + } + } + + @Override + public void onHostDestroy() { + if (mIsRegistered) { + mContext.unregisterReceiver(mNoisyAudioStreamReceiver); + mIsRegistered = false; + } + + // remove all remaining sounds + Iterator iter = mSoundMap.values().iterator(); + while (iter.hasNext()) { + final PlayerData data = iter.next(); + iter.remove(); + if (data != null) { + data.release(); + } + } + + for (final VideoView videoView : mVideoViewSet) { + videoView.unloadPlayerAndMediaController(); + } + + removeAudioRecorder(); + abandonAudioFocus(); + } + + // Global audio state control API + + @Override + public void registerVideoViewForAudioLifecycle(final VideoView videoView) { + mVideoViewSet.add(videoView); + } + + @Override + public void unregisterVideoViewForAudioLifecycle(final VideoView videoView) { + mVideoViewSet.remove(videoView); + } + + private Set getAllRegisteredAudioEventHandlers() { + final Set set = new HashSet<>(); + set.addAll(mVideoViewSet); + set.addAll(mSoundMap.values()); + return set; + } + + @Override // AudioManager.OnAudioFocusChangeListener + public void onAudioFocusChange(int focusChange) { + switch (focusChange) { + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + if (mShouldDuckAudio) { + mIsDuckingAudio = true; + mAcquiredAudioFocus = true; + updateDuckStatusForAllPlayersPlaying(); + break; + } // Otherwise, it is treated as AUDIOFOCUS_LOSS_TRANSIENT: + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + case AudioManager.AUDIOFOCUS_LOSS: + mIsDuckingAudio = false; + mAcquiredAudioFocus = false; + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + handler.handleAudioFocusInterruptionBegan(); + } + break; + case AudioManager.AUDIOFOCUS_GAIN: + mIsDuckingAudio = false; + mAcquiredAudioFocus = true; + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + handler.handleAudioFocusGained(); + } + break; + } + } + + @Override + public void acquireAudioFocus() throws AudioFocusNotAcquiredException { + if (!mEnabled) { + throw new AudioFocusNotAcquiredException("Expo Audio is disabled, so audio focus could not be acquired."); + } + + if (mAppIsPaused && !mStaysActiveInBackground) { + throw new AudioFocusNotAcquiredException("This experience is currently in the background, so audio focus could not be acquired."); + } + + if (mAcquiredAudioFocus) { + return; + } + + final int audioFocusRequest = mAudioInterruptionMode == AudioInterruptionMode.DO_NOT_MIX + ? AudioManager.AUDIOFOCUS_GAIN : AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; + + int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, audioFocusRequest); + mAcquiredAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + if (!mAcquiredAudioFocus) { + throw new AudioFocusNotAcquiredException("Audio focus could not be acquired from the OS at this time."); + } + } + + private void abandonAudioFocus() { + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + if (handler.requiresAudioFocus()) { + handler.pauseImmediately(); + } + } + mAcquiredAudioFocus = false; + mAudioManager.abandonAudioFocus(this); + } + + public void abandonAudioFocusIfUnused() { // used by PlayerData + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + if (handler.requiresAudioFocus()) { + return; + } + } + abandonAudioFocus(); + } + + @Override + public float getVolumeForDuckAndFocus(final boolean isMuted, final float volume) { + return (!mAcquiredAudioFocus || isMuted) ? 0f : mIsDuckingAudio ? volume / 2f : volume; + } + + private void updateDuckStatusForAllPlayersPlaying() { + for (final AudioEventHandler handler : getAllRegisteredAudioEventHandlers()) { + handler.updateVolumeMuteAndDuck(); + } + } + + private void updatePlaySoundThroughEarpiece(boolean playThroughEarpiece) { + mAudioManager.setMode(playThroughEarpiece ? AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_NORMAL); + mAudioManager.setSpeakerphoneOn(!playThroughEarpiece); + } + + @Override + public void setAudioIsEnabled(final Boolean value) { + mEnabled = value; + if (!value) { + getUIManager().runOnUiQueueThread(this::abandonAudioFocus); + } + } + + @Override + public void setAudioMode(final ReadableArguments map) { + mShouldDuckAudio = map.getBoolean(AUDIO_MODE_SHOULD_DUCK_KEY); + if (!mShouldDuckAudio) { + mIsDuckingAudio = false; + getUIManager().runOnUiQueueThread(this::updateDuckStatusForAllPlayersPlaying); + } + + if (map.containsKey(AUDIO_MODE_PLAY_THROUGH_EARPIECE)) { + mShouldRouteThroughEarpiece = map.getBoolean(AUDIO_MODE_PLAY_THROUGH_EARPIECE); + updatePlaySoundThroughEarpiece(mShouldRouteThroughEarpiece); + } + + final int interruptionModeInt = map.getInt(AUDIO_MODE_INTERRUPTION_MODE_KEY); + switch (interruptionModeInt) { + case 1: + mAudioInterruptionMode = AudioInterruptionMode.DO_NOT_MIX; + break; + case 2: + default: + mAudioInterruptionMode = AudioInterruptionMode.DUCK_OTHERS; + } + + mStaysActiveInBackground = map.getBoolean(AUDIO_MODE_STAYS_ACTIVE_IN_BACKGROUND); + } + + // Unified playback API - Audio + + // Rejects the promise and returns null if the PlayerData is not found. + private PlayerData tryGetSoundForKey(final Integer key, final Promise promise) { + final PlayerData data = this.mSoundMap.get(key); + if (data == null && promise != null) { + promise.reject("E_AUDIO_NOPLAYER", "Player does not exist."); + } + return data; + } + + private void removeSoundForKey(final Integer key) { + final PlayerData data = mSoundMap.remove(key); + if (data != null) { + data.release(); + abandonAudioFocusIfUnused(); + } + } + + @Override + public void loadForSound(final ReadableArguments source, final ReadableArguments status, final Promise promise) { + getUIManager().runOnUiQueueThread(() -> { + final int key = mSoundMapKeyCount++; + final PlayerData data = PlayerData.createUnloadedPlayerData(this, mContext, source, status.toBundle()); + data.setErrorListener(new PlayerData.ErrorListener() { + @Override + public void onError(final String error) { + removeSoundForKey(key); + } + }); + mSoundMap.put(key, data); + data.load(status.toBundle(), new PlayerData.LoadCompletionListener() { + @Override + public void onLoadSuccess(final Bundle status) { + promise.resolve(Arrays.asList(key, status)); + } + + @Override + public void onLoadError(final String error) { + mSoundMap.remove(key); + promise.reject("E_LOAD_ERROR", error, null); + } + }); + + data.setStatusUpdateListener(new PlayerData.StatusUpdateListener() { + @Override + public void onStatusUpdate(final Bundle status) { + Bundle payload = new Bundle(); + payload.putInt("key", key); + payload.putBundle("status", status); + sendEvent("didUpdatePlaybackStatus", payload); + } + }); + }); + } + + @Override + public void unloadForSound(final Integer key, final Promise promise) { + getUIManager().runOnUiQueueThread(() -> { + if (tryGetSoundForKey(key, promise) != null) { + removeSoundForKey(key); + promise.resolve(PlayerData.getUnloadedStatus()); + } // Otherwise, tryGetSoundForKey has already rejected the promise. + }); + } + + @Override + public void setStatusForSound(final Integer key, final ReadableArguments status, final Promise promise) { + getUIManager().runOnUiQueueThread(() -> { + final PlayerData data = tryGetSoundForKey(key, promise); + if (data != null) { + data.setStatus(status.toBundle(), promise); + } // Otherwise, tryGetSoundForKey has already rejected the promise. + }); + } + + @Override + public void replaySound(final Integer key, final ReadableArguments status, final Promise promise) { + getUIManager().runOnUiQueueThread(() -> { + final PlayerData data = tryGetSoundForKey(key, promise); + if (data != null) { + data.setStatus(status.toBundle(), promise); + } // Otherwise, tryGetSoundForKey has already rejected the promise. + }); + } + + @Override + public void getStatusForSound(final Integer key, final Promise promise) { + getUIManager().runOnUiQueueThread(() -> { + final PlayerData data = tryGetSoundForKey(key, promise); + if (data != null) { + promise.resolve(data.getStatus()); + } // Otherwise, tryGetSoundForKey has already rejected the promise. + }); + } + + // Unified playback API - Video + + @Override + public void loadForVideo(final Integer tag, final ReadableArguments source, final ReadableArguments status, final Promise promise) { + ViewUtils.tryRunWithVideoView(mModuleRegistry, tag, new ViewUtils.VideoViewCallback() { + @Override + public void runWithVideoView(final VideoView videoView) { + videoView.setSource(source, status, promise); + } + }, promise); // Otherwise, tryRunWithVideoView has already rejected the promise. + } + + @Override + public void unloadForVideo(final Integer tag, final Promise promise) { + ViewUtils.tryRunWithVideoView(mModuleRegistry, tag, new ViewUtils.VideoViewCallback() { + @Override + public void runWithVideoView(final VideoView videoView) { + videoView.setSource(null, null, promise); + } + }, promise); // Otherwise, tryRunWithVideoView has already rejected the promise. + } + + @Override + public void setStatusForVideo(final Integer tag, final ReadableArguments status, final Promise promise) { + ViewUtils.tryRunWithVideoView(mModuleRegistry, tag, new ViewUtils.VideoViewCallback() { + @Override + public void runWithVideoView(final VideoView videoView) { + videoView.setStatus(status, promise); + } + }, promise); // Otherwise, tryRunWithVideoView has already rejected the promise. + } + + @Override + public void replayVideo(final Integer tag, final ReadableArguments status, final Promise promise) { + ViewUtils.tryRunWithVideoView(mModuleRegistry, tag, new ViewUtils.VideoViewCallback() { + @Override + public void runWithVideoView(final VideoView videoView) { + videoView.setStatus(status, promise); + } + }, promise); // Otherwise, tryRunWithVideoView has already rejected the promise. + } + + @Override + public void getStatusForVideo(final Integer tag, final Promise promise) { + ViewUtils.tryRunWithVideoView(mModuleRegistry, tag, new ViewUtils.VideoViewCallback() { + @Override + public void runWithVideoView(final VideoView videoView) { + promise.resolve(videoView.getStatus()); + } + }, promise); // Otherwise, tryRunWithVideoView has already rejected the promise. + } + + // Note that setStatusUpdateCallback happens in the JS for video via onStatusUpdate + + // Recording API + + public boolean hasAudioPermission() { + return mModuleRegistry.getModule(Permissions.class).hasGrantedPermissions(Manifest.permission.RECORD_AUDIO); + } + + public void requestAudioPermission(PermissionsResponseListener permissionsResponseListener) { + mModuleRegistry.getModule(Permissions.class).askForPermissions(permissionsResponseListener, Manifest.permission.RECORD_AUDIO); + } + + private boolean isMissingAudioRecordingPermissions() { + return !hasAudioPermission(); + } + + // Rejects the promise and returns false if the MediaRecorder is not found. + private boolean checkAudioRecorderExistsOrReject(final Promise promise) { + if (mAudioRecorder == null && promise != null) { + promise.reject("E_AUDIO_NORECORDER", "Recorder does not exist."); + } + return mAudioRecorder != null; + } + + private long getAudioRecorderDurationMillis() { + if (mAudioRecorder == null) { + return 0L; + } + long duration = mAudioRecorderDurationAlreadyRecorded; + if (mAudioRecorderIsRecording && mAudioRecorderUptimeOfLastStartResume > 0) { + duration += SystemClock.uptimeMillis() - mAudioRecorderUptimeOfLastStartResume; + } + return duration; + } + + private int getAudioRecorderLevels() { + /** + * Defaulting to -160 to match the scenario on iOS platform when there's no sound + */ + if (mAudioRecorder == null || !mAudioRecorderIsMeteringEnabled) { + return -160; + } + + int amplitude = mAudioRecorder.getMaxAmplitude(); + if (amplitude == 0) { + return -160; + } + + // Amplitude to decibel conversion. + // Code copied from https://github.com/punarinta/react-native-sound-level + // It's supposed to be a ratio between the base sound level and the measured one. + // Decibels is a relative measurement. + // Value `32767d` gives levels info comparable to iOS's values. + // see: https://github.com/punarinta/react-native-sound-level/issues/20 + return (int) (20 * Math.log(((double) amplitude) / 32767d)); + } + + private Bundle getAudioRecorderStatus() { + final Bundle map = new Bundle(); + if (mAudioRecorder != null) { + map.putBoolean("canRecord", true); + map.putBoolean("isRecording", mAudioRecorderIsRecording); + map.putInt("durationMillis", (int) getAudioRecorderDurationMillis()); + + if (mAudioRecorderIsMeteringEnabled) { + map.putInt("metering", (int) getAudioRecorderLevels()); + } + } + return map; + } + + private void removeAudioRecorder() { + if (mAudioRecorder != null) { + try { + mAudioRecorder.stop(); + } catch (final RuntimeException e) { + // Do nothing-- this just means that the recorder is already stopped, + // or was stopped immediately after starting. + } + mAudioRecorder.release(); + mAudioRecorder = null; + } + + mAudioRecordingFilePath = null; + mAudioRecorderIsRecording = false; + mAudioRecorderIsPaused = false; + mAudioRecorderDurationAlreadyRecorded = 0L; + mAudioRecorderUptimeOfLastStartResume = 0L; + } + + @Override + public void onInfo(final MediaRecorder mr, final int what, final int extra) { + switch (what) { + case MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED: + removeAudioRecorder(); + if (mModuleRegistry != null) { + EventEmitter eventEmitter = mModuleRegistry.getModule(EventEmitter.class); + if (eventEmitter != null) { + eventEmitter.emit("Expo.Recording.recorderUnloaded", new Bundle()); + } + } + default: + // Do nothing + } + } + + @Override + public void prepareAudioRecorder(final ReadableArguments options, final Promise promise) { + if (isMissingAudioRecordingPermissions()) { + promise.reject("E_MISSING_PERMISSION", "Missing audio recording permissions."); + return; + } + + mAudioRecorderIsMeteringEnabled + = options.getBoolean(RECORDING_OPTION_IS_METERING_ENABLED_KEY); + + removeAudioRecorder(); + + final ReadableArguments androidOptions = options.getArguments(RECORDING_OPTIONS_KEY); + + final String filename = "recording-" + UUID.randomUUID().toString() + + androidOptions.getString(RECORDING_OPTION_EXTENSION_KEY); + try { + final File directory = new File(mContext.getCacheDir() + File.separator + "Audio"); + ensureDirExists(directory); + mAudioRecordingFilePath = directory + File.separator + filename; + } catch (final IOException e) { + // This only occurs in the case that the scoped path is not in this experience's scope, + // which is never true. + } + + mAudioRecorder = new MediaRecorder(); + mAudioRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); + + mAudioRecorder.setOutputFormat(androidOptions.getInt(RECORDING_OPTION_OUTPUT_FORMAT_KEY)); + mAudioRecorder.setAudioEncoder(androidOptions.getInt(RECORDING_OPTION_AUDIO_ENCODER_KEY)); + if (androidOptions.containsKey(RECORDING_OPTION_SAMPLE_RATE_KEY)) { + mAudioRecorder.setAudioSamplingRate(androidOptions.getInt(RECORDING_OPTION_SAMPLE_RATE_KEY)); + } + if (androidOptions.containsKey(RECORDING_OPTION_NUMBER_OF_CHANNELS_KEY)) { + mAudioRecorder.setAudioChannels(androidOptions.getInt(RECORDING_OPTION_NUMBER_OF_CHANNELS_KEY)); + } + if (androidOptions.containsKey(RECORDING_OPTION_BIT_RATE_KEY)) { + mAudioRecorder.setAudioEncodingBitRate(androidOptions.getInt(RECORDING_OPTION_BIT_RATE_KEY)); + } + + mAudioRecorder.setOutputFile(mAudioRecordingFilePath); + + if (androidOptions.containsKey(RECORDING_OPTION_MAX_FILE_SIZE_KEY)) { + mAudioRecorder.setMaxFileSize(androidOptions.getInt(RECORDING_OPTION_MAX_FILE_SIZE_KEY)); + mAudioRecorder.setOnInfoListener(this); + } + + try { + mAudioRecorder.prepare(); + } catch (final Exception e) { + promise.reject("E_AUDIO_RECORDERNOTCREATED", "Prepare encountered an error: recorder not prepared", e); + removeAudioRecorder(); + return; + } + + final Bundle map = new Bundle(); + map.putString("uri", Uri.fromFile(new File(mAudioRecordingFilePath)).toString()); + map.putBundle("status", getAudioRecorderStatus()); + promise.resolve(map); + } + + private AudioDeviceInfo getDeviceInfoFromUid(String uid) { + AudioDeviceInfo deviceInfo = null; + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) { + return deviceInfo; + } + + int id = Integer.valueOf(uid); + AudioDeviceInfo[] audioDevices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); + for (AudioDeviceInfo device : audioDevices) { + int deviceId = device.getId(); + if (deviceId == id) { + return device; + } + } + return null; + } + + private Bundle getMapFromDeviceInfo(AudioDeviceInfo deviceInfo) { + Bundle map = new Bundle(); + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) { + return map; + } + int type = deviceInfo.getType(); + String typeStr = String.valueOf(type); + if (type == AudioDeviceInfo.TYPE_BUILTIN_MIC) { + typeStr = "MicrophoneBuiltIn"; + } else if (type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { + typeStr = "BluetoothSCO"; + } else if (type == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) { + typeStr = "BluetoothA2DP"; + } else if (type == AudioDeviceInfo.TYPE_TELEPHONY) { + typeStr = "Telephony"; + } else if (type == AudioDeviceInfo.TYPE_WIRED_HEADSET) { + typeStr = "MicrophoneWired"; + } + map.putString(RECORDING_INPUT_NAME_KEY, deviceInfo.getProductName().toString()); + map.putString(RECORDING_INPUT_TYPE_KEY, typeStr); + map.putString(RECORDING_INPUT_UID_KEY, String.valueOf(deviceInfo.getId())); + return map; + } + + @Override + public void getCurrentInput(final Promise promise) { + AudioDeviceInfo deviceInfo = null; + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P){ + promise.reject("E_AUDIO_VERSIONINCOMPATIBLE", "Getting current audio input is not supported on devices running Android version lower than Android 9.0"); + return; + } else { + + try { + // getRoutedDevice() is the most reliable way to return the actual mic input, however it + // only returns a valid device when actively recording, and may throw otherwise. + // https://developer.android.com/reference/android/media/MediaRecorder#getRoutedDevice() + deviceInfo = mAudioRecorder.getRoutedDevice(); + } catch (Exception e) { + // Noop if this throws, try alternate method of determining current input below. + } + + // If no routed device is found try preferred device + deviceInfo = mAudioRecorder.getPreferredDevice(); + + if (deviceInfo == null) { + // If no preferred device is found, set it to the first built-in input we can find + AudioDeviceInfo[] audioDevices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); + for (int i = 0; i < audioDevices.length; i++) { + AudioDeviceInfo availableDeviceInfo = audioDevices[i]; + int type = availableDeviceInfo.getType(); + if (type == AudioDeviceInfo.TYPE_BUILTIN_MIC) { + deviceInfo = availableDeviceInfo; + mAudioRecorder.setPreferredDevice(deviceInfo); + break; + } + } + } + } + + if (deviceInfo != null) { + final Bundle map = getMapFromDeviceInfo(deviceInfo); + promise.resolve(map); + } else { + promise.reject("E_AUDIO_DEVICENOTFOUND", "Cannot get current input, AudioDeviceInfo not found."); + } + } + + @Override + public void getAvailableInputs(final Promise promise) { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M){ + promise.reject("E_AUDIO_VERSIONINCOMPATIBLE", "Getting available inputs is not supported on devices running Android version lower than Android 6.0"); + } else { + ArrayList devices = new ArrayList(); + AudioDeviceInfo[] audioDevices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); + for (AudioDeviceInfo deviceInfo : audioDevices) { + int type = deviceInfo.getType(); + if (type == AudioDeviceInfo.TYPE_BUILTIN_MIC || type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO || type == AudioDeviceInfo.TYPE_WIRED_HEADSET) { + final Bundle map = getMapFromDeviceInfo(deviceInfo); + devices.add(map); + } + } + promise.resolve(devices); + } + } + + @Override + public void setInput(final String uid, final Promise promise) { + AudioDeviceInfo deviceInfo = getDeviceInfoFromUid(uid); + boolean success = false; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { + if (deviceInfo != null && deviceInfo.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { + mAudioManager.startBluetoothSco(); + } else { + mAudioManager.stopBluetoothSco(); + } + + success = mAudioRecorder.setPreferredDevice(deviceInfo); + + } else { + promise.reject("E_AUDIO_VERSIONINCOMPATIBLE", "Setting input is not supported on devices running Android version lower than Android 9.0"); + } + if (success) { + promise.resolve(success); + } else { + promise.reject("E_AUDIO_SETINPUTFAIL", "Could not set preferred device input."); + } + } + + @Override + public void startAudioRecording(final Promise promise) { + if (isMissingAudioRecordingPermissions()) { + promise.reject("E_MISSING_PERMISSION", "Missing audio recording permissions."); + return; + } + + if (checkAudioRecorderExistsOrReject(promise)) { + try { + if (mAudioRecorderIsPaused && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + mAudioRecorder.resume(); + } else { + mAudioRecorder.start(); + } + } catch (final IllegalStateException e) { + promise.reject("E_AUDIO_RECORDING", "Start encountered an error: recording not started", e); + return; + } + + mAudioRecorderUptimeOfLastStartResume = SystemClock.uptimeMillis(); + mAudioRecorderIsRecording = true; + mAudioRecorderIsPaused = false; + + promise.resolve(getAudioRecorderStatus()); + } + } + + @Override + public void pauseAudioRecording(final Promise promise) { + if (checkAudioRecorderExistsOrReject(promise)) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + promise.reject("E_AUDIO_VERSIONINCOMPATIBLE", "Pausing an audio recording is unsupported on" + + " Android devices running SDK < 24."); + } else { + try { + mAudioRecorder.pause(); + } catch (final IllegalStateException e) { + promise.reject("E_AUDIO_RECORDINGPAUSE", "Pause encountered an error: recording not paused", e); + return; + } + + mAudioRecorderDurationAlreadyRecorded = getAudioRecorderDurationMillis(); + mAudioRecorderIsRecording = false; + mAudioRecorderIsPaused = true; + + promise.resolve(getAudioRecorderStatus()); + } + } + } + + @Override + public void stopAudioRecording(final Promise promise) { + if (checkAudioRecorderExistsOrReject(promise)) { + try { + mAudioRecorder.stop(); + } catch (final RuntimeException e) { + mAudioRecorderIsPaused = false; + if (!mAudioRecorderIsRecording) { + promise.reject("E_AUDIO_RECORDINGSTOP", "Stop encountered an error: recording not started", e); + } else { + mAudioRecorderIsRecording = false; + promise.reject("E_AUDIO_NODATA", "Stop encountered an error: no valid audio data has been received", e); + } + return; + } + + mAudioRecorderDurationAlreadyRecorded = getAudioRecorderDurationMillis(); + mAudioRecorderIsRecording = false; + mAudioRecorderIsPaused = false; + + promise.resolve(getAudioRecorderStatus()); + } + } + + @Override + public void getAudioRecordingStatus(final Promise promise) { + if (checkAudioRecorderExistsOrReject(promise)) { + promise.resolve(getAudioRecorderStatus()); + } + } + + @Override + public void unloadAudioRecorder(final Promise promise) { + if (checkAudioRecorderExistsOrReject(promise)) { + removeAudioRecorder(); + promise.resolve(null); + } + } + + private static File ensureDirExists(File dir) throws IOException { + if (!(dir.isDirectory() || dir.mkdirs())) { + throw new IOException("Couldn't create directory '" + dir + "'"); + } + return dir; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVManagerInterface.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVManagerInterface.java new file mode 100644 index 00000000000000..564501fbb79eec --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVManagerInterface.java @@ -0,0 +1,71 @@ +package abi49_0_0.expo.modules.av; + +import android.content.Context; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.Promise; +import abi49_0_0.expo.modules.core.arguments.ReadableArguments; +import abi49_0_0.expo.modules.av.video.VideoView; +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsResponseListener; + +public interface AVManagerInterface { + void registerVideoViewForAudioLifecycle(final VideoView videoView); + + void unregisterVideoViewForAudioLifecycle(final VideoView videoView); + + void abandonAudioFocusIfUnused(); + + Context getContext(); + + float getVolumeForDuckAndFocus(boolean isMuted, float volume); + + void acquireAudioFocus() throws AudioFocusNotAcquiredException; + + void setAudioIsEnabled(final Boolean value); + + void setAudioMode(final ReadableArguments map); + + void loadForSound(final ReadableArguments source, final ReadableArguments status, final Promise promise); + + void unloadForSound(final Integer key, final Promise promise); + + void setStatusForSound(final Integer key, final ReadableArguments status, final Promise promise); + + void replaySound(final Integer key, final ReadableArguments status, final Promise promise); + + void getStatusForSound(final Integer key, final Promise promise); + + void loadForVideo(final Integer tag, final ReadableArguments source, final ReadableArguments status, final Promise promise); + + void unloadForVideo(final Integer tag, final Promise promise); + + void setStatusForVideo(final Integer tag, final ReadableArguments status, final Promise promise); + + void replayVideo(final Integer tag, final ReadableArguments status, final Promise promise); + + void getStatusForVideo(final Integer tag, final Promise promise); + + void prepareAudioRecorder(final ReadableArguments options, final Promise promise); + + void startAudioRecording(final Promise promise); + + void pauseAudioRecording(final Promise promise); + + void stopAudioRecording(final Promise promise); + + void getAudioRecordingStatus(final Promise promise); + + void unloadAudioRecorder(final Promise promise); + + void getCurrentInput(final Promise promise); + + void setInput(final String uid, final Promise promise); + + void getAvailableInputs(final Promise promise); + + boolean hasAudioPermission(); + + void requestAudioPermission(PermissionsResponseListener permissionsResponseListener); + + ModuleRegistry getModuleRegistry(); +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVModule.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVModule.java new file mode 100644 index 00000000000000..d561cb6644ed2e --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVModule.java @@ -0,0 +1,149 @@ +package abi49_0_0.expo.modules.av; + +import android.Manifest; +import android.content.Context; + +import abi49_0_0.expo.modules.core.ExportedModule; +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.Promise; +import abi49_0_0.expo.modules.core.arguments.ReadableArguments; +import abi49_0_0.expo.modules.core.interfaces.ExpoMethod; + +import abi49_0_0.expo.modules.interfaces.permissions.Permissions; + +public class AVModule extends ExportedModule { + private AVManagerInterface mAVManager; + private ModuleRegistry mModuleRegistry; + + public AVModule(Context context) { + super(context); + } + + @Override + public String getName() { + return "ExponentAV"; + } + + @Override + public void onCreate(ModuleRegistry moduleRegistry) { + mModuleRegistry = moduleRegistry; + mAVManager = moduleRegistry.getModule(AVManagerInterface.class); + } + + @ExpoMethod + public void setAudioIsEnabled(final Boolean value, final Promise promise) { + mAVManager.setAudioIsEnabled(value); + promise.resolve(null); + } + + @ExpoMethod + public void setAudioMode(final ReadableArguments map, final Promise promise) { + mAVManager.setAudioMode(map); + promise.resolve(null); + } + + @ExpoMethod + public void loadForSound(final ReadableArguments source, final ReadableArguments status, final Promise promise) { + mAVManager.loadForSound(source, status, promise); + } + + @ExpoMethod + public void unloadForSound(final Integer key, final Promise promise) { + mAVManager.unloadForSound(key, promise); + } + + @ExpoMethod + public void setStatusForSound(final Integer key, final ReadableArguments status, final Promise promise) { + mAVManager.setStatusForSound(key, status, promise); + } + + @ExpoMethod + public void replaySound(final Integer key, final ReadableArguments status, final Promise promise) { + mAVManager.replaySound(key, status, promise); + } + + @ExpoMethod + public void getStatusForSound(final Integer key, final Promise promise) { + mAVManager.getStatusForSound(key, promise); + } + + @ExpoMethod + public void loadForVideo(final Integer tag, final ReadableArguments source, final ReadableArguments status, final Promise promise) { + mAVManager.loadForVideo(tag, source, status, promise); + } + + @ExpoMethod + public void unloadForVideo(final Integer tag, final Promise promise) { + mAVManager.unloadForVideo(tag, promise); + } + + @ExpoMethod + public void setStatusForVideo(final Integer tag, final ReadableArguments status, final Promise promise) { + mAVManager.setStatusForVideo(tag, status, promise); + } + + @ExpoMethod + public void replayVideo(final Integer tag, final ReadableArguments status, final Promise promise) { + mAVManager.replayVideo(tag, status, promise); + } + + @ExpoMethod + public void getStatusForVideo(final Integer tag, final Promise promise) { + mAVManager.getStatusForVideo(tag, promise); + } + + @ExpoMethod + public void prepareAudioRecorder(final ReadableArguments options, final Promise promise) { + mAVManager.prepareAudioRecorder(options, promise); + } + + @ExpoMethod + public void getAvailableInputs(final Promise promise) { + mAVManager.getAvailableInputs(promise); + } + + @ExpoMethod + public void getCurrentInput(final Promise promise) { + mAVManager.getCurrentInput(promise); + } + + @ExpoMethod + public void setInput(final String uid, final Promise promise) { + mAVManager.setInput(uid, promise); + } + + @ExpoMethod + public void startAudioRecording(final Promise promise) { + mAVManager.startAudioRecording(promise); + } + + @ExpoMethod + public void pauseAudioRecording(final Promise promise) { + mAVManager.pauseAudioRecording(promise); + } + + @ExpoMethod + public void stopAudioRecording(final Promise promise) { + mAVManager.stopAudioRecording(promise); + } + + @ExpoMethod + public void getAudioRecordingStatus(final Promise promise) { + mAVManager.getAudioRecordingStatus(promise); + } + + @ExpoMethod + public void unloadAudioRecorder(final Promise promise) { + mAVManager.unloadAudioRecorder(promise); + } + + @ExpoMethod + public void requestPermissionsAsync(final Promise promise) { + Permissions.askForPermissionsWithPermissionsManager(mModuleRegistry.getModule(Permissions.class), promise, Manifest.permission.RECORD_AUDIO); + } + + @ExpoMethod + public void getPermissionsAsync(final Promise promise) { + Permissions.getPermissionsWithPermissionsManager(mModuleRegistry.getModule(Permissions.class), promise, Manifest.permission.RECORD_AUDIO); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVPackage.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVPackage.java new file mode 100644 index 00000000000000..89393e683c1ef3 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AVPackage.java @@ -0,0 +1,36 @@ +package abi49_0_0.expo.modules.av; + +import android.content.Context; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import abi49_0_0.expo.modules.core.BasePackage; +import abi49_0_0.expo.modules.core.ExportedModule; +import abi49_0_0.expo.modules.core.ViewManager; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; +import abi49_0_0.expo.modules.av.player.datasource.SharedCookiesDataSourceFactoryProvider; + +public class AVPackage extends BasePackage { + + @Override + public List createInternalModules(Context context) { + return Arrays.asList( + new AVManager(context), + new SharedCookiesDataSourceFactoryProvider() + ); + } + + @Override + public List createExportedModules(Context context) { + return Arrays.asList( + new AVModule(context) + ); + } + + @Override + public List createViewManagers(Context context) { + return Collections.emptyList(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AudioEventHandler.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AudioEventHandler.java new file mode 100644 index 00000000000000..69a94c6d289674 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AudioEventHandler.java @@ -0,0 +1,18 @@ +package abi49_0_0.expo.modules.av; + +public interface AudioEventHandler { + + void pauseImmediately(); + + boolean requiresAudioFocus(); + + void updateVolumeMuteAndDuck(); + + void handleAudioFocusInterruptionBegan(); + + void handleAudioFocusGained(); + + void onPause(); + + void onResume(); +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AudioFocusNotAcquiredException.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AudioFocusNotAcquiredException.java new file mode 100644 index 00000000000000..a04ed05fecb31f --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/AudioFocusNotAcquiredException.java @@ -0,0 +1,7 @@ +package abi49_0_0.expo.modules.av; + +public class AudioFocusNotAcquiredException extends Exception { + public AudioFocusNotAcquiredException(final String message) { + super(message); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/ViewUtils.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/ViewUtils.kt new file mode 100644 index 00000000000000..1a678eeeafad3f --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/ViewUtils.kt @@ -0,0 +1,78 @@ +package abi49_0_0.expo.modules.av + +import androidx.annotation.AnyThread +import androidx.annotation.UiThread +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil +import abi49_0_0.com.facebook.react.uimanager.IllegalViewOperationException +import abi49_0_0.expo.modules.av.video.VideoView +import abi49_0_0.expo.modules.av.video.VideoViewWrapper +import abi49_0_0.expo.modules.core.ModuleRegistry +import abi49_0_0.expo.modules.core.Promise +import abi49_0_0.expo.modules.core.interfaces.services.UIManager + +object ViewUtils { + interface VideoViewCallback { + fun runWithVideoView(videoView: VideoView): Unit + } + + @UiThread + private fun tryRunWithVideoViewOnUiThread(moduleRegistry: ModuleRegistry, viewTag: Int, callback: VideoViewCallback, promise: Promise) { + try { + val videoWrapperView = moduleRegistry.getModule(UIManager::class.java).resolveView(viewTag) as VideoViewWrapper? + val videoView = videoWrapperView?.videoViewInstance + if (videoView != null) { + callback.runWithVideoView(videoView) + } else { + promise.reject("E_VIDEO_TAGINCORRECT", "Invalid view returned from registry.") + } + } catch (e: IllegalViewOperationException) { + promise.reject("E_VIDEO_TAGINCORRECT", "Invalid view returned from registry.") + } + } + + /** + * Rejects the promise if the VideoView is not found, otherwise executes the callback. + */ + @JvmStatic + @AnyThread + @Deprecated("Use `dispatchCommands` in favor of finding view with imperative calls") + fun tryRunWithVideoView(moduleRegistry: ModuleRegistry, viewTag: Int, callback: VideoViewCallback, promise: Promise) { + if (UiThreadUtil.isOnUiThread()) { + tryRunWithVideoViewOnUiThread(moduleRegistry, viewTag, callback, promise) + } else { + UiThreadUtil.runOnUiThread { + tryRunWithVideoViewOnUiThread(moduleRegistry, viewTag, callback, promise) + } + } + } + + @UiThread + private fun tryRunWithVideoViewOnUiThread(moduleRegistry: ModuleRegistry, viewTag: Int, callback: VideoViewCallback, promise: abi49_0_0.expo.modules.kotlin.Promise) { + try { + val videoWrapperView = moduleRegistry.getModule(UIManager::class.java).resolveView(viewTag) as VideoViewWrapper? + val videoView = videoWrapperView?.videoViewInstance + if (videoView != null) { + callback.runWithVideoView(videoView) + } else { + promise.reject("E_VIDEO_TAGINCORRECT", "Invalid view returned from registry.", null) + } + } catch (e: IllegalViewOperationException) { + promise.reject("E_VIDEO_TAGINCORRECT", "Invalid view returned from registry.", null) + } + } + + /** + * Rejects the promise if the VideoView is not found, otherwise executes the callback. + */ + @AnyThread + @Deprecated("Use `dispatchCommands` in favor of finding view with imperative calls") + fun tryRunWithVideoView(moduleRegistry: ModuleRegistry, viewTag: Int, callback: VideoViewCallback, promise: abi49_0_0.expo.modules.kotlin.Promise) { + if (UiThreadUtil.isOnUiThread()) { + tryRunWithVideoViewOnUiThread(moduleRegistry, viewTag, callback, promise) + } else { + UiThreadUtil.runOnUiThread { + tryRunWithVideoViewOnUiThread(moduleRegistry, viewTag, callback, promise) + } + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/MediaPlayerData.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/MediaPlayerData.java new file mode 100644 index 00000000000000..ba2b489ca409ae --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/MediaPlayerData.java @@ -0,0 +1,450 @@ +package abi49_0_0.expo.modules.av.player; + +import android.content.Context; +import android.media.MediaPlayer; +import android.media.PlaybackParams; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import androidx.annotation.RequiresApi; +import android.util.Log; +import android.util.Pair; +import android.view.Surface; + +import abi49_0_0.expo.modules.core.ModuleRegistry; + +import java.io.IOException; +import java.net.CookieHandler; +import java.net.HttpCookie; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import abi49_0_0.expo.modules.av.AVManagerInterface; +import abi49_0_0.expo.modules.av.AudioFocusNotAcquiredException; + + +class MediaPlayerData extends PlayerData implements + MediaPlayer.OnBufferingUpdateListener, + MediaPlayer.OnCompletionListener, + MediaPlayer.OnErrorListener, + MediaPlayer.OnInfoListener, + MediaPlayer.OnSeekCompleteListener, + MediaPlayer.OnVideoSizeChangedListener { + + static final String IMPLEMENTATION_NAME = "MediaPlayer"; + + private MediaPlayer mMediaPlayer = null; + private ModuleRegistry mModuleRegistry = null; + private boolean mMediaPlayerHasStartedEver = false; + + private Integer mPlayableDurationMillis = null; + private boolean mIsBuffering = false; + + MediaPlayerData(final AVManagerInterface avModule, final Context context, final Uri uri, final Map requestHeaders) { + super(avModule, uri, requestHeaders); + mModuleRegistry = avModule.getModuleRegistry(); + } + + @Override + String getImplementationName() { + return IMPLEMENTATION_NAME; + } + + // --------- PlayerData implementation --------- + + // Lifecycle + + @Override + public void load(final Bundle status, + final LoadCompletionListener loadCompletionListener) { + if (mMediaPlayer != null) { + loadCompletionListener.onLoadError("Load encountered an error: MediaPlayerData cannot be loaded twice."); + return; + } + + final MediaPlayer unpreparedPlayer = new MediaPlayer(); + + try { + Uri uri = mUri; + if (uri.getScheme() == null) { + int resourceId = mAVModule.getContext().getResources().getIdentifier(uri.toString(), "raw", mAVModule.getContext().getPackageName()); + uri = Uri.parse("android.resource://" + mAVModule.getContext().getPackageName() + "/" + resourceId); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + unpreparedPlayer.setDataSource(mAVModule.getContext(), uri, null, getHttpCookiesList()); + } else { + Map headers = new HashMap<>(1); + StringBuilder cookieBuilder = new StringBuilder(); + for (HttpCookie httpCookie : getHttpCookiesList()) { + cookieBuilder.append(httpCookie.getName()); + cookieBuilder.append("="); + cookieBuilder.append(httpCookie.getValue()); + cookieBuilder.append("; "); + } + cookieBuilder.append("\r\n"); + headers.put("Cookie", cookieBuilder.toString()); + if (mRequestHeaders != null) { + for (Map.Entry headerEntry : mRequestHeaders.entrySet()) { + if (headerEntry.getValue() instanceof String) { + headers.put(headerEntry.getKey(), (String) headerEntry.getValue()); + } + } + } + unpreparedPlayer.setDataSource(mAVModule.getContext(), uri, headers); + } + } catch (final Throwable throwable) { + loadCompletionListener.onLoadError("Load encountered an error: setDataSource() threw an exception was thrown with message: " + throwable.toString()); + return; + } + + unpreparedPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { + @Override + public boolean onError(final MediaPlayer mp, final int what, final int extra) { + loadCompletionListener.onLoadError("Load encountered an error: the OnErrorListener was called with 'what' code " + what + " and 'extra' code " + extra + "."); + return true; + } + }); + + unpreparedPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(final MediaPlayer mp) { + mMediaPlayer = mp; + mMediaPlayer.setOnBufferingUpdateListener(MediaPlayerData.this); + mMediaPlayer.setOnCompletionListener(MediaPlayerData.this); + mMediaPlayer.setOnErrorListener(MediaPlayerData.this); + mMediaPlayer.setOnInfoListener(MediaPlayerData.this); + + setStatusWithListener(status, new SetStatusCompletionListener() { + @Override + public void onSetStatusComplete() { + loadCompletionListener.onLoadSuccess(getStatus()); + } + + @Override + public void onSetStatusError(final String error) { + loadCompletionListener.onLoadSuccess(getStatus()); + } + }); + } + }); + + try { + unpreparedPlayer.prepareAsync(); + } catch (final Throwable throwable) { + loadCompletionListener.onLoadError("Load encountered an error: an exception was thrown from prepareAsync() with message: " + throwable.toString()); + } + } + + @Override + public synchronized void release() { + super.release(); + stopUpdatingProgressIfNecessary(); + if (mMediaPlayer != null) { + mMediaPlayer.setOnBufferingUpdateListener(null); + mMediaPlayer.setOnCompletionListener(null); + mMediaPlayer.setOnErrorListener(null); + mMediaPlayer.setOnInfoListener(null); + mMediaPlayer.stop(); + mMediaPlayer.release(); + mMediaPlayer = null; + } + } + + @Override + protected double getCurrentPositionSeconds() { + return (double)mMediaPlayer.getCurrentPosition() / 1000.0; + } + + @Override + boolean shouldContinueUpdatingProgress() { + return mMediaPlayer != null && !mIsBuffering; + } + + // Set status + + @RequiresApi(api = Build.VERSION_CODES.M) + private void playMediaPlayerWithRateMAndHigher(final float rate) { + final PlaybackParams params = mMediaPlayer.getPlaybackParams(); + params.setPitch(mShouldCorrectPitch ? 1.0f : rate); + params.setSpeed(rate); + params.setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_DEFAULT); + mMediaPlayer.setPlaybackParams(params); + mMediaPlayer.start(); + } + + @Override + void playPlayerWithRateAndMuteIfNecessary() throws AudioFocusNotAcquiredException { + if (mMediaPlayer == null || !shouldPlayerPlay()) { + return; + } + + if (!mIsMuted) { + mAVModule.acquireAudioFocus(); + } + + updateVolumeMuteAndDuck(); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + if (!mMediaPlayer.isPlaying()) { + mMediaPlayer.start(); + mMediaPlayerHasStartedEver = true; + } + } else { + boolean rateAndPitchAreSetCorrectly; + try { + final PlaybackParams params = mMediaPlayer.getPlaybackParams(); + final float setRate = params.getSpeed(); + final boolean setShouldCorrectPitch = params.getPitch() == 1.0f; + rateAndPitchAreSetCorrectly = setRate == mRate && setShouldCorrectPitch == mShouldCorrectPitch; + } catch (final Throwable throwable) { + rateAndPitchAreSetCorrectly = false; + } + if (mRate != 0 && (!mMediaPlayer.isPlaying() || !rateAndPitchAreSetCorrectly)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + playMediaPlayerWithRateMAndHigher(mRate); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // Bizarrely, I wasn't able to change rate while a sound was playing unless I had + // changed the rate to something other than 1f before the sound started. + // This workaround seems to fix this issue (which is said to only be fixed in N): + // https://code.google.com/p/android/issues/detail?id=192135 + playMediaPlayerWithRateMAndHigher(2f); + mMediaPlayer.pause(); + playMediaPlayerWithRateMAndHigher(mRate); + } + mMediaPlayerHasStartedEver = true; + } + } + beginUpdatingProgressIfNecessary(); + } + + @Override + void applyNewStatus(final Integer newPositionMillis, final Boolean newIsLooping) + throws AudioFocusNotAcquiredException, IllegalStateException { + if (mMediaPlayer == null) { + throw new IllegalStateException("mMediaPlayer is null!"); + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && mRate != 1.0f) { + Log.w("Expo MediaPlayerData", "Cannot set audio/video playback rate for Android SDK < 23."); + mRate = 1.0f; + } + + // Set looping idempotently + if (newIsLooping != null) { + mMediaPlayer.setLooping(newIsLooping); + } + + // Pause first if necessary. + if (!shouldPlayerPlay()) { + if (mMediaPlayerHasStartedEver) { + mMediaPlayer.pause(); + } + stopUpdatingProgressIfNecessary(); + } + + // Mute / update volume if it doesn't require a request of the audio focus. + updateVolumeMuteAndDuck(); + + // Seek + if (newPositionMillis != null && newPositionMillis != mMediaPlayer.getCurrentPosition()) { + mMediaPlayer.seekTo(newPositionMillis); + } + + // Play / unmute + playPlayerWithRateAndMuteIfNecessary(); + } + + // Get status + + @Override + boolean isLoaded() { + return mMediaPlayer != null; + } + + @Override + void getExtraStatusFields(final Bundle map) { + Integer duration = mMediaPlayer.getDuration(); + duration = duration < 0 ? null : duration; + if (duration != null) { + map.putInt(STATUS_DURATION_MILLIS_KEY_PATH, duration); + } + map.putInt(STATUS_POSITION_MILLIS_KEY_PATH, getClippedIntegerForValue(mMediaPlayer.getCurrentPosition(), 0, duration)); + if (mPlayableDurationMillis != null) { + map.putInt(STATUS_PLAYABLE_DURATION_MILLIS_KEY_PATH, getClippedIntegerForValue(mPlayableDurationMillis, 0, duration)); + } + + map.putBoolean(STATUS_IS_PLAYING_KEY_PATH, mMediaPlayer.isPlaying()); + map.putBoolean(STATUS_IS_BUFFERING_KEY_PATH, mIsBuffering); + + map.putBoolean(STATUS_IS_LOOPING_KEY_PATH, mMediaPlayer.isLooping()); + } + + // Video specific stuff + + @Override + public Pair getVideoWidthHeight() { + return mMediaPlayer == null ? new Pair<>(0, 0) : new Pair<>(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight()); + } + + @Override + public void tryUpdateVideoSurface(final Surface surface) { + if (mMediaPlayer == null) { + return; + } + mMediaPlayer.setSurface(surface); + if (!mMediaPlayerHasStartedEver && !mShouldPlay) { + // For some reason, the media player does not render to the screen until start() has been + // called in some cases. + mMediaPlayer.start(); + mMediaPlayer.pause(); + mMediaPlayerHasStartedEver = true; + } + } + + @Override + public int getAudioSessionId() { + return mMediaPlayer != null ? mMediaPlayer.getAudioSessionId() : 0; + } + + // --------- Interface implementation --------- + + // AudioEventHandler + + @Override + public void pauseImmediately() { + if (mMediaPlayer != null && mMediaPlayerHasStartedEver) { + mMediaPlayer.pause(); + } + stopUpdatingProgressIfNecessary(); + } + + @Override + public boolean requiresAudioFocus() { + return mMediaPlayer != null && (mMediaPlayer.isPlaying() || shouldPlayerPlay()) && !mIsMuted; + } + + @Override + public void updateVolumeMuteAndDuck() { + if (mMediaPlayer != null) { + final float value = mAVModule.getVolumeForDuckAndFocus(mIsMuted, mVolume); + float leftValue = value; + float rightValue = value; + if (mPan > 0) { + leftValue *= (1.0f - mPan); + } else if (mPan < 0) { + rightValue *= (1.0f + mPan); + } + mMediaPlayer.setVolume(leftValue, rightValue); + } + } + + // MediaPlayer.*Listener + + @Override + public void onBufferingUpdate(final MediaPlayer mp, final int percent) { + if (mp.getDuration() >= 0) { + mPlayableDurationMillis = (int) (mp.getDuration() * (((double) percent) / 100.0)); + } else { + mPlayableDurationMillis = null; + } + callStatusUpdateListener(); + } + + @Override + public void onCompletion(final MediaPlayer mp) { + callStatusUpdateListenerWithDidJustFinish(); + + if (!mp.isLooping()) { + mAVModule.abandonAudioFocusIfUnused(); + stopUpdatingProgressIfNecessary(); + } + } + + @Override + public boolean onError(final MediaPlayer mp, final int what, final int extra) { + release(); + if (mErrorListener != null) { + mErrorListener.onError("MediaPlayer failed with 'what' code " + what + " and 'extra' code " + extra + "."); + } + return true; + } + + @Override + public boolean onInfo(final MediaPlayer mp, final int what, final int extra) { + // Writing out all of the possible values here for clarity + // @jesseruder @nikki93 I think we should hold off on handling some of the more obscure values + // until the ExoPlayer refactor. + switch (what) { + case MediaPlayer.MEDIA_INFO_UNKNOWN: + break; + case MediaPlayer.MEDIA_INFO_BUFFERING_START: + mIsBuffering = true; + break; + case MediaPlayer.MEDIA_INFO_BUFFERING_END: + mIsBuffering = false; + beginUpdatingProgressIfNecessary(); + break; + case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: + break; + case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE: + break; + case MediaPlayer.MEDIA_INFO_METADATA_UPDATE: + break; + case MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE: + break; + case MediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT: + break; + case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: + if (mVideoSizeUpdateListener != null) { + mVideoSizeUpdateListener.onVideoSizeUpdate(new Pair<>(mp.getVideoWidth(), mp.getVideoHeight())); + } + break; + case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: + break; + } + callStatusUpdateListener(); + return true; + } + + @Override + public void onSeekComplete(final MediaPlayer mp) { + callStatusUpdateListener(); + } + + @Override + public void onVideoSizeChanged(final MediaPlayer mp, final int width, final int height) { + if (mVideoSizeUpdateListener != null) { + mVideoSizeUpdateListener.onVideoSizeUpdate(new Pair<>(width, height)); + } + } + + // Utilities + + private List getHttpCookiesList() { + if (mModuleRegistry != null) { + CookieHandler cookieHandler = mModuleRegistry.getModule(CookieHandler.class); + if (cookieHandler != null) { + try { + Map> headersMap = cookieHandler.get(URI.create(mUri.toString()), null); + List cookies = headersMap.get("Cookie"); + if (cookies != null) { + List httpCookies = new ArrayList<>(); + for (String cookieValue : cookies) { + httpCookies.addAll(HttpCookie.parse(cookieValue)); + } + return httpCookies; + } else { + return Collections.emptyList(); + } + } catch (IOException e) { + // do nothing, we'll return an empty list + } + } + } + return Collections.emptyList(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/PlayerData.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/PlayerData.java new file mode 100644 index 00000000000000..eb1b155c3ed2d0 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/PlayerData.java @@ -0,0 +1,521 @@ +package abi49_0_0.expo.modules.av.player; + +import android.Manifest; +import android.content.Context; +import android.media.audiofx.Visualizer; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.util.Pair; +import android.view.Surface; + +import androidx.annotation.UiThread; + +import com.facebook.jni.HybridData; +import abi49_0_0.com.facebook.react.bridge.UiThreadUtil; + +import abi49_0_0.expo.modules.core.Promise; +import abi49_0_0.expo.modules.core.arguments.ReadableArguments; + +import java.lang.ref.WeakReference; +import java.util.Map; + +import abi49_0_0.expo.modules.av.AVManagerInterface; +import abi49_0_0.expo.modules.av.AudioEventHandler; +import abi49_0_0.expo.modules.av.AudioFocusNotAcquiredException; +import abi49_0_0.expo.modules.av.progress.AndroidLooperTimeMachine; +import abi49_0_0.expo.modules.av.progress.ProgressLooper; +import abi49_0_0.expo.modules.core.interfaces.DoNotStrip; +import abi49_0_0.expo.modules.core.interfaces.services.UIManager; +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsResponse; +import abi49_0_0.expo.modules.interfaces.permissions.PermissionsStatus; + +public abstract class PlayerData implements AudioEventHandler { + static final String STATUS_ANDROID_IMPLEMENTATION_KEY_PATH = "androidImplementation"; + static final String STATUS_HEADERS_KEY_PATH = "headers"; + static final String STATUS_IS_LOADED_KEY_PATH = "isLoaded"; + public static final String STATUS_URI_KEY_PATH = "uri"; + static final String STATUS_OVERRIDING_EXTENSION_KEY_PATH = "overridingExtension"; + static final String STATUS_PROGRESS_UPDATE_INTERVAL_MILLIS_KEY_PATH = "progressUpdateIntervalMillis"; + static final String STATUS_DURATION_MILLIS_KEY_PATH = "durationMillis"; + static final String STATUS_POSITION_MILLIS_KEY_PATH = "positionMillis"; + static final String STATUS_PLAYABLE_DURATION_MILLIS_KEY_PATH = "playableDurationMillis"; + static final String STATUS_SHOULD_PLAY_KEY_PATH = "shouldPlay"; + public static final String STATUS_IS_PLAYING_KEY_PATH = "isPlaying"; + static final String STATUS_IS_BUFFERING_KEY_PATH = "isBuffering"; + static final String STATUS_RATE_KEY_PATH = "rate"; + static final String STATUS_SHOULD_CORRECT_PITCH_KEY_PATH = "shouldCorrectPitch"; + static final String STATUS_VOLUME_KEY_PATH = "volume"; + static final String STATUS_VOLUME_PAN_KEY_PATH = "audioPan"; + static final String STATUS_IS_MUTED_KEY_PATH = "isMuted"; + static final String STATUS_IS_LOOPING_KEY_PATH = "isLooping"; + static final String STATUS_DID_JUST_FINISH_KEY_PATH = "didJustFinish"; + + @DoNotStrip + private final HybridData mHybridData; + + public static Bundle getUnloadedStatus() { + final Bundle map = new Bundle(); + map.putBoolean(STATUS_IS_LOADED_KEY_PATH, false); + return map; + } + + public interface VideoSizeUpdateListener { + void onVideoSizeUpdate(final Pair videoWidthHeight); + } + + public interface ErrorListener { + void onError(final String error); + } + + public interface LoadCompletionListener { + void onLoadSuccess(final Bundle status); + + void onLoadError(final String error); + } + + public interface StatusUpdateListener { + void onStatusUpdate(final Bundle status); + } + + interface SetStatusCompletionListener { + void onSetStatusComplete(); + + void onSetStatusError(final String error); + } + + public interface FullscreenPresenter { + boolean isBeingPresentedFullscreen(); + + void setFullscreenMode(boolean isFullscreen); + } + + final AVManagerInterface mAVModule; + final Uri mUri; + final Map mRequestHeaders; + private final WeakReference mUiManager; + + private ProgressLooper mProgressUpdater = new ProgressLooper(new AndroidLooperTimeMachine()); + + private Visualizer mVisualizer = null; + + private FullscreenPresenter mFullscreenPresenter = null; + private StatusUpdateListener mStatusUpdateListener = null; + ErrorListener mErrorListener = null; + VideoSizeUpdateListener mVideoSizeUpdateListener = null; + + private int mProgressUpdateIntervalMillis = 500; + boolean mShouldPlay = false; + float mRate = 1.0f; + boolean mShouldCorrectPitch = false; + float mVolume = 1.0f; + float mPan = 0.0f; + boolean mIsMuted = false; + + PlayerData(final AVManagerInterface avModule, final Uri uri, final Map requestHeaders) { + mRequestHeaders = requestHeaders; + mAVModule = avModule; + mUri = uri; + mUiManager = new WeakReference<>(avModule.getModuleRegistry().getModule(UIManager.class)); + + mHybridData = initHybrid(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + if (mVisualizer != null) { + mVisualizer.release(); + mVisualizer = null; + } + mHybridData.resetNative(); + } + + @SuppressWarnings("JavaJniMissingFunction") + private native HybridData initHybrid(); + @SuppressWarnings({"JavaJniMissingFunction"}) + protected native void sampleBufferCallback(byte[] sampleBuffer, double positionSeconds); + + protected double getCurrentPositionSeconds() { + return 0; + } + +// @SuppressWarnings("unused") + @DoNotStrip + void setEnableSampleBufferCallback(boolean enable) { + if (!UiThreadUtil.isOnUiThread()) { + UiThreadUtil.runOnUiThread(() -> { + setEnableSampleBufferCallback(enable); + }); + return; + } + + if (enable) { + try { + boolean hasRecordAudioPermission = mAVModule.hasAudioPermission(); + if (!hasRecordAudioPermission) { + mAVModule.requestAudioPermission(result -> { + PermissionsResponse response = result.get(Manifest.permission.RECORD_AUDIO); + if (response == null) { + return; + } + if (response.getStatus() == PermissionsStatus.GRANTED) { + // call func again, this time we have audio permission + setEnableSampleBufferCallback(true); + } else if (!response.getCanAskAgain()) { + Log.e("PlayerData", "Cannot initialize Sample Data Callback (Visualizer) when RECORD_AUDIO permission is not granted!"); + } + }); + return; + } + int id = getAudioSessionId(); + Log.i("PlayerData", "Initializing Visualizer for Audio Session #" + id + "..."); + mVisualizer = new Visualizer(id); + mVisualizer.setEnabled(false); + mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]); + + // the rate at which the Visualizer calls back with new bytes - will be clamped to max 100ms (1000 mHz) + int callbackRate = Math.min(Visualizer.getMaxCaptureRate(), 10000); + mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { + @Override + public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) { + if (mShouldPlay) { + emitSampleBufferEvent(bytes, getCurrentPositionSeconds()); + } + } + + @Override + public void onFftDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) { } + }, callbackRate, true, false); + + mVisualizer.setEnabled(true); + + Log.i("PlayerData", "Visualizer initialized with a capture rate of " + callbackRate); + } catch (Throwable e) { + Log.e("PlayerData", "Failed to initialize Visualizer! " + e.getLocalizedMessage()); + e.printStackTrace(); + } + } else { + if (mVisualizer != null) { + mVisualizer.setEnabled(false); + mVisualizer.release(); + } + mVisualizer = null; + } + } + + public static PlayerData createUnloadedPlayerData(final AVManagerInterface avModule, final Context context, final ReadableArguments source, final Bundle status) { + final String uriString = source.getString(STATUS_URI_KEY_PATH); + Map requestHeaders = null; + if (source.containsKey(STATUS_HEADERS_KEY_PATH)) { + requestHeaders = source.getMap(STATUS_HEADERS_KEY_PATH); + } + final String uriOverridingExtension = source.containsKey(STATUS_OVERRIDING_EXTENSION_KEY_PATH) ? source.getString(STATUS_OVERRIDING_EXTENSION_KEY_PATH) : null; + // uriString is guaranteed not to be null (both VideoView.setSource and Sound.loadAsync handle that case) + final Uri uri = Uri.parse(uriString); + + if (status.containsKey(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH) + && status.getString(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH).equals(MediaPlayerData.IMPLEMENTATION_NAME)) { + return new MediaPlayerData(avModule, context, uri, requestHeaders); + } else { + return new SimpleExoPlayerData(avModule, context, uri, uriOverridingExtension, requestHeaders); + } + } + + @UiThread + private void emitSampleBufferEvent(final byte[] bytes, final double currentPositionSeconds) { + final UIManager uiManager = mUiManager.get(); + if (uiManager != null) { + uiManager.runOnClientCodeQueueThread(() -> { + sampleBufferCallback(bytes, currentPositionSeconds); + }); + } + } + + abstract String getImplementationName(); + + // Lifecycle + + public abstract void load(final Bundle status, final LoadCompletionListener loadCompletionListener); + + public void release() { + if (mVisualizer != null) { + mVisualizer.setDataCaptureListener(null, 0, false, false); + mVisualizer.setEnabled(false); + mVisualizer.release(); + mVisualizer = null; + } + } + + // Status update listener + + private void callStatusUpdateListenerWithStatus(final Bundle status) { + if (mStatusUpdateListener != null) { + mStatusUpdateListener.onStatusUpdate(status); + } + } + + final void callStatusUpdateListenerWithDidJustFinish() { + final Bundle status = getStatus(); + status.putBoolean(STATUS_DID_JUST_FINISH_KEY_PATH, true); + callStatusUpdateListenerWithStatus(status); + } + + final void callStatusUpdateListener() { + callStatusUpdateListenerWithStatus(getStatus()); + } + + abstract boolean shouldContinueUpdatingProgress(); + + final void stopUpdatingProgressIfNecessary() { + mProgressUpdater.stopLooping(); + } + + final void beginUpdatingProgressIfNecessary() { + if (shouldContinueUpdatingProgress() && !mProgressUpdater.isLooping() && (mStatusUpdateListener != null)) { + mProgressUpdater.loop(mProgressUpdateIntervalMillis, () -> { + this.callStatusUpdateListener(); + return null; + }); + } + } + + public final void setStatusUpdateListener(final StatusUpdateListener listener) { + final StatusUpdateListener oldListener = mStatusUpdateListener; + mStatusUpdateListener = listener; + if (mStatusUpdateListener != null) { + beginUpdatingProgressIfNecessary(); + + // Notify app about the current status upon setting the status listener + if (oldListener == null) { + callStatusUpdateListener(); + } + } else { + stopUpdatingProgressIfNecessary(); + } + } + + // Error listener + + public final void setErrorListener(final ErrorListener listener) { + mErrorListener = listener; + } + + // Status + + final boolean shouldPlayerPlay() { + return mShouldPlay && mRate > 0.0; + } + + abstract void playPlayerWithRateAndMuteIfNecessary() throws AudioFocusNotAcquiredException; + + abstract void applyNewStatus(final Integer newPositionMillis, final Boolean newIsLooping) + throws AudioFocusNotAcquiredException, IllegalStateException; + + final void setStatusWithListener(final Bundle status, final SetStatusCompletionListener setStatusCompletionListener) { + if (status.containsKey(STATUS_PROGRESS_UPDATE_INTERVAL_MILLIS_KEY_PATH)) { + if (mProgressUpdateIntervalMillis != (int) status.getDouble(STATUS_PROGRESS_UPDATE_INTERVAL_MILLIS_KEY_PATH)) { + mProgressUpdateIntervalMillis = (int) status.getDouble(STATUS_PROGRESS_UPDATE_INTERVAL_MILLIS_KEY_PATH); + + // Restart looper when update interval is changed + if (mProgressUpdater.isLooping()) { + stopUpdatingProgressIfNecessary(); + beginUpdatingProgressIfNecessary(); + } + } + } + + final Integer newPositionMillis; + if (status.containsKey(STATUS_POSITION_MILLIS_KEY_PATH)) { + // Even though we set the position with an int, this is a double in the map because iOS can + // take a floating point value for positionMillis. + newPositionMillis = (int) status.getDouble(STATUS_POSITION_MILLIS_KEY_PATH); + } else { + newPositionMillis = null; + } + + if (status.containsKey(STATUS_SHOULD_PLAY_KEY_PATH)) { + mShouldPlay = status.getBoolean(STATUS_SHOULD_PLAY_KEY_PATH); + } + + if (status.containsKey(STATUS_RATE_KEY_PATH)) { + mRate = (float) status.getDouble(STATUS_RATE_KEY_PATH); + } + + if (status.containsKey(STATUS_SHOULD_CORRECT_PITCH_KEY_PATH)) { + mShouldCorrectPitch = status.getBoolean(STATUS_SHOULD_CORRECT_PITCH_KEY_PATH); + } + + if (status.containsKey(STATUS_VOLUME_KEY_PATH)) { + mVolume = (float) status.getDouble(STATUS_VOLUME_KEY_PATH); + } + + if (status.containsKey(STATUS_VOLUME_PAN_KEY_PATH)) { + mPan = (float) status.getDouble(STATUS_VOLUME_PAN_KEY_PATH); + } + + if (status.containsKey(STATUS_IS_MUTED_KEY_PATH)) { + mIsMuted = status.getBoolean(STATUS_IS_MUTED_KEY_PATH); + } + + final Boolean newIsLooping; + if (status.containsKey(STATUS_IS_LOOPING_KEY_PATH)) { + newIsLooping = status.getBoolean(STATUS_IS_LOOPING_KEY_PATH); + } else { + newIsLooping = null; + } + + try { + applyNewStatus(newPositionMillis, newIsLooping); + } catch (final Throwable throwable) { + mAVModule.abandonAudioFocusIfUnused(); + setStatusCompletionListener.onSetStatusError(throwable.toString()); + return; + } + + mAVModule.abandonAudioFocusIfUnused(); + setStatusCompletionListener.onSetStatusComplete(); + } + + public final void setStatus(final Bundle status, final Promise promise) { + if (status == null) { + if (promise != null) { + promise.reject("E_AV_SETSTATUS", "Cannot set null status."); + } + return; + } + + try { + setStatusWithListener(status, new SetStatusCompletionListener() { + @Override + public void onSetStatusComplete() { + if (promise == null) { + callStatusUpdateListener(); + } else { + promise.resolve(getStatus()); + } + } + + @Override + public void onSetStatusError(final String error) { + if (promise == null) { + callStatusUpdateListener(); + } else { + promise.reject("E_AV_SETSTATUS", error); + } + } + }); + } catch (final Throwable throwable) { + if (promise != null) { + promise.reject("E_AV_SETSTATUS", "Encountered an error while setting status!", throwable); + } + } + } + + final int getClippedIntegerForValue(final Integer value, final Integer min, final Integer max) { + return (min != null && value < min) ? min : (max != null && value > max) ? max : value; + } + + abstract boolean isLoaded(); + + abstract void getExtraStatusFields(final Bundle map); + + // Sometimes another thread would release the player + // in the middle of `getStatus()` call, which would result + // in a null reference method invocation in `getExtraStatusFields`, + // so we need to ensure nothing will release or nullify the property + // while we get the latest status. + public synchronized final Bundle getStatus() { + if (!isLoaded()) { + final Bundle map = getUnloadedStatus(); + map.putString(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH, getImplementationName()); + return map; + } + + final Bundle map = new Bundle(); + + map.putBoolean(STATUS_IS_LOADED_KEY_PATH, true); + map.putString(STATUS_ANDROID_IMPLEMENTATION_KEY_PATH, getImplementationName()); + + map.putString(STATUS_URI_KEY_PATH, mUri.getPath()); + + map.putInt(STATUS_PROGRESS_UPDATE_INTERVAL_MILLIS_KEY_PATH, mProgressUpdateIntervalMillis); + // STATUS_DURATION_MILLIS_KEY_PATH, STATUS_POSITION_MILLIS_KEY_PATH, + // and STATUS_PLAYABLE_DURATION_MILLIS_KEY_PATH are set in addExtraStatusFields(). + + map.putBoolean(STATUS_SHOULD_PLAY_KEY_PATH, mShouldPlay); + // STATUS_IS_PLAYING_KEY_PATH and STATUS_IS_BUFFERING_KEY_PATH are set + // in addExtraStatusFields(). + + map.putDouble(STATUS_RATE_KEY_PATH, (double) mRate); + map.putBoolean(STATUS_SHOULD_CORRECT_PITCH_KEY_PATH, mShouldCorrectPitch); + map.putDouble(STATUS_VOLUME_KEY_PATH, (double) mVolume); + map.putDouble(STATUS_VOLUME_PAN_KEY_PATH, (double) mPan); + map.putBoolean(STATUS_IS_MUTED_KEY_PATH, mIsMuted); + // STATUS_IS_LOOPING_KEY_PATH is set in addExtraStatusFields(). + + map.putBoolean(STATUS_DID_JUST_FINISH_KEY_PATH, false); + + getExtraStatusFields(map); + + return map; + } + + // Video specific stuff + + public final void setVideoSizeUpdateListener(final VideoSizeUpdateListener videoSizeUpdateListener) { + mVideoSizeUpdateListener = videoSizeUpdateListener; + } + + public final void setFullscreenPresenter(final FullscreenPresenter fullscreenPresenter) { + mFullscreenPresenter = fullscreenPresenter; + } + + public abstract Pair getVideoWidthHeight(); + + public abstract void tryUpdateVideoSurface(final Surface surface); + + abstract int getAudioSessionId(); + + public boolean isPresentedFullscreen() { + return mFullscreenPresenter.isBeingPresentedFullscreen(); + } + + public void toggleFullscreen() { + mFullscreenPresenter.setFullscreenMode(!isPresentedFullscreen()); + } + + // AudioEventHandler + + @Override + public final void handleAudioFocusInterruptionBegan() { + if (!mIsMuted) { + pauseImmediately(); + } + } + + @Override + public final void handleAudioFocusGained() { + try { + playPlayerWithRateAndMuteIfNecessary(); + } catch (final AudioFocusNotAcquiredException e) { + // This is ok -- we might be paused or audio might have been disabled. + } + } + + @Override + public final void onPause() { + pauseImmediately(); + } + + @Override + public final void onResume() { + try { + playPlayerWithRateAndMuteIfNecessary(); + } catch (final AudioFocusNotAcquiredException e) { + // Do nothing -- another app has audio focus for now, and handleAudioFocusGained() will be + // called when it abandons it. + } + } + +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/PlayerDataControl.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/PlayerDataControl.java new file mode 100644 index 00000000000000..e438f0b9c34e6c --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/PlayerDataControl.java @@ -0,0 +1,98 @@ +package abi49_0_0.expo.modules.av.player; + +import android.os.Bundle; +import androidx.annotation.NonNull; +import android.widget.MediaController; + +public class PlayerDataControl implements MediaController.MediaPlayerControl { + private final PlayerData mPlayerData; + + public PlayerDataControl(final @NonNull PlayerData playerData) { + mPlayerData = playerData; + } + + @Override + public void start() { + final Bundle map = new Bundle(); + map.putBoolean(PlayerData.STATUS_SHOULD_PLAY_KEY_PATH, true); + mPlayerData.setStatus(map, null); + } + + @Override + public void pause() { + final Bundle map = new Bundle(); + map.putBoolean(PlayerData.STATUS_SHOULD_PLAY_KEY_PATH, false); + mPlayerData.setStatus(map, null); + } + + @Override + public int getDuration() { + final Bundle status = mPlayerData.getStatus(); + return (status.getBoolean(PlayerData.STATUS_IS_LOADED_KEY_PATH) + && status.containsKey(PlayerData.STATUS_DURATION_MILLIS_KEY_PATH)) + ? status.getInt(PlayerData.STATUS_DURATION_MILLIS_KEY_PATH) : 0; + } + + @Override + public int getCurrentPosition() { + final Bundle status = mPlayerData.getStatus(); + return status.getBoolean(PlayerData.STATUS_IS_LOADED_KEY_PATH) + ? status.getInt(PlayerData.STATUS_POSITION_MILLIS_KEY_PATH) : 0; + } + + @Override + public void seekTo(final int msec) { + final Bundle map = new Bundle(); + map.putDouble(PlayerData.STATUS_POSITION_MILLIS_KEY_PATH, (double) msec); + mPlayerData.setStatus(map, null); + } + + @Override + public boolean isPlaying() { + final Bundle status = mPlayerData.getStatus(); + return status.getBoolean(PlayerData.STATUS_IS_LOADED_KEY_PATH) + && status.getBoolean(PlayerData.STATUS_IS_PLAYING_KEY_PATH); + } + + @Override + public int getBufferPercentage() { + final Bundle status = mPlayerData.getStatus(); + if (status.getBoolean(PlayerData.STATUS_IS_LOADED_KEY_PATH) + && status.containsKey(PlayerData.STATUS_DURATION_MILLIS_KEY_PATH) + && status.containsKey(PlayerData.STATUS_PLAYABLE_DURATION_MILLIS_KEY_PATH)) { + final double duration = status.getInt(PlayerData.STATUS_DURATION_MILLIS_KEY_PATH); + final double playableDuration = status.getInt(PlayerData.STATUS_PLAYABLE_DURATION_MILLIS_KEY_PATH); + return (int) (playableDuration / duration * 100.0); + } else { + return 0; + } + } + + @Override + public boolean canPause() { + return true; + } + + @Override + public boolean canSeekBackward() { + return true; + } + + @Override + public boolean canSeekForward() { + return true; + } + + @Override + public int getAudioSessionId() { + return mPlayerData.getAudioSessionId(); + } + + public boolean isFullscreen() { + return mPlayerData.isPresentedFullscreen(); + } + + public void toggleFullscreen() { + mPlayerData.toggleFullscreen(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/SimpleExoPlayerData.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/SimpleExoPlayerData.java new file mode 100644 index 00000000000000..76b6ba48a95f93 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/SimpleExoPlayerData.java @@ -0,0 +1,432 @@ +package abi49_0_0.expo.modules.av.player; + +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; + +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; +import android.view.Surface; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.PlaybackException; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.source.LoadEventInfo; +import com.google.android.exoplayer2.source.MediaLoadData; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.ProgressiveMediaSource; +import com.google.android.exoplayer2.source.dash.DashMediaSource; +import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; +import com.google.android.exoplayer2.source.hls.HlsMediaSource; +import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource; +import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; +import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; +import com.google.android.exoplayer2.upstream.RawResourceDataSource; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.VideoSize; + +import java.io.IOException; +import java.util.Map; + +import abi49_0_0.expo.modules.av.AVManagerInterface; +import abi49_0_0.expo.modules.av.AudioFocusNotAcquiredException; +import abi49_0_0.expo.modules.av.player.datasource.DataSourceFactoryProvider; + +class SimpleExoPlayerData extends PlayerData + implements Player.Listener, MediaSourceEventListener { + + private static final String IMPLEMENTATION_NAME = "SimpleExoPlayer"; + private static final String TAG = SimpleExoPlayerData.class.getSimpleName(); + + private SimpleExoPlayer mSimpleExoPlayer = null; + private final String mOverridingExtension; + private LoadCompletionListener mLoadCompletionListener = null; + private boolean mFirstFrameRendered = false; + private Pair mVideoWidthHeight = null; + private Integer mLastPlaybackState = null; + private boolean mIsLooping = false; + private boolean mIsLoading = true; + private final Context mReactContext; + + SimpleExoPlayerData(final AVManagerInterface avModule, final Context context, final Uri uri, final String overridingExtension, final Map requestHeaders) { + super(avModule, uri, requestHeaders); + mReactContext = context; + mOverridingExtension = overridingExtension; + } + + @Override + String getImplementationName() { + return IMPLEMENTATION_NAME; + } + + // --------- PlayerData implementation --------- + + // Lifecycle + + @Override + public void load(final Bundle status, final LoadCompletionListener loadCompletionListener) { + mLoadCompletionListener = loadCompletionListener; + + final Context context = mAVModule.getContext(); + final BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build(); + final TrackSelector trackSelector = new DefaultTrackSelector(context, new AdaptiveTrackSelection.Factory()); + + // Create the player + mSimpleExoPlayer = new SimpleExoPlayer.Builder(context) + .setTrackSelector(trackSelector) + .setBandwidthMeter(bandwidthMeter) + .build(); + + mSimpleExoPlayer.addListener(this); + + // Produces DataSource instances through which media data is loaded. + final DataSource.Factory dataSourceFactory = mAVModule.getModuleRegistry() + .getModule(DataSourceFactoryProvider.class) + .createFactory( + mReactContext, + mAVModule.getModuleRegistry(), + Util.getUserAgent(context, "yourApplicationName"), + mRequestHeaders, + bandwidthMeter.getTransferListener()); + try { + // This is the MediaSource representing the media to be played. + final MediaSource source = buildMediaSource(mUri, mOverridingExtension, dataSourceFactory); + + // Prepare the player with the source. + mSimpleExoPlayer.prepare(source); + setStatus(status, null); + } catch (IllegalStateException e) { + onFatalError(e); + } + } + + @Override + public synchronized void release() { + super.release(); + stopUpdatingProgressIfNecessary(); + if (mSimpleExoPlayer != null) { + mSimpleExoPlayer.release(); + mSimpleExoPlayer = null; + } + } + + @Override + protected double getCurrentPositionSeconds() { + // TODO: Find a way to fix "IllegalStateException: SimpleExoPlayer is accessed on the wrong thread." + // this is called synchronously on JS thread while SimpleExoPlayer is accessed on main thread. + return -1.0; + // return (double)mSimpleExoPlayer.getCurrentPosition() / 1000.0; + } + + @Override + boolean shouldContinueUpdatingProgress() { + return mSimpleExoPlayer != null && mSimpleExoPlayer.getPlayWhenReady(); + } + + // Set status + + @Override + void playPlayerWithRateAndMuteIfNecessary() throws AudioFocusNotAcquiredException { + if (mSimpleExoPlayer == null || !shouldPlayerPlay()) { + return; + } + + if (!mIsMuted) { + mAVModule.acquireAudioFocus(); + } + + updateVolumeMuteAndDuck(); + + mSimpleExoPlayer.setPlaybackParameters(new PlaybackParameters(mRate, mShouldCorrectPitch ? 1.0f : mRate)); + + mSimpleExoPlayer.setPlayWhenReady(mShouldPlay); + } + + @Override + void applyNewStatus(final Integer newPositionMillis, final Boolean newIsLooping) + throws AudioFocusNotAcquiredException, IllegalStateException { + if (mSimpleExoPlayer == null) { + throw new IllegalStateException("mSimpleExoPlayer is null!"); + } + + // Set looping idempotently + if (newIsLooping != null) { + mIsLooping = newIsLooping; + if (mIsLooping) { + mSimpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_ALL); + } else { + mSimpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_OFF); + } + } + + // Pause first if necessary. + if (!shouldPlayerPlay()) { + mSimpleExoPlayer.setPlayWhenReady(false); + stopUpdatingProgressIfNecessary(); + } + + // Mute / update volume if it doesn't require a request of the audio focus. + updateVolumeMuteAndDuck(); + + // Seek + if (newPositionMillis != null) { + // TODO handle different timeline cases for streaming + mSimpleExoPlayer.seekTo(newPositionMillis); + } + + // Play / unmute + playPlayerWithRateAndMuteIfNecessary(); + } + + // Get status + + @Override + boolean isLoaded() { + return mSimpleExoPlayer != null; + } + + @Override + void getExtraStatusFields(final Bundle map) { + // TODO handle different timeline cases for streaming + final int duration = (int) mSimpleExoPlayer.getDuration(); + map.putInt(STATUS_DURATION_MILLIS_KEY_PATH, duration); + map.putInt(STATUS_POSITION_MILLIS_KEY_PATH, + getClippedIntegerForValue((int) mSimpleExoPlayer.getCurrentPosition(), 0, duration)); + map.putInt(STATUS_PLAYABLE_DURATION_MILLIS_KEY_PATH, + getClippedIntegerForValue((int) mSimpleExoPlayer.getBufferedPosition(), 0, duration)); + + map.putBoolean(STATUS_IS_PLAYING_KEY_PATH, + mSimpleExoPlayer.getPlayWhenReady() && mSimpleExoPlayer.getPlaybackState() == Player.STATE_READY); + map.putBoolean(STATUS_IS_BUFFERING_KEY_PATH, + mIsLoading || mSimpleExoPlayer.getPlaybackState() == Player.STATE_BUFFERING); + + map.putBoolean(STATUS_IS_LOOPING_KEY_PATH, mIsLooping); + } + + // Video specific stuff + + @Override + public Pair getVideoWidthHeight() { + return mVideoWidthHeight != null ? mVideoWidthHeight : new Pair<>(0, 0); + } + + @Override + public void tryUpdateVideoSurface(final Surface surface) { + if (mSimpleExoPlayer != null) { + mSimpleExoPlayer.setVideoSurface(surface); + } + } + + @Override + public int getAudioSessionId() { + return mSimpleExoPlayer != null ? mSimpleExoPlayer.getAudioSessionId() : 0; + } + + // --------- Interface implementation --------- + + // region AudioEventHandler + + @Override + public void pauseImmediately() { + if (mSimpleExoPlayer != null) { + mSimpleExoPlayer.setPlayWhenReady(false); + } + stopUpdatingProgressIfNecessary(); + } + + @Override + public boolean requiresAudioFocus() { + return mSimpleExoPlayer != null && (mSimpleExoPlayer.getPlayWhenReady() || shouldPlayerPlay()) && !mIsMuted; + } + + @Override + public void updateVolumeMuteAndDuck() { + if (mSimpleExoPlayer != null) { + mSimpleExoPlayer.setVolume(mAVModule.getVolumeForDuckAndFocus(mIsMuted, mVolume)); + } + } + + // endregion + + // region Player.Listener + + @Override + public void onLoadingChanged(final boolean isLoading) { + mIsLoading = isLoading; + callStatusUpdateListener(); + } + + @Override + public void onPlaybackParametersChanged(PlaybackParameters parameters) { + } + + @Override + public void onRepeatModeChanged(int repeatMode) { + } + + @Override + public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) { + + } + + @Override + public void onPlayerStateChanged(final boolean playWhenReady, final int playbackState) { + if (playbackState == Player.STATE_READY && mLoadCompletionListener != null) { + final LoadCompletionListener listener = mLoadCompletionListener; + mLoadCompletionListener = null; + listener.onLoadSuccess(getStatus()); + } + + if (mLastPlaybackState != null + && playbackState != mLastPlaybackState + && playbackState == Player.STATE_ENDED) { + callStatusUpdateListenerWithDidJustFinish(); + stopUpdatingProgressIfNecessary(); + } else { + callStatusUpdateListener(); + if (playWhenReady && (playbackState == Player.STATE_READY)) { + beginUpdatingProgressIfNecessary(); + } + } + mLastPlaybackState = playbackState; + } + + @Override + public void onPlayerError(PlaybackException error) { + onFatalError(error.getCause()); + } + + @Override + public void onPositionDiscontinuity(int reason) { + // According to the documentation: + // > A period defines a single logical piece of media, for example a media file. + // > It may also define groups of ads inserted into the media, + // > along with information about whether those ads have been loaded and played. + // Source: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/Timeline.Period.html + // So I guess it's safe to say that when a period transition happens, + // media file transition happens, so we just finished playing one. + if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) { + callStatusUpdateListenerWithDidJustFinish(); + } + } + + @Override + public void onVideoSizeChanged(VideoSize videoSize) { + mVideoWidthHeight = new Pair<>(videoSize.width, videoSize.height); + if (mFirstFrameRendered && mVideoSizeUpdateListener != null) { + mVideoSizeUpdateListener.onVideoSizeUpdate(mVideoWidthHeight); + } + } + + @Override + public void onRenderedFirstFrame() { + if (!mFirstFrameRendered && mVideoWidthHeight != null && mVideoSizeUpdateListener != null) { + mVideoSizeUpdateListener.onVideoSizeUpdate(mVideoWidthHeight); + } + mFirstFrameRendered = true; + } + + // endregion + + // region MediaSourceEventListener + + @Override + public void onLoadError( + int windowIndex, + @Nullable MediaSource.MediaPeriodId mediaPeriodId, + LoadEventInfo loadEventInfo, + MediaLoadData mediaLoadData, + IOException error, + boolean wasCanceled + ) { + if (mLoadCompletionListener != null) { + final LoadCompletionListener listener = mLoadCompletionListener; + mLoadCompletionListener = null; + listener.onLoadError(error.toString()); + } + } + + private void onFatalError(final Throwable error) { + if (mLoadCompletionListener != null) { + final LoadCompletionListener listener = mLoadCompletionListener; + mLoadCompletionListener = null; + listener.onLoadError(error.toString()); + } else if (mErrorListener != null) { + mErrorListener.onError("Player error: " + error.getMessage()); + } + release(); + } + + // endregion + + private MediaSource buildMediaSource(@NonNull Uri uri, String overrideExtension, DataSource.Factory factory) { + try { + if (uri.getScheme() == null) { + int resourceId = mReactContext.getResources().getIdentifier(uri.toString(), "raw", mReactContext.getPackageName()); + DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(resourceId)); + final RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(mReactContext); + rawResourceDataSource.open(dataSpec); + uri = rawResourceDataSource.getUri(); + } + } catch (Exception e) { + Log.e(TAG, "Error reading raw resource from ExoPlayer", e); + } + @C.ContentType int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(String.valueOf(uri)) : Util.inferContentType("." + overrideExtension); + switch (type) { + case C.TYPE_SS: + return new SsMediaSource.Factory(new DefaultSsChunkSource.Factory(factory), factory).createMediaSource(MediaItem.fromUri(uri)); + case C.TYPE_DASH: + return new DashMediaSource.Factory(new DefaultDashChunkSource.Factory(factory), factory).createMediaSource(MediaItem.fromUri(uri)); + case C.TYPE_HLS: + return new HlsMediaSource.Factory(factory).createMediaSource(MediaItem.fromUri(uri)); + case C.TYPE_OTHER: + return new ProgressiveMediaSource.Factory(factory).createMediaSource(MediaItem.fromUri(uri)); + default: { + throw new IllegalStateException("Content of this type is unsupported at the moment. Unsupported type: " + type); + } + } + } + + // region MediaSourceEventListener + + @Override + public void onLoadStarted(int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { + + } + + @Override + public void onLoadCompleted(int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { + + } + + @Override + public void onLoadCanceled(int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) { + + } + + @Override + public void onUpstreamDiscarded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) { + + } + + @Override + public void onDownstreamFormatChanged(int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) { + + } + + // endregion +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/CustomHeadersOkHttpDataSourceFactory.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/CustomHeadersOkHttpDataSourceFactory.kt new file mode 100644 index 00000000000000..51b8141146ea96 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/CustomHeadersOkHttpDataSourceFactory.kt @@ -0,0 +1,38 @@ +package abi49_0_0.expo.modules.av.player.datasource + +import androidx.collection.ArrayMap +import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory +import com.google.android.exoplayer2.upstream.HttpDataSource.RequestProperties +import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource +import okhttp3.CacheControl +import okhttp3.Call + +// Mainly a copy of com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory, +// because it's declared as final :( +class CustomHeadersOkHttpDataSourceFactory( + private val callFactory: Call.Factory, + private val userAgent: String?, + requestHeaders: Map? +) : BaseFactory() { + private val cacheControl: CacheControl? = null + + private fun updateRequestProperties(requestHeaders: Map?) { + if (requestHeaders != null) { + val requestProperties = ArrayMap() + for ((key, value) in requestHeaders) { + if (value is String) { + requestProperties[key] = value + } + } + setDefaultRequestProperties(requestProperties) + } + } + + override fun createDataSourceInternal(defaultRequestProperties: RequestProperties): OkHttpDataSource { + return OkHttpDataSource(callFactory, userAgent, cacheControl, defaultRequestProperties) + } + + init { + updateRequestProperties(requestHeaders) + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/DataSourceFactoryProvider.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/DataSourceFactoryProvider.java new file mode 100644 index 00000000000000..57e09ce0531bf6 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/DataSourceFactoryProvider.java @@ -0,0 +1,14 @@ +package abi49_0_0.expo.modules.av.player.datasource; + +import android.content.Context; + +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.TransferListener; + +import java.util.Map; + +import abi49_0_0.expo.modules.core.ModuleRegistry; + +public interface DataSourceFactoryProvider { + DataSource.Factory createFactory(Context reactApplicationContext, ModuleRegistry moduleRegistry, String userAgent, Map requestHeaders, TransferListener transferListener); +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/SharedCookiesDataSourceFactory.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/SharedCookiesDataSourceFactory.java new file mode 100644 index 00000000000000..80c4a1130b32fb --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/SharedCookiesDataSourceFactory.java @@ -0,0 +1,33 @@ +package abi49_0_0.expo.modules.av.player.datasource; + +import android.content.Context; + +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; +import com.google.android.exoplayer2.upstream.TransferListener; + +import java.net.CookieHandler; +import java.util.Map; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; + +public class SharedCookiesDataSourceFactory implements DataSource.Factory { + private final DataSource.Factory mDataSourceFactory; + + public SharedCookiesDataSourceFactory(Context reactApplicationContext, ModuleRegistry moduleRegistry, String userAgent, Map requestHeaders, TransferListener transferListener) { + CookieHandler cookieHandler = moduleRegistry.getModule(CookieHandler.class); + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + if (cookieHandler != null) { + builder.cookieJar(new JavaNetCookieJar(cookieHandler)); + } + OkHttpClient client = builder.build(); + mDataSourceFactory = new DefaultDataSourceFactory(reactApplicationContext, transferListener, new CustomHeadersOkHttpDataSourceFactory(client, userAgent, requestHeaders)); + } + + @Override + public DataSource createDataSource() { + return mDataSourceFactory.createDataSource(); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/SharedCookiesDataSourceFactoryProvider.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/SharedCookiesDataSourceFactoryProvider.java new file mode 100644 index 00000000000000..e03d602e16e8f7 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/player/datasource/SharedCookiesDataSourceFactoryProvider.java @@ -0,0 +1,25 @@ +package abi49_0_0.expo.modules.av.player.datasource; + +import android.content.Context; + +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.TransferListener; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.interfaces.InternalModule; + +public class SharedCookiesDataSourceFactoryProvider implements InternalModule, DataSourceFactoryProvider { + @Override + public List getExportedInterfaces() { + return Collections.singletonList((Class) DataSourceFactoryProvider.class); + } + + @Override + public DataSource.Factory createFactory(Context reactApplicationContext, ModuleRegistry moduleRegistry, String userAgent, Map requestHeaders, TransferListener transferListener) { + return new SharedCookiesDataSourceFactory(reactApplicationContext, moduleRegistry, userAgent, requestHeaders, transferListener); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/progress/AndroidLooperTimeMachine.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/progress/AndroidLooperTimeMachine.kt new file mode 100644 index 00000000000000..e41a5afa465e3e --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/progress/AndroidLooperTimeMachine.kt @@ -0,0 +1,13 @@ +package abi49_0_0.expo.modules.av.progress + +import android.os.Handler + +class AndroidLooperTimeMachine : TimeMachine { + + override fun scheduleAt(intervalMillis: Long, callback: TimeMachineTick) { + Handler().postDelayed(callback, intervalMillis) + } + + override val time: Long + get() = System.currentTimeMillis() +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/progress/ProgressLooper.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/progress/ProgressLooper.kt new file mode 100644 index 00000000000000..d05945020e1735 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/progress/ProgressLooper.kt @@ -0,0 +1,70 @@ +package abi49_0_0.expo.modules.av.progress + +typealias TimeMachineTick = () -> Unit + +interface TimeMachine { + fun scheduleAt(intervalMillis: Long, callback: TimeMachineTick) + val time: Long +} + +typealias PlayerProgressListener = () -> Unit + +class ProgressLooper(private val timeMachine: TimeMachine) { + + private var interval = 0L + private var nextExpectedTick = -1L + private var waiting = false + + private var shouldLoop: Boolean + get() = interval > 0 && nextExpectedTick >= 0 && !waiting + set(value) { + if (!value) { + interval = 0L + nextExpectedTick = -1L + waiting = false + } + } + + private var listener: PlayerProgressListener? = null + + fun setListener(listener: PlayerProgressListener) { + this.listener = listener + } + + fun loop(interval: Long, listener: PlayerProgressListener) { + this.listener = listener + this.interval = interval + scheduleNextTick() + } + + fun stopLooping() { + this.shouldLoop = false + this.listener = null + } + + fun isLooping(): Boolean { + return this.interval > 0 + } + + private fun scheduleNextTick() { + if (nextExpectedTick == -1L) { + nextExpectedTick = timeMachine.time + } + if (shouldLoop) { + nextExpectedTick += calculateNextInterval() + waiting = true + timeMachine.scheduleAt(nextExpectedTick - timeMachine.time) { + waiting = false + listener?.invoke() + scheduleNextTick() + } + } + } + + private fun calculateNextInterval() = + if (nextExpectedTick > timeMachine.time) { + interval + } else { + (((timeMachine.time - nextExpectedTick) / interval) + 1) * interval + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenPlayerUpdate.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenPlayerUpdate.kt new file mode 100644 index 00000000000000..e26240bd2d186e --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenPlayerUpdate.kt @@ -0,0 +1,8 @@ +package abi49_0_0.expo.modules.av.video + +internal enum class FullscreenPlayerUpdate(val jsValue: Int) { + FULLSCREEN_PLAYER_WILL_PRESENT(0), + FULLSCREEN_PLAYER_DID_PRESENT(1), + FULLSCREEN_PLAYER_WILL_DISMISS(2), + FULLSCREEN_PLAYER_DID_DISMISS(3); +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayer.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayer.java new file mode 100644 index 00000000000000..cc68d7dd08d6e0 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayer.java @@ -0,0 +1,157 @@ +package abi49_0_0.expo.modules.av.video; + +import android.app.Dialog; +import android.content.Context; +import android.os.Handler; +import androidx.annotation.NonNull; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import java.lang.ref.WeakReference; + +import abi49_0_0.expo.modules.core.ModuleRegistry; +import abi49_0_0.expo.modules.core.interfaces.services.KeepAwakeManager; +import abi49_0_0.expo.modules.av.player.PlayerData; +import abi49_0_0.expo.modules.kotlin.AppContext; + +public class FullscreenVideoPlayer extends Dialog { + private static class KeepScreenOnUpdater implements Runnable { + private final static long UPDATE_KEEP_SCREEN_ON_FLAG_MS = 200; + private final WeakReference mFullscreenPlayer; + + KeepScreenOnUpdater(FullscreenVideoPlayer player) { + mFullscreenPlayer = new WeakReference<>(player); + } + + @Override + public void run() { + FullscreenVideoPlayer fullscreenVideoPlayer = mFullscreenPlayer.get(); + if (fullscreenVideoPlayer != null) { + final Window window = fullscreenVideoPlayer.getWindow(); + if (window != null) { + boolean isPlaying = + fullscreenVideoPlayer.mVideoView.getStatus().containsKey(PlayerData.STATUS_IS_PLAYING_KEY_PATH) + && fullscreenVideoPlayer.mVideoView.getStatus().getBoolean(PlayerData.STATUS_IS_PLAYING_KEY_PATH); + AppContext appContext = fullscreenVideoPlayer.mAppContext.get(); + ModuleRegistry moduleRegistry = appContext != null ? appContext.getLegacyModuleRegistry() : null; + if (moduleRegistry != null) { + KeepAwakeManager keepAwakeManager = moduleRegistry.getModule(KeepAwakeManager.class); + boolean keepAwakeIsActivated = keepAwakeManager != null && keepAwakeManager.isActivated(); + if (isPlaying || keepAwakeIsActivated) { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + } + } + fullscreenVideoPlayer.mKeepScreenOnHandler.postDelayed(this, UPDATE_KEEP_SCREEN_ON_FLAG_MS); + } + } + } + + private Handler mKeepScreenOnHandler; + private Runnable mKeepScreenOnUpdater; + + private FrameLayout mParent; + private WeakReference mAppContext; + private final VideoView mVideoView; + private final FrameLayout mContainerView; + private WeakReference mUpdateListener; + + FullscreenVideoPlayer(@NonNull Context context, VideoView videoView, AppContext appContext) { + super(context, android.R.style.Theme_Black_NoTitleBar_Fullscreen); + mAppContext = new WeakReference<>(appContext); + + setCancelable(false); + + mVideoView = videoView; + + mContainerView = new FrameLayout(context); + setContentView(mContainerView, generateDefaultLayoutParams()); + + mKeepScreenOnUpdater = new KeepScreenOnUpdater(this); + mKeepScreenOnHandler = new Handler(); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + + if (isShowing()) { + dismiss(); + } + } + + @Override + public void show() { + final FullscreenVideoPlayerPresentationChangeListener updateListener = mUpdateListener.get(); + if (updateListener != null) { + updateListener.onFullscreenPlayerWillPresent(); + } + + super.show(); + } + + @Override + public void dismiss() { + mVideoView.setOverridingUseNativeControls(null); + final FullscreenVideoPlayerPresentationChangeListener updateListener = mUpdateListener.get(); + if (updateListener != null) { + updateListener.onFullscreenPlayerWillDismiss(); + } + + super.dismiss(); + } + + @Override + protected void onStart() { + mParent = (FrameLayout) mVideoView.getParent(); + mParent.removeView(mVideoView); + + mContainerView.addView(mVideoView, generateDefaultLayoutParams()); + + super.onStart(); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + final FullscreenVideoPlayerPresentationChangeListener updateListener = mUpdateListener.get(); + if (updateListener != null) { + updateListener.onFullscreenPlayerDidPresent(); + } + + mVideoView.setOverridingUseNativeControls(true); + + mKeepScreenOnHandler.post(mKeepScreenOnUpdater); + } + + void setUpdateListener(FullscreenVideoPlayerPresentationChangeListener listener) { + mUpdateListener = new WeakReference<>(listener); + } + + @Override + protected void onStop() { + mKeepScreenOnHandler.removeCallbacks(mKeepScreenOnUpdater); + mContainerView.removeView(mVideoView); + mParent.addView(mVideoView, generateDefaultLayoutParams()); + + mParent.requestLayout(); + mParent = null; + + super.onStop(); + + final FullscreenVideoPlayerPresentationChangeListener updateListener = mUpdateListener.get(); + if (updateListener != null) { + updateListener.onFullscreenPlayerDidDismiss(); + } + } + + private FrameLayout.LayoutParams generateDefaultLayoutParams() { + return new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ); + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayerPresentationChangeListener.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayerPresentationChangeListener.java new file mode 100644 index 00000000000000..1b5acb8b5e23f7 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayerPresentationChangeListener.java @@ -0,0 +1,8 @@ +package abi49_0_0.expo.modules.av.video; + +public interface FullscreenVideoPlayerPresentationChangeListener { + void onFullscreenPlayerWillPresent(); + void onFullscreenPlayerDidPresent(); + void onFullscreenPlayerWillDismiss(); + void onFullscreenPlayerDidDismiss(); +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayerPresentationChangeProgressListener.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayerPresentationChangeProgressListener.java new file mode 100644 index 00000000000000..ff60850e2734f1 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/FullscreenVideoPlayerPresentationChangeProgressListener.java @@ -0,0 +1,23 @@ +package abi49_0_0.expo.modules.av.video; + +import androidx.annotation.Nullable; + +public abstract class FullscreenVideoPlayerPresentationChangeProgressListener implements FullscreenVideoPlayerPresentationChangeListener { + @Override + public void onFullscreenPlayerWillDismiss() {} + + @Override + public void onFullscreenPlayerDidPresent() {} + + @Override + public void onFullscreenPlayerDidDismiss() {} + + @Override + public void onFullscreenPlayerWillPresent() {} + + void onFullscreenPlayerPresentationTriedToInterrupt() {} + + void onFullscreenPlayerPresentationInterrupted() {} + + void onFullscreenPlayerPresentationError(@Nullable String errorMessage) {} +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/MediaController.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/MediaController.java new file mode 100644 index 00000000000000..3192f194a949d4 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/MediaController.java @@ -0,0 +1,635 @@ +package abi49_0_0.expo.modules.av.video; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ProgressBar; +import android.widget.SeekBar; +import android.widget.TextView; + +import java.lang.ref.WeakReference; +import java.util.Formatter; +import java.util.Locale; + +import abi49_0_0.host.exp.expoview.R; +import abi49_0_0.expo.modules.av.player.PlayerDataControl; + +// Based on https://www.brightec.co.uk/ideas/custom-android-media-controller +// We implement our own MediaController, +// because android.MediaController manages its own floating window +// which not only causes problems when VideoView is in a ScrollView +// (when VideoView is not visible on the screen and the controller +// is triggered, controls float at the edge of the screen), +// but also it's not possible to use MediaController when the player +// is in a FullscreenVideoPlayer (the controls float in a window below). + +public class MediaController extends FrameLayout { + private PlayerDataControl mPlayer; + private Context mContext; + private ViewGroup mAnchor; + private View mRoot; + private ProgressBar mProgress; + private TextView mEndTime, mCurrentTime; + private boolean mShowing; + private boolean mDragging; + private static final int sDefaultTimeout = 3000; + private static final int FADE_OUT = 1; + private static final int SHOW_PROGRESS = 2; + private boolean mUseFastForward; + private boolean mFromXml; + private boolean mListenersSet; + private View.OnClickListener mNextListener, mPrevListener; + private StringBuilder mFormatBuilder; + private Formatter mFormatter; + private ImageButton mPauseButton; + private ImageButton mFastForwardButton; + private ImageButton mRewindButton; + private ImageButton mNextButton; + private ImageButton mPrevButton; + private ImageButton mFullscreenButton; + private Handler mHandler = new MessageHandler(this); + + public MediaController(Context context, AttributeSet attrs) { + super(context, attrs); + mRoot = null; + mContext = context; + mUseFastForward = true; + mFromXml = true; + } + + public MediaController(Context context, boolean useFastForward) { + super(context); + mContext = context; + mUseFastForward = useFastForward; + } + + public MediaController(Context context) { + this(context, true); + } + + @Override + public void onFinishInflate() { + if (mRoot != null) + initControllerView(mRoot); + + super.onFinishInflate(); + } + + public void setMediaPlayer(PlayerDataControl player) { + mPlayer = player; + updateControls(); + } + + public void updateControls() { + setProgress(); + updatePausePlay(); + updateFullScreen(); + } + + /** + * Set the view that acts as the anchor for the control view. + * This can for example be a VideoView, or your Activity's main view. + * + * @param view The view to which to anchor the controller when it is visible. + */ + public void setAnchorView(ViewGroup view) { + mAnchor = view; + + if (mRoot == null) { + FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + Gravity.BOTTOM + ); + + removeAllViews(); + View controllerView = makeControllerView(); + addView(controllerView, frameParams); + } + } + + /** + * Create the view that holds the widgets that control playback. + * Derived classes can override this to create their own. + * + * @return The controller view. + */ + protected View makeControllerView() { + LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mRoot = inflate.inflate(R.layout.expo_media_controller, null); + + initControllerView(mRoot); + + return mRoot; + } + + private void initControllerView(View v) { + mPauseButton = v.findViewById(R.id.play_button); + if (mPauseButton != null) { + mPauseButton.requestFocus(); + mPauseButton.setOnClickListener(mPauseListener); + } + + mFullscreenButton = v.findViewById(R.id.fullscreen_mode_button); + if (mFullscreenButton != null) { + mFullscreenButton.requestFocus(); + mFullscreenButton.setOnClickListener(mFullscreenListener); + } + + mFastForwardButton = v.findViewById(R.id.fast_forward_button); + if (mFastForwardButton != null) { + mFastForwardButton.setOnClickListener(mFfwdListener); + if (!mFromXml) { + mFastForwardButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE); + } + } + + mRewindButton = v.findViewById(R.id.rewind_button); + if (mRewindButton != null) { + mRewindButton.setOnClickListener(mRewListener); + if (!mFromXml) { + mRewindButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE); + } + } + + // By default these are hidden. They will be enabled when setPrevNextListeners() is called + mNextButton = v.findViewById(R.id.skip_next_button); + if (mNextButton != null && !mFromXml && !mListenersSet) { + mNextButton.setVisibility(View.GONE); + } + mPrevButton = v.findViewById(R.id.skip_previous_button); + if (mPrevButton != null && !mFromXml && !mListenersSet) { + mPrevButton.setVisibility(View.GONE); + } + + mProgress = v.findViewById(R.id.seek_bar); + if (mProgress != null) { + if (mProgress instanceof SeekBar) { + SeekBar seeker = (SeekBar) mProgress; + seeker.setOnSeekBarChangeListener(mSeekListener); + } + mProgress.setMax(1000); + } + + mEndTime = v.findViewById(R.id.end_time_text); + mCurrentTime = v.findViewById(R.id.current_time_text); + mFormatBuilder = new StringBuilder(); + mFormatter = new Formatter(mFormatBuilder, Locale.getDefault()); + + installPrevNextListeners(); + } + + /** + * Show the controller on screen. It will go away + * automatically after 3 seconds of inactivity. + */ + public void show() { + show(sDefaultTimeout); + } + + /** + * Disable pause or seek buttons if the stream cannot be paused or seeked. + * This requires the control interface to be a MediaPlayerControlExt + */ + private void disableUnsupportedButtons() { + if (mPlayer == null) { + return; + } + + try { + if (mPauseButton != null && !mPlayer.canPause()) { + mPauseButton.setEnabled(false); + } + if (mRewindButton != null && !mPlayer.canSeekBackward()) { + mRewindButton.setEnabled(false); + } + if (mFastForwardButton != null && !mPlayer.canSeekForward()) { + mFastForwardButton.setEnabled(false); + } + } catch (IncompatibleClassChangeError ex) { + // We were given an old version of the interface, that doesn't have + // the canPause/canSeekXYZ methods. This is OK, it just means we + // assume the media can be paused and seeked, and so we don't disable + // the buttons. + } + } + + /** + * Show the controller on screen. It will go away + * automatically after 'timeout' milliseconds of inactivity. + * + * @param timeout The timeout in milliseconds. Use 0 to show + * the controller until hide() is called. + */ + public void show(int timeout) { + if (!mShowing && mAnchor != null) { + setProgress(); + if (mPauseButton != null) { + mPauseButton.requestFocus(); + } + disableUnsupportedButtons(); + + FrameLayout.LayoutParams tlp = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ); + + mAnchor.addView(this, tlp); + mShowing = true; + } + updateControls(); + + // Causes the progress bar to be updated even if mShowing + // was already true. This happens, for example, if we're + // paused with the progress bar showing and the user hits play. + mHandler.sendEmptyMessage(SHOW_PROGRESS); + + Message msg = mHandler.obtainMessage(FADE_OUT); + if (timeout != 0) { + mHandler.removeMessages(FADE_OUT); + mHandler.sendMessageDelayed(msg, timeout); + } + } + + public boolean isShowing() { + return mShowing; + } + + /** + * Remove the controller from the screen. + */ + public void hide() { + if (mAnchor == null) { + return; + } + + try { + mAnchor.removeView(this); + mHandler.removeMessages(SHOW_PROGRESS); + } catch (IllegalArgumentException ex) { + Log.w("MediaController", "already removed"); + } + mShowing = false; + } + + private String stringForTime(int timeMs) { + int totalSeconds = timeMs / 1000; + + int seconds = totalSeconds % 60; + int minutes = (totalSeconds / 60) % 60; + int hours = totalSeconds / 3600; + + mFormatBuilder.setLength(0); + if (hours > 0) { + return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString(); + } else { + return mFormatter.format("%02d:%02d", minutes, seconds).toString(); + } + } + + private int setProgress() { + if (mPlayer == null || mDragging) { + return 0; + } + + int position = mPlayer.getCurrentPosition(); + int duration = mPlayer.getDuration(); + if (mProgress != null) { + if (duration > 0) { + // use long to avoid overflow + long pos = 1000L * position / duration; + mProgress.setProgress((int) pos); + } + int percent = mPlayer.getBufferPercentage(); + mProgress.setSecondaryProgress(percent * 10); + } + + if (mEndTime != null) + mEndTime.setText(stringForTime(duration)); + if (mCurrentTime != null) + mCurrentTime.setText(stringForTime(position)); + + return position; + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (isEnabled()) { + show(sDefaultTimeout); + } + return true; + } + + @Override + public boolean onTrackballEvent(MotionEvent ev) { + if (isEnabled()) { + show(sDefaultTimeout); + } + return false; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (mPlayer == null || !isEnabled()) { + return true; + } + + int keyCode = event.getKeyCode(); + final boolean uniqueDown = event.getRepeatCount() == 0 + && event.getAction() == KeyEvent.ACTION_DOWN; + if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK + || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE + || keyCode == KeyEvent.KEYCODE_SPACE) { + if (uniqueDown) { + doPauseResume(); + show(sDefaultTimeout); + if (mPauseButton != null) { + mPauseButton.requestFocus(); + } + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { + if (uniqueDown && !mPlayer.isPlaying()) { + mPlayer.start(); + updatePausePlay(); + show(sDefaultTimeout); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP + || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { + if (uniqueDown && mPlayer.isPlaying()) { + mPlayer.pause(); + updatePausePlay(); + show(sDefaultTimeout); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN + || keyCode == KeyEvent.KEYCODE_VOLUME_UP + || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { + // don't show the controls for volume adjustment + return super.dispatchKeyEvent(event); + } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { + if (uniqueDown) { + hide(); + } + return true; + } + + show(sDefaultTimeout); + return super.dispatchKeyEvent(event); + } + + private View.OnClickListener mPauseListener = new View.OnClickListener() { + public void onClick(View v) { + show(sDefaultTimeout); + doPauseResume(); + } + }; + + private View.OnClickListener mFullscreenListener = new View.OnClickListener() { + public void onClick(View v) { + show(sDefaultTimeout); + doToggleFullscreen(); + } + }; + + public void updatePausePlay() { + if (mRoot == null || mPauseButton == null || mPlayer == null) { + return; + } + + if (mPlayer.isPlaying()) { + mPauseButton.setImageResource(R.drawable.exo_controls_pause); + } else { + mPauseButton.setImageResource(R.drawable.exo_controls_play); + } + } + + public void updateFullScreen() { + if (mRoot == null || mFullscreenButton == null || mPlayer == null) { + return; + } + + if (mPlayer.isFullscreen()) { + mFullscreenButton.setImageResource(R.drawable.ic_fullscreen_exit_32dp); + } else { + mFullscreenButton.setImageResource(R.drawable.ic_fullscreen_32dp); + } + } + + private void doPauseResume() { + if (mPlayer == null) { + return; + } + + if (mPlayer.isPlaying()) { + mPlayer.pause(); + } else { + mPlayer.start(); + } + updatePausePlay(); + } + + private void doToggleFullscreen() { + if (mPlayer == null) { + return; + } + + mPlayer.toggleFullscreen(); + } + + // There are two scenarios that can trigger the SeekBar listener to trigger: + // + // The first is the user using the touchpad to adjust the position of the + // SeekBar's thumb. In this case onStartTrackingTouch is called followed by + // a number of onProgressChanged notifications, concluded by onStopTrackingTouch. + // We're setting the field "mDragging" to true for the duration of the dragging + // session to avoid jumps in the position in case of ongoing playback. + // + // The second scenario involves the user operating the scroll ball, in this + // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications, + // we will simply apply the updated position without suspending regular updates. + private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() { + public void onStartTrackingTouch(SeekBar bar) { + show(3600000); + + mDragging = true; + + // By removing these pending progress messages we make sure + // that a) we won't update the progress while the user adjusts + // the SeekBar and b) once the user is done dragging the thumb + // we will post one of these messages to the queue again and + // this ensures that there will be exactly one message queued up. + mHandler.removeMessages(SHOW_PROGRESS); + } + + public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) { + if (mPlayer == null) { + return; + } + + if (!fromUser) { + // We're not interested in programmatically generated changes to + // the progress bar's position. + return; + } + + long duration = mPlayer.getDuration(); + long newPosition = (duration * progress) / 1000L; + mPlayer.seekTo((int) newPosition); + if (mCurrentTime != null) + mCurrentTime.setText(stringForTime((int) newPosition)); + } + + public void onStopTrackingTouch(SeekBar bar) { + mDragging = false; + setProgress(); + updatePausePlay(); + show(sDefaultTimeout); + + // Ensure that progress is properly updated in the future, + // the call to show() does not guarantee this because it is a + // no-op if we are already showing. + mHandler.sendEmptyMessage(SHOW_PROGRESS); + } + }; + + @Override + public void setEnabled(boolean enabled) { + if (mPauseButton != null) { + mPauseButton.setEnabled(enabled); + } + if (mFastForwardButton != null) { + mFastForwardButton.setEnabled(enabled); + } + if (mRewindButton != null) { + mRewindButton.setEnabled(enabled); + } + if (mNextButton != null) { + mNextButton.setEnabled(enabled && mNextListener != null); + } + if (mPrevButton != null) { + mPrevButton.setEnabled(enabled && mPrevListener != null); + } + if (mProgress != null) { + mProgress.setEnabled(enabled); + } + disableUnsupportedButtons(); + super.setEnabled(enabled); + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(MediaController.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(MediaController.class.getName()); + } + + private View.OnClickListener mRewListener = new View.OnClickListener() { + public void onClick(View v) { + if (mPlayer == null) { + return; + } + + int pos = mPlayer.getCurrentPosition(); + pos -= 5000; // milliseconds + mPlayer.seekTo(pos); + setProgress(); + + show(sDefaultTimeout); + } + }; + + private View.OnClickListener mFfwdListener = new View.OnClickListener() { + public void onClick(View v) { + if (mPlayer == null) { + return; + } + + int pos = mPlayer.getCurrentPosition(); + pos += 15000; // milliseconds + mPlayer.seekTo(pos); + setProgress(); + + show(sDefaultTimeout); + } + }; + + private void installPrevNextListeners() { + if (mNextButton != null) { + mNextButton.setOnClickListener(mNextListener); + mNextButton.setEnabled(mNextListener != null); + } + + if (mPrevButton != null) { + mPrevButton.setOnClickListener(mPrevListener); + mPrevButton.setEnabled(mPrevListener != null); + } + } + + public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) { + mNextListener = next; + mPrevListener = prev; + mListenersSet = true; + + if (mRoot != null) { + installPrevNextListeners(); + + if (mNextButton != null && !mFromXml) { + mNextButton.setVisibility(View.VISIBLE); + } + if (mPrevButton != null && !mFromXml) { + mPrevButton.setVisibility(View.VISIBLE); + } + } + } + + private static class MessageHandler extends Handler { + private final WeakReference mView; + + MessageHandler(MediaController view) { + mView = new WeakReference<>(view); + } + + @Override + public void handleMessage(Message msg) { + MediaController view = mView.get(); + if (view == null || view.mPlayer == null) { + return; + } + + int pos; + switch (msg.what) { + case FADE_OUT: + view.hide(); + break; + case SHOW_PROGRESS: + pos = view.setProgress(); + if (!view.mDragging && view.mShowing && view.mPlayer.isPlaying()) { + msg = obtainMessage(SHOW_PROGRESS); + sendMessageDelayed(msg, 1000 - (pos % 1000)); + } + break; + } + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoTextureView.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoTextureView.java new file mode 100644 index 00000000000000..1b32ab895c6970 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoTextureView.java @@ -0,0 +1,118 @@ +package abi49_0_0.expo.modules.av.video; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.SurfaceTexture; +import android.util.Pair; +import android.util.Size; +import android.view.Surface; +import android.view.TextureView; +import android.view.View; + +import abi49_0_0.expo.modules.av.video.scalablevideoview.ScalableType; +import abi49_0_0.expo.modules.av.video.scalablevideoview.ScaleManager; + +@SuppressLint("ViewConstructor") +public class VideoTextureView extends TextureView implements TextureView.SurfaceTextureListener { + + private VideoView mVideoView = null; + private boolean mIsAttachedToWindow = false; + private Surface mSurface = null; + private boolean mVisible = true; + + public VideoTextureView(final Context themedReactContext, VideoView videoView) { + super(themedReactContext, null, 0); + + mVideoView = videoView; + + setSurfaceTextureListener(this); + } + + public boolean isAttachedToWindow() { + return mIsAttachedToWindow; + } + + public Surface getSurface() { + return mSurface; + } + + public void scaleVideoSize(final Pair videoWidthHeight, ScalableType resizeMode) { + final int videoWidth = videoWidthHeight.first; + final int videoHeight = videoWidthHeight.second; + + if (videoWidth == 0 || videoHeight == 0) { + return; + } + + final Size viewSize = new Size(getWidth(), getHeight()); + final Size videoSize = new Size(videoWidth, videoHeight); + final Matrix matrix = new ScaleManager(viewSize, videoSize).getScaleMatrix(resizeMode); + if (matrix != null) { + Matrix prevMatrix = new Matrix(); + getTransform(prevMatrix); + if (!matrix.equals(prevMatrix)) { + setTransform(matrix); + invalidate(); + } + } + } + + public void onResume() { + + // TextureView contains a bug which sometimes causes the view to + // not be rendered after resuming the app (e.g. by unlocking the screen). + // The bug occurs when the hardware layer is destroyed, but onVisibilityChanged + // has not been called. For this particular case we forcefully invalidate the + // view and its layer so it is always drawn correctly after resuming. + if (mVisible) { + onVisibilityChanged(this, View.INVISIBLE); + onVisibilityChanged(this, View.VISIBLE); + } + } + + // TextureView + + @Override + public void onSurfaceTextureAvailable(final SurfaceTexture surfaceTexture, final int width, final int height) { + mSurface = new Surface(surfaceTexture); + mVideoView.tryUpdateVideoSurface(mSurface); + } + + @Override + public void onSurfaceTextureSizeChanged(final SurfaceTexture surfaceTexture, final int width, final int height) { + // no-op + } + + @Override + public void onSurfaceTextureUpdated(final SurfaceTexture surfaceTexture) { + // no-op + } + + @Override + public boolean onSurfaceTextureDestroyed(final SurfaceTexture surfaceTexture) { + mSurface = null; + mVideoView.tryUpdateVideoSurface(null); + return true; + } + + // View + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mIsAttachedToWindow = false; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mIsAttachedToWindow = true; + mVideoView.tryUpdateVideoSurface(mSurface); + } + + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + mVisible = visibility == View.VISIBLE; + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoView.java b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoView.java new file mode 100644 index 00000000000000..86bc0c2f7f8b0c --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoView.java @@ -0,0 +1,546 @@ +package abi49_0_0.expo.modules.av.video; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Bundle; +import android.util.Pair; +import android.view.MotionEvent; +import android.view.Surface; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import abi49_0_0.expo.modules.av.AVManagerInterface; +import abi49_0_0.expo.modules.av.AudioEventHandler; +import abi49_0_0.expo.modules.av.player.PlayerData; +import abi49_0_0.expo.modules.av.player.PlayerDataControl; +import abi49_0_0.expo.modules.av.video.scalablevideoview.ScalableType; +import abi49_0_0.expo.modules.core.Promise; +import abi49_0_0.expo.modules.core.arguments.ReadableArguments; +import abi49_0_0.expo.modules.kotlin.AppContext; +import kotlin.Unit; + +@SuppressLint("ViewConstructor") +public class VideoView extends FrameLayout implements AudioEventHandler, FullscreenVideoPlayerPresentationChangeListener, PlayerData.FullscreenPresenter { + + private final Runnable mMediaControllerUpdater = new Runnable() { + @Override + public void run() { + if (mMediaController != null) { + mMediaController.updateControls(); + } + } + }; + + private final PlayerData.StatusUpdateListener mStatusUpdateListener = new PlayerData.StatusUpdateListener() { + @Override + public void onStatusUpdate(final Bundle status) { + post(mMediaControllerUpdater); + mVideoViewWrapper.getOnStatusUpdate().invoke(status); + } + }; + + private final AVManagerInterface mAVModule; + private VideoViewWrapper mVideoViewWrapper; + + private PlayerData mPlayerData = null; + + private ReadableArguments mLastSource; + private ScalableType mResizeMode = ScalableType.LEFT_TOP; + private boolean mUseNativeControls = false; + private Boolean mOverridingUseNativeControls = null; + private MediaController mMediaController = null; + private Pair mVideoWidthHeight = null; + private FullscreenVideoPlayerPresentationChangeProgressListener mFullscreenPlayerPresentationChangeProgressListener = null; + + private Bundle mStatusToSet = new Bundle(); + + private FullscreenVideoPlayer mFullscreenPlayer = null; + private VideoTextureView mVideoTextureView = null; + + // Fullscreen change requests before the video loads + private boolean mIsLoaded = false; + private boolean mShouldShowFullscreenPlayerOnLoad = false; + private FullscreenVideoPlayerPresentationChangeProgressListener mFullscreenVideoPlayerPresentationOnLoadChangeListener = null; + + public VideoView(@NonNull Context context, VideoViewWrapper videoViewWrapper, AppContext appContext) { + super(context); + + mVideoViewWrapper = videoViewWrapper; + + mAVModule = appContext.getLegacyModuleRegistry().getModule(AVManagerInterface.class); + mAVModule.registerVideoViewForAudioLifecycle(this); + + mVideoTextureView = new VideoTextureView(context, this); + addView(mVideoTextureView, generateDefaultLayoutParams()); + + mFullscreenPlayer = new FullscreenVideoPlayer(context, this, appContext); + mFullscreenPlayer.setUpdateListener(this); + + mMediaController = new MediaController(VideoView.this.getContext()); + mMediaController.setAnchorView(this); + maybeUpdateMediaControllerForUseNativeControls(); + } + + public void unloadPlayerAndMediaController() { + ensureFullscreenPlayerIsDismissed(); + if (mMediaController != null) { + mMediaController.hide(); + mMediaController.setEnabled(false); + mMediaController.setAnchorView(null); + mMediaController = null; + } + if (mPlayerData != null) { + mPlayerData.release(); + mPlayerData = null; + } + mIsLoaded = false; + } + + void onDropViewInstance() { + mAVModule.unregisterVideoViewForAudioLifecycle(this); + unloadPlayerAndMediaController(); + } + + private void callOnError(final String error) { + final Bundle map = new Bundle(); + map.putString("error", error); + mVideoViewWrapper.getOnError().invoke(map); + } + + private void callOnReadyForDisplay(final Pair videoWidthHeight) { + if (videoWidthHeight != null && mIsLoaded) { + final int width = videoWidthHeight.first; + final int height = videoWidthHeight.second; + + if (width == 0 || height == 0) { + return; + } + + final Bundle naturalSize = new Bundle(); + naturalSize.putInt("width", width); + naturalSize.putInt("height", height); + naturalSize.putString("orientation", width > height ? "landscape" : "portrait"); + + final Bundle map = new Bundle(); + map.putBundle("naturalSize", naturalSize); + map.putBundle("status", mPlayerData.getStatus()); + mVideoViewWrapper.getOnReadyForDisplay().invoke(map); + } + } + + public void maybeUpdateMediaControllerForUseNativeControls() { + maybeUpdateMediaControllerForUseNativeControls(true); + } + + public void maybeUpdateMediaControllerForUseNativeControls(boolean showMediaControllerIfEnabled) { + if (mPlayerData != null && mMediaController != null) { + mMediaController.updateControls(); + mMediaController.setEnabled(shouldUseNativeControls()); + if (shouldUseNativeControls() && showMediaControllerIfEnabled) { + mMediaController.show(); + } else { + mMediaController.hide(); + } + } + } + + // Imperative API + + public void ensureFullscreenPlayerIsPresented() { + ensureFullscreenPlayerIsPresented(null); + } + + public void ensureFullscreenPlayerIsPresented(FullscreenVideoPlayerPresentationChangeProgressListener listener) { + if (!mIsLoaded) { + saveFullscreenPlayerStateForOnLoad(true, listener); + return; + } + + if (mFullscreenPlayerPresentationChangeProgressListener != null) { + if (listener != null) { + listener.onFullscreenPlayerPresentationTriedToInterrupt(); + } + return; + } + + if (!isBeingPresentedFullscreen()) { + if (listener != null) { + mFullscreenPlayerPresentationChangeProgressListener = listener; + } + + mFullscreenPlayer.show(); + } else { + if (listener != null) { + listener.onFullscreenPlayerDidPresent(); + } + } + } + + public void ensureFullscreenPlayerIsDismissed() { + ensureFullscreenPlayerIsDismissed(null); + } + + public void ensureFullscreenPlayerIsDismissed(FullscreenVideoPlayerPresentationChangeProgressListener listener) { + if (!mIsLoaded) { + saveFullscreenPlayerStateForOnLoad(false, listener); + return; + } + + if (mFullscreenPlayerPresentationChangeProgressListener != null) { + if (listener != null) { + listener.onFullscreenPlayerPresentationTriedToInterrupt(); + } + return; + } + + if (isBeingPresentedFullscreen()) { + if (listener != null) { + mFullscreenPlayerPresentationChangeProgressListener = listener; + } + + mFullscreenPlayer.dismiss(); + } else { + if (listener != null) { + listener.onFullscreenPlayerDidDismiss(); + } + } + } + + private void saveFullscreenPlayerStateForOnLoad(boolean requestedIsPresentedFullscreen, FullscreenVideoPlayerPresentationChangeProgressListener listener) { + mShouldShowFullscreenPlayerOnLoad = requestedIsPresentedFullscreen; + if (mFullscreenVideoPlayerPresentationOnLoadChangeListener != null) { + mFullscreenVideoPlayerPresentationOnLoadChangeListener.onFullscreenPlayerPresentationInterrupted(); + } + mFullscreenVideoPlayerPresentationOnLoadChangeListener = listener; + } + + @Override + public void onFullscreenPlayerWillPresent() { + callFullscreenCallbackWithUpdate(FullscreenPlayerUpdate.FULLSCREEN_PLAYER_WILL_PRESENT); + + if (mFullscreenPlayerPresentationChangeProgressListener != null) { + mFullscreenPlayerPresentationChangeProgressListener.onFullscreenPlayerWillPresent(); + } + } + + @Override + public void onFullscreenPlayerDidPresent() { + if (mMediaController != null) { + mMediaController.updateControls(); + } + callFullscreenCallbackWithUpdate(FullscreenPlayerUpdate.FULLSCREEN_PLAYER_DID_PRESENT); + + if (mFullscreenPlayerPresentationChangeProgressListener != null) { + mFullscreenPlayerPresentationChangeProgressListener.onFullscreenPlayerDidPresent(); + mFullscreenPlayerPresentationChangeProgressListener = null; + } + } + + @Override + public void onFullscreenPlayerWillDismiss() { + callFullscreenCallbackWithUpdate(FullscreenPlayerUpdate.FULLSCREEN_PLAYER_WILL_DISMISS); + + if (mFullscreenPlayerPresentationChangeProgressListener != null) { + mFullscreenPlayerPresentationChangeProgressListener.onFullscreenPlayerWillDismiss(); + } + } + + @Override + public void onFullscreenPlayerDidDismiss() { + if (mMediaController != null) { + mMediaController.updateControls(); + } + callFullscreenCallbackWithUpdate(FullscreenPlayerUpdate.FULLSCREEN_PLAYER_DID_DISMISS); + + if (mFullscreenPlayerPresentationChangeProgressListener != null) { + mFullscreenPlayerPresentationChangeProgressListener.onFullscreenPlayerDidDismiss(); + mFullscreenPlayerPresentationChangeProgressListener = null; + } + } + + private void callFullscreenCallbackWithUpdate(FullscreenPlayerUpdate update) { + Bundle event = new Bundle(); + event.putInt("fullscreenUpdate", update.getJsValue()); + event.putBundle("status", getStatus()); + mVideoViewWrapper.getOnFullscreenUpdate().invoke(event); + } + + // Prop setting + + public void setStatus(final ReadableArguments status, final Promise promise) { + Bundle statusBundle = status.toBundle(); + mStatusToSet.putAll(statusBundle); + if (mPlayerData != null) { + final Bundle statusToSet = new Bundle(); + statusToSet.putAll(mStatusToSet); + mStatusToSet = new Bundle(); + mPlayerData.setStatus(statusBundle, promise); + } else if (promise != null) { + promise.resolve(PlayerData.getUnloadedStatus()); + } + } + + public Bundle getStatus() { + return mPlayerData == null ? PlayerData.getUnloadedStatus() : mPlayerData.getStatus(); + } + + private boolean shouldUseNativeControls() { + if (mOverridingUseNativeControls != null) { + return mOverridingUseNativeControls; + } + + return mUseNativeControls; + } + + void setOverridingUseNativeControls(final Boolean useNativeControls) { + mOverridingUseNativeControls = useNativeControls; + maybeUpdateMediaControllerForUseNativeControls(); + } + + void setUseNativeControls(final boolean useNativeControls) { + mUseNativeControls = useNativeControls; + maybeUpdateMediaControllerForUseNativeControls(); + } + + private static boolean equalBundles(Bundle one, Bundle two) { + if((one.size() != two.size()) || !one.keySet().containsAll(two.keySet())) { + return false; + } + + for (String key : one.keySet()) { + Object valueOne = one.get(key); + Object valueTwo = two.get(key); + if (valueOne instanceof Bundle && valueTwo instanceof Bundle) { + if (!equalBundles((Bundle) valueOne, (Bundle) valueTwo)) { + return false; + } + } else if (valueOne == null) { + if (valueTwo != null) { + return false; + } + } else if (!valueOne.equals(valueTwo)) { + return false; + } + } + + return true; + } + + public void setSource(final ReadableArguments source) { + if (mLastSource == null || !equalBundles(mLastSource.toBundle(), source.toBundle())) { + mLastSource = source; + setSource(source, null, null); + } + } + + public void setSource(final ReadableArguments source, final ReadableArguments initialStatus, final Promise promise) { + if (mPlayerData != null) { + mStatusToSet.putAll(mPlayerData.getStatus()); + mPlayerData.release(); + mPlayerData = null; + mIsLoaded = false; + } + + if (initialStatus != null) { + mStatusToSet.putAll(initialStatus.toBundle()); + } + + final String uriString = source != null ? source.getString(PlayerData.STATUS_URI_KEY_PATH) : null; + + if (uriString == null) { + if (promise != null) { + promise.resolve(PlayerData.getUnloadedStatus()); + } + return; + } + + mVideoViewWrapper.getOnLoadStart().invoke(Unit.INSTANCE); + + final Bundle statusToInitiallySet = new Bundle(); + statusToInitiallySet.putAll(mStatusToSet); + mStatusToSet = new Bundle(); + + mPlayerData = PlayerData.createUnloadedPlayerData(mAVModule, getContext(), source, statusToInitiallySet); + + mPlayerData.setErrorListener(new PlayerData.ErrorListener() { + @Override + public void onError(final String error) { + unloadPlayerAndMediaController(); + callOnError(error); + } + }); + mPlayerData.setVideoSizeUpdateListener(new PlayerData.VideoSizeUpdateListener() { + @Override + public void onVideoSizeUpdate(final Pair videoWidthHeight) { + mVideoTextureView.scaleVideoSize(videoWidthHeight, mResizeMode); + mVideoWidthHeight = videoWidthHeight; + callOnReadyForDisplay(videoWidthHeight); + } + }); + + mPlayerData.setFullscreenPresenter(this); + + mPlayerData.load(statusToInitiallySet, new PlayerData.LoadCompletionListener() { + @Override + public void onLoadSuccess(final Bundle status) { + mIsLoaded = true; + mVideoTextureView.scaleVideoSize(mPlayerData.getVideoWidthHeight(), mResizeMode); + + if (mVideoTextureView.isAttachedToWindow()) { + mPlayerData.tryUpdateVideoSurface(mVideoTextureView.getSurface()); + } + + if (promise != null) { + final Bundle statusCopy = new Bundle(); + statusCopy.putAll(status); + promise.resolve(statusCopy); + } + + mPlayerData.setStatusUpdateListener(mStatusUpdateListener); + + if (mMediaController == null) { + mMediaController = new MediaController(VideoView.this.getContext()); + } + mMediaController.setMediaPlayer(new PlayerDataControl(mPlayerData)); + mMediaController.setAnchorView(VideoView.this); + maybeUpdateMediaControllerForUseNativeControls(false); + mVideoViewWrapper.getOnLoad().invoke(status); + // Execute the fullscreen player state change requested before the video loaded + if (mFullscreenVideoPlayerPresentationOnLoadChangeListener != null) { + FullscreenVideoPlayerPresentationChangeProgressListener listener = mFullscreenVideoPlayerPresentationOnLoadChangeListener; + mFullscreenVideoPlayerPresentationOnLoadChangeListener = null; + if (mShouldShowFullscreenPlayerOnLoad) { + ensureFullscreenPlayerIsPresented(listener); + } else { + ensureFullscreenPlayerIsDismissed(listener); + } + } + callOnReadyForDisplay(mVideoWidthHeight); + } + + @Override + public void onLoadError(final String error) { + if (mFullscreenVideoPlayerPresentationOnLoadChangeListener != null) { + mFullscreenVideoPlayerPresentationOnLoadChangeListener.onFullscreenPlayerPresentationError(error); + mFullscreenVideoPlayerPresentationOnLoadChangeListener = null; + } + mShouldShowFullscreenPlayerOnLoad = false; + + unloadPlayerAndMediaController(); + if (promise != null) { + promise.reject("E_VIDEO_NOTCREATED", error); + } + callOnError(error); + } + }); + } + + void setResizeMode(final ScalableType resizeMode) { + if (mResizeMode != resizeMode) { + mResizeMode = resizeMode; + if (mPlayerData != null) { + mVideoTextureView.scaleVideoSize(mPlayerData.getVideoWidthHeight(), mResizeMode); + } + } + } + + // View + + private int getReactId() { + return mVideoViewWrapper.getId(); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(final MotionEvent event) { + if (shouldUseNativeControls() && mMediaController != null) { + mMediaController.show(); + } + return super.onTouchEvent(event); + } + + @Override + @SuppressLint("DrawAllocation") + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + if (changed && mPlayerData != null) { + mVideoTextureView.scaleVideoSize(mPlayerData.getVideoWidthHeight(), mResizeMode); + } + } + + // TextureView + + public void tryUpdateVideoSurface(Surface surface) { + if (mPlayerData != null) { + mPlayerData.tryUpdateVideoSurface(surface); + } + } + + // AudioEventHandler + + @Override + public void pauseImmediately() { + if (mPlayerData != null) { + mPlayerData.pauseImmediately(); + } + } + + @Override + public boolean requiresAudioFocus() { + return mPlayerData != null && mPlayerData.requiresAudioFocus(); + } + + @Override + public void updateVolumeMuteAndDuck() { + if (mPlayerData != null) { + mPlayerData.updateVolumeMuteAndDuck(); + } + } + + @Override + public void handleAudioFocusInterruptionBegan() { + if (mPlayerData != null) { + mPlayerData.handleAudioFocusInterruptionBegan(); + } + } + + @Override + public void handleAudioFocusGained() { + if (mPlayerData != null) { + mPlayerData.handleAudioFocusGained(); + } + } + + @Override + public void onPause() { + if (mPlayerData != null) { + ensureFullscreenPlayerIsDismissed(); + mPlayerData.onPause(); + } + } + + @Override + public void onResume() { + if (mPlayerData != null) { + mPlayerData.onResume(); + } + mVideoTextureView.onResume(); + } + + // FullscreenPresenter + + @Override + public boolean isBeingPresentedFullscreen() { + return mFullscreenPlayer.isShowing(); + } + + @Override + public void setFullscreenMode(boolean isFullscreen) { + if (isFullscreen) { + ensureFullscreenPlayerIsPresented(); + } else { + ensureFullscreenPlayerIsDismissed(); + } + } +} diff --git a/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoViewModule.kt b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoViewModule.kt new file mode 100644 index 00000000000000..49c777d04ee133 --- /dev/null +++ b/android/versioned-abis/expoview-abi49_0_0/src/main/java/abi49_0_0/expo/modules/av/video/VideoViewModule.kt @@ -0,0 +1,109 @@ +package abi49_0_0.expo.modules.av.video + +import abi49_0_0.com.facebook.react.bridge.ReadableMap +import abi49_0_0.expo.modules.av.ViewUtils +import abi49_0_0.expo.modules.av.video.scalablevideoview.ScalableType +import abi49_0_0.expo.modules.core.arguments.MapArguments +import abi49_0_0.expo.modules.kotlin.Promise +import abi49_0_0.expo.modules.kotlin.modules.Module +import abi49_0_0.expo.modules.kotlin.modules.ModuleDefinition + +class VideoViewModule : Module() { + override fun definition() = ModuleDefinition { + Name("ExpoVideoView") + + View(VideoViewWrapper::class) { + OnViewDestroys { view -> + view.videoViewInstance.onDropViewInstance() + } + + Events( + "onStatusUpdate", + "onLoadStart", + "onLoad", + "onError", + "onReadyForDisplay", + "onFullscreenUpdate" + ) + + //region Props set directly in