Skip to content

Commit

Permalink
Add support for loading vector drawables
Browse files Browse the repository at this point in the history
Reviewed By: oprisnik

Differential Revision: D64209263
  • Loading branch information
Abbondanzo authored and facebook-github-bot committed Oct 18, 2024
1 parent ae2cec4 commit 8dc93e7
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
val animationRenderFpsLimit: Int
val prefetchShortcutEnabled: Boolean
val platformDecoderOptions: PlatformDecoderOptions
val isBinaryXmlEnabled: Boolean

class Builder(private val configBuilder: ImagePipelineConfig.Builder) {
@JvmField var shouldUseDecodingBufferHelper = false
Expand Down Expand Up @@ -127,6 +128,8 @@ class ImagePipelineExperiments private constructor(builder: Builder) {

@JvmField var platformDecoderOptions = PlatformDecoderOptions()

@JvmField var isBinaryXmlEnabled = false

private fun asBuilder(block: () -> Unit): Builder {
block()
return this
Expand Down Expand Up @@ -324,6 +327,10 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
this.platformDecoderOptions = platformDecoderOptions
}

fun setBinaryXmlEnabled(binaryXmlEnabled: Boolean) = asBuilder {
isBinaryXmlEnabled = binaryXmlEnabled
}

fun build(): ImagePipelineExperiments = ImagePipelineExperiments(this)
}

Expand Down Expand Up @@ -442,6 +449,7 @@ class ImagePipelineExperiments private constructor(builder: Builder) {
cancelDecodeOnCacheMiss = builder.cancelDecodeOnCacheMiss
prefetchShortcutEnabled = builder.prefetchShortcutEnabled
platformDecoderOptions = builder.platformDecoderOptions
isBinaryXmlEnabled = builder.isBinaryXmlEnabled
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import com.facebook.imagepipeline.transcoder.ImageTranscoderFactory;
import com.facebook.imagepipeline.transcoder.MultiImageTranscoderFactory;
import com.facebook.imagepipeline.transcoder.SimpleImageTranscoderFactory;
import com.facebook.imagepipeline.xml.XmlDrawableFactory;
import com.facebook.imagepipeline.xml.XmlFormatDecoder;
import com.facebook.infer.annotation.Nullsafe;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
Expand Down Expand Up @@ -246,19 +248,23 @@ private ImageDecoder getImageDecoder() {
webPDecoder = animatedFactory.getWebPDecoder();
}

ImageDecoder xmlDecoder = this.getXmlImageDecoder();

if (mConfig.getImageDecoderConfig() == null) {
mImageDecoder = new DefaultImageDecoder(gifDecoder, webPDecoder, getPlatformDecoder());
mImageDecoder =
new DefaultImageDecoder(gifDecoder, webPDecoder, xmlDecoder, getPlatformDecoder());
} else {
mImageDecoder =
new DefaultImageDecoder(
gifDecoder,
webPDecoder,
xmlDecoder,
getPlatformDecoder(),
mConfig.getImageDecoderConfig().getCustomImageDecoders());
// Add custom image formats if needed
ImageFormatChecker.getInstance()
.setCustomImageFormatCheckers(
mConfig.getImageDecoderConfig().getCustomImageFormats());
.setCustomImageFormatCheckers(mConfig.getImageDecoderConfig().getCustomImageFormats())
.setBinaryXmlEnabled(mConfig.getExperiments().isBinaryXmlEnabled());
}
}
}
Expand Down Expand Up @@ -418,4 +424,22 @@ public String reportData() {
}
return b.toString();
}

@Nullable
public ImageDecoder getXmlImageDecoder() {
if (mConfig.getExperiments().isBinaryXmlEnabled()) {
return new XmlFormatDecoder(mConfig.getContext().getApplicationContext().getResources());
} else {
return null;
}
}

@Nullable
public DrawableFactory getXmlDrawableFactory() {
if (mConfig.getExperiments().isBinaryXmlEnabled()) {
return new XmlDrawableFactory();
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class DefaultImageDecoder implements ImageDecoder {

private final @Nullable ImageDecoder mAnimatedGifDecoder;
private final @Nullable ImageDecoder mAnimatedWebPDecoder;
private final @Nullable ImageDecoder mXmlDecoder;
private final PlatformDecoder mPlatformDecoder;
private final Supplier<Boolean> mEnableEncodedImageColorSpaceUsage;

Expand All @@ -77,7 +78,7 @@ public class DefaultImageDecoder implements ImageDecoder {
} else if (imageFormat == DefaultImageFormats.WEBP_ANIMATED) {
return decodeAnimatedWebp(encodedImage, length, qualityInfo, options);
} else if (imageFormat == DefaultImageFormats.BINARY_XML) {
throw new DecodeException("unsupported image format", encodedImage);
return decodeXml(encodedImage, length, qualityInfo, options);
} else if (imageFormat == ImageFormat.UNKNOWN) {
throw new DecodeException("unknown image format", encodedImage);
}
Expand All @@ -90,17 +91,20 @@ public class DefaultImageDecoder implements ImageDecoder {
public DefaultImageDecoder(
@Nullable final ImageDecoder animatedGifDecoder,
@Nullable final ImageDecoder animatedWebPDecoder,
@Nullable final ImageDecoder xmlDecoder,
final PlatformDecoder platformDecoder) {
this(animatedGifDecoder, animatedWebPDecoder, platformDecoder, null);
this(animatedGifDecoder, animatedWebPDecoder, xmlDecoder, platformDecoder, null);
}

public DefaultImageDecoder(
@Nullable final ImageDecoder animatedGifDecoder,
@Nullable final ImageDecoder animatedWebPDecoder,
@Nullable final ImageDecoder xmlDecoder,
final PlatformDecoder platformDecoder,
@Nullable Map<ImageFormat, ImageDecoder> customDecoders) {
mAnimatedGifDecoder = animatedGifDecoder;
mAnimatedWebPDecoder = animatedWebPDecoder;
mXmlDecoder = xmlDecoder;
mPlatformDecoder = platformDecoder;
mCustomDecoders = customDecoders;
mEnableEncodedImageColorSpaceUsage = Suppliers.BOOLEAN_FALSE;
Expand All @@ -109,11 +113,13 @@ public DefaultImageDecoder(
public DefaultImageDecoder(
@Nullable final ImageDecoder animatedGifDecoder,
@Nullable final ImageDecoder animatedWebPDecoder,
@Nullable final ImageDecoder xmlDecoder,
final PlatformDecoder platformDecoder,
@Nullable Map<ImageFormat, ImageDecoder> customDecoders,
final Supplier<Boolean> enableEncodedImageColorSpaceUsage) {
mAnimatedGifDecoder = animatedGifDecoder;
mAnimatedWebPDecoder = animatedWebPDecoder;
mXmlDecoder = xmlDecoder;
mPlatformDecoder = platformDecoder;
mCustomDecoders = customDecoders;
mEnableEncodedImageColorSpaceUsage = enableEncodedImageColorSpaceUsage;
Expand Down Expand Up @@ -266,4 +272,23 @@ public CloseableStaticBitmap decodeJpeg(
}
return decodeStaticImage(encodedImage, options);
}

/**
* Decodes a binary xml resource.
*
* @param encodedImage input image (encoded bytes plus meta data)
* @param length amount of currently available data in bytes
* @param qualityInfo quality info for the image
* @return a CloseableStaticBitmap
*/
private @Nullable CloseableImage decodeXml(
final EncodedImage encodedImage,
final int length,
final QualityInfo qualityInfo,
final ImageDecodeOptions options) {
if (mXmlDecoder != null) {
return mXmlDecoder.decode(encodedImage, length, qualityInfo, options);
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,16 @@ class DefaultFrescoVitoProvider(
companion object {
private fun createDefaultDrawableFactory(): ImageOptionsDrawableFactory {
val animatedDrawableFactory =
ImagePipelineFactory.getInstance().getAnimatedDrawableFactory(null)
ImagePipelineFactory.getInstance()
.getAnimatedDrawableFactory(null)
?.let(DrawableFactoryWrapper::wrap)
val bitmapFactory = BitmapDrawableFactory()
return if (animatedDrawableFactory == null) {
bitmapFactory
} else {
ArrayVitoDrawableFactory(
bitmapFactory, DrawableFactoryWrapper.wrap(animatedDrawableFactory))
val xmlFactory =
ImagePipelineFactory.getInstance().xmlDrawableFactory?.let(DrawableFactoryWrapper::wrap)
val factories = listOfNotNull(bitmapFactory, animatedDrawableFactory, xmlFactory)
return when (factories.size) {
1 -> factories[0]
else -> ArrayVitoDrawableFactory(*factories.toTypedArray())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.facebook.fresco.vito.core.impl.DebugOverlayHandler
import com.facebook.fresco.vito.core.impl.FrescoVitoPrefetcherImpl
import com.facebook.fresco.vito.core.impl.KFrescoController
import com.facebook.fresco.vito.core.impl.VitoImagePipelineImpl
import com.facebook.fresco.vito.drawable.ArrayVitoDrawableFactory
import com.facebook.fresco.vito.draweesupport.DrawableFactoryWrapper
import com.facebook.fresco.vito.options.ImageOptionsDrawableFactory
import com.facebook.fresco.vito.provider.impl.NoOpCallerContextVerifier
Expand Down Expand Up @@ -62,8 +63,19 @@ class KFrescoVitoProvider(
override fun getConfig(): FrescoVitoConfig = vitoConfig

private fun getFactory(): ImageOptionsDrawableFactory? {
return ImagePipelineFactory.getInstance()
.getAnimatedDrawableFactory(null)
?.let(DrawableFactoryWrapper::wrap)
val animatedDrawableFactory =
ImagePipelineFactory.getInstance()
.getAnimatedDrawableFactory(null)
?.let(DrawableFactoryWrapper::wrap)
val xmlFactory =
ImagePipelineFactory.getInstance()
.getXmlDrawableFactory()
?.let(DrawableFactoryWrapper::wrap)
val factories = listOfNotNull(animatedDrawableFactory, xmlFactory)
return when (factories.size) {
0 -> null
1 -> factories[0]
else -> ArrayVitoDrawableFactory(*factories.toTypedArray())
}
}
}

0 comments on commit 8dc93e7

Please sign in to comment.