Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Image resizeMode=repeat on Android #17404

Closed

Conversation

motiz88
Copy link
Contributor

@motiz88 motiz88 commented Dec 31, 2017

Motivation

<Image resizeMode="repeat" /> for Android, matching the iOS implementation (#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. #14158.

Approach and caveats

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with onLayout and multiple <Image> instances.

  • Picking up on a TODO note in the existing code, I implemented MultiPostprocessor to allow arbitrary chaining of Fresco-compatible postprocessors inside ReactImageView.
  • Rather than extensively refactor ImageResizeMode, ReactImageManager and ReactImageView, I mostly preserved the existing API that maps resizeMode values to ScaleType instances, and simply added a second mapping, to TileMode.
  • To match the iOS rendering exactly for oversized images, I found that scaling with a custom ScaleType was required - a kind of combination of CENTER_INSIDE and FIT_START which Fresco doesn't provide - so I implemented that as ScaleTypeStartInside. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
  • resizeMode="repeat" is therefore unpacked by the view manager to the effect of:
       view.setScaleType(ScaleTypeStartInside.INSTANCE);
       view.setTileMode(Shader.TileMode.REPEAT);
    And the added postprocessing in the view (in case of a non-CLAMP tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in #17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken this comment to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Test Plan

Tested by enabling the relevant case in RNTester on Android.

iOS Android

Related PRs

Docs update: facebook/react-native-website#106

Release Notes

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Dec 31, 2017
motiz88 added a commit to motiz88/react-native-website that referenced this pull request Dec 31, 2017
@motiz88
Copy link
Contributor Author

motiz88 commented Dec 31, 2017

I've just noticed that resizeMode=contain seems to be broken in the Android screenshot - I'll investigate and come up with a fix if this is due to my changes.

UPDATE: Nope, it's like that on master. @shergin would you like me to open an issue for this?

@janicduplessis
Copy link
Contributor

Looks like contain stretches the image background color on android, you could open an issue about it.

@janicduplessis
Copy link
Contributor

janicduplessis commented Jan 20, 2018

What would be the idea scale type behavior when using repeat? I’d rather not add a new one to match iOS if possible.

@janicduplessis
Copy link
Contributor

I’ll try to review this in the next few days, I did the ios implementation so I don’t mind making small changes to it also if it makes sense.

@motiz88
Copy link
Contributor Author

motiz88 commented Jan 20, 2018

  1. To my mind, a resizeMode of repeat should never scale the image but only crop it. But to change it now on iOS would be a breaking change - is it worth it?

  2. The wider problem I alluded to above (which, again, I think is a non-goal for this particular PR, but is worth mentioning) is that users coming from CSS expect sophisticated independent controls over resizing, tiling, cropping/positioning and other properties of background images, of which RN provides an arbitrary subset to begin with. I'd be happy if we started a project to fix that with a more powerful CSS-aligned API, rather than trade one arbitrary choice for another within the too-limited framework of resizeMode as it stands.

@motiz88
Copy link
Contributor Author

motiz88 commented Jan 20, 2018

I've opened #17684 for the contain / center issue.

@mdvacca
Copy link
Contributor

mdvacca commented Feb 3, 2018

@motiz88 can you resolve the conflicts?

@motiz88 motiz88 force-pushed the image-resizemode-repeat-android branch from d2cb163 to 433baed Compare February 3, 2018 13:38
@motiz88
Copy link
Contributor Author

motiz88 commented Feb 3, 2018

@mdvacca - done.

@motiz88
Copy link
Contributor Author

motiz88 commented Feb 18, 2018

@janicduplessis No pressure, but do you think there's anything I could do from my side to help get this merged?

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdvacca has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@motiz88 I tried to find reviewers for this pull request and wanted to ping them to take another look. However, based on the blame information for the files in this pull request I couldn't find any reviewers. This sometimes happens when the files in the pull request are new or don't exist on master anymore. Is this pull request still relevant? If yes could you please rebase? In case you know who has context on this code feel free to mention them in a comment (one person is fine). Thanks for reading and hope you will continue contributing to the project.

@motiz88
Copy link
Contributor Author

motiz88 commented Mar 5, 2018

Will rebase tomorrow if it helps

@janicduplessis
Copy link
Contributor

@motiz88 Sorry about the delay with this, rebasing on master would be nice, hopefully it gets CI passing :)

@mdvacca What is the status of the import? I could have a look this week if that can help.

@mdvacca
Copy link
Contributor

mdvacca commented Mar 8, 2018

I will re-import and code-review this PR after the rebase.
Thanks for working on this @motiz88

@motiz88 motiz88 force-pushed the image-resizemode-repeat-android branch from 433baed to 90c2719 Compare March 8, 2018 17:51
@motiz88
Copy link
Contributor Author

motiz88 commented Mar 8, 2018

@mdvacca - rebased

@mdvacca
Copy link
Contributor

mdvacca commented Mar 8, 2018

Great! I will review it later today

Copy link
Contributor

@mdvacca mdvacca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this @motiz88!
I just added a few comments

if ("stretch".equals(resizeModeValue)) {
return Shader.TileMode.CLAMP;
}
if ("center".equals(resizeModeValue)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: why not to unify all the conditions that return Shader.TileMode.CLAMP into one "IF"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going for a clear parallel with the structure of toScaleType() above, but I see your point - will fix

canvas.drawRect(destRect, paint);
return output.clone();
} finally {
output.close();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use CloseableReference.closeSafely(output);

try {
Canvas canvas = new Canvas(output.get());
canvas.drawRect(destRect, paint);
return output.clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: do you need to clone the output?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This clones just the reference (a cheap operation), unless I'm missing something? So to gracefully handle any errors between allocating and returning the bitmap (e.g. I don't know if new Canvas() might throw, or if more code might be introduced in between), I treat output as a local reference which gets released within process(), and explicitly make a new reference to return (keeping the Bitmap alive) right before releasing it.

}
return nextBitmap.clone();
} finally {
if (nextBitmap != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CloseableReference.closeSafely();

try {
for (Postprocessor p : mPostprocessors) {
nextBitmap = p.process(prevBitmap != null ? prevBitmap.get() : sourceBitmap, bitmapFactory);
if (prevBitmap != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CloseableReference.closeSafely();

}
name.append(p.getName());
first = false;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you simplify this "for" statement?

@motiz88
Copy link
Contributor Author

motiz88 commented Mar 12, 2018

@mdvacca Thanks for the review! I've addressed everything, just not sure if 431a560 is what you had in mind with #17404 (comment).

@mdvacca
Copy link
Contributor

mdvacca commented Mar 12, 2018

Thank you for addressing everything so fast! The code looks good to me.
I will re-import this and land it.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdvacca has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

hamaron pushed a commit to hamaron/react-native that referenced this pull request Apr 9, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
charpeni pushed a commit to facebook/react-native-website that referenced this pull request Apr 9, 2018
* Update Image resizeMode=repeat docs for Android

To go along with facebook/react-native#17404

* Describe actual Image resizeMode=repeat behaviour

* Clarify Image resizeMode=repeat wording
campsafari pushed a commit to exozet/react-native that referenced this pull request Apr 11, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
LukeDurrant pushed a commit to LukeDurrant/react-native that referenced this pull request Apr 11, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
LukeDurrant pushed a commit to LukeDurrant/react-native that referenced this pull request Apr 11, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
bunnyc1986 pushed a commit to bunnyc1986/react-native that referenced this pull request May 11, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
buoyad pushed a commit to keybase/react-native that referenced this pull request Jun 5, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
(cherry picked from commit 0459e4f)
lnikkila pushed a commit to Boulevard/react-native that referenced this pull request Jun 6, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
macdoum1 pushed a commit to macdoum1/react-native that referenced this pull request Jun 28, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (facebook#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. facebook#14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
rozele pushed a commit to microsoft/react-native-windows that referenced this pull request Aug 17, 2018
Summary:
`<Image resizeMode="repeat" />` for Android, matching the iOS implementation (#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future)

As requested in e.g. #14158.

Given facebook/fresco#1575, and lacking the context to follow the specific recommendations in facebook/fresco#1575 (comment), I've opted for a minimal change within RN itself.

It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `<Image>` instances.

- Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`.
- Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html).
- To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here)
- `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of:
  ```js
     view.setScaleType(ScaleTypeStartInside.INSTANCE);
     view.setTileMode(Shader.TileMode.REPEAT);
   ```
  And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type.

Note that as in facebook/react-native#17398 (comment), I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](facebook/react-native#12770 (comment)) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers.

Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder.

Tested by enabling the relevant case in RNTester on Android.

| iOS | Android |
|-|-|
| <img src=https://user-images.githubusercontent.com/2246565/34461897-4e12008e-ee2f-11e7-8581-1dc0cc8f2779.png width=300>| <img src=https://user-images.githubusercontent.com/2246565/34461894-40b2c8ec-ee2f-11e7-8a8f-96704f3c8caa.png width=300> |

Docs update: facebook/react-native-website#106

[ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat
Closes facebook/react-native#17404

Reviewed By: achen1

Differential Revision: D7070329

Pulled By: mdvacca

fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249
risenforward pushed a commit to risenforward/proactive-web that referenced this pull request Jan 4, 2019
* Update Image resizeMode=repeat docs for Android

To go along with facebook/react-native#17404

* Describe actual Image resizeMode=repeat behaviour

* Clarify Image resizeMode=repeat wording
JackWillie added a commit to JackWillie/react-native-website that referenced this pull request Nov 27, 2022
* Update Image resizeMode=repeat docs for Android

To go along with facebook/react-native#17404

* Describe actual Image resizeMode=repeat behaviour

* Clarify Image resizeMode=repeat wording
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants