From b1b70a420d8373868e5165ae53e179472d9a5151 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Sat, 10 Jun 2017 14:43:58 -0700 Subject: [PATCH] [fix] Image support for inline SVG data SVG data may contain characters that need escaping when applied as a CSS background image. Fix #512 --- docs/storybook/components/Image/ImageExample.js | 8 ++++++++ src/components/Image/ImageUriCache.js | 4 +++- src/components/Image/index.js | 11 ++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/storybook/components/Image/ImageExample.js b/docs/storybook/components/Image/ImageExample.js index 1a7cdbb7..acdc5a87 100644 --- a/docs/storybook/components/Image/ImageExample.js +++ b/docs/storybook/components/Image/ImageExample.js @@ -30,6 +30,8 @@ import { ActivityIndicator, Image, StyleSheet, Text, View } from 'react-native'; const base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg=='; +const dataSvg = + 'data:image/svg+xml;utf8,'; const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now(); const prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL); @@ -475,6 +477,12 @@ const examples = [ return ; } }, + { + title: 'Data SVG', + render() { + return ; + } + }, { title: 'Image dimensions', description: diff --git a/src/components/Image/ImageUriCache.js b/src/components/Image/ImageUriCache.js index c1b6ad1b..11655059 100644 --- a/src/components/Image/ImageUriCache.js +++ b/src/components/Image/ImageUriCache.js @@ -2,13 +2,15 @@ * @flow */ +const dataUriPattern = /^data:/; + export default class ImageUriCache { static _maximumEntries: number = 256; static _entries = {}; static has(uri: string) { const entries = ImageUriCache._entries; - const isDataUri = /^data:/.test(uri); + const isDataUri = dataUriPattern.test(uri); return isDataUri || Boolean(entries[uri]); } diff --git a/src/components/Image/index.js b/src/components/Image/index.js index a10aee73..06532981 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -45,8 +45,17 @@ const resolveAssetDimensions = source => { } }; +const svgDataUriPattern = /^data:image\/svg\+xml;/; const resolveAssetSource = source => { - return (typeof source === 'object' ? source.uri : source) || ''; + const uri = typeof source === 'object' ? source.uri : source || ''; + // SVG data may contain characters (e.g., #, ") that need to be escaped + if (svgDataUriPattern.test(uri)) { + const parts = uri.split('