-
Notifications
You must be signed in to change notification settings - Fork 204
Add Rect support for ObjectFit::affine.
#1791
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| use crate::core::Property; | ||
| use crate::kurbo::{Affine, Axis, Size}; | ||
| use crate::kurbo::{Affine, Axis, Rect, Size}; | ||
| use crate::layout::{LenReq, Length}; | ||
| use crate::util::Sanitize; | ||
|
|
||
|
|
@@ -67,34 +67,32 @@ impl Default for ObjectFit { | |
| } | ||
| } | ||
|
|
||
| // TODO - Need to write tests for this, in a way that's relatively easy to visualize. | ||
|
|
||
| impl ObjectFit { | ||
| /// Calculates an [`Affine`] transform to fit `content` inside `container`. | ||
| /// | ||
| /// Both `content` and `container` can have arbitrary origins, which will be | ||
| /// correctly translated in the returned `Affine`. | ||
| /// | ||
| /// See [`ObjectFit`] variant documentation for fitting details. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics if either `content` or `container` is non-finite or negative | ||
| /// Panics if either `content` or `container` has non-finite or negative size | ||
| /// and debug assertions are enabled. | ||
| pub fn affine(self, container: Size, content: Size) -> Affine { | ||
| pub fn affine(self, container: Rect, content: Rect) -> Affine { | ||
| // Guard against invalid input | ||
| let container = Size::new( | ||
| container.width.sanitize("container width"), | ||
| container.height.sanitize("container height"), | ||
| ); | ||
| let content = Size::new( | ||
| content.width.sanitize("content width"), | ||
| content.height.sanitize("content height"), | ||
| ); | ||
| let container_width = container.width().sanitize("container width"); | ||
| let container_height = container.height().sanitize("container height"); | ||
| let content_width = content.width().sanitize("content width"); | ||
| let content_height = content.height().sanitize("content height"); | ||
|
|
||
| // Guard against division by zero | ||
| if content.width == 0. || content.height == 0. { | ||
| if content_width == 0. || content_height == 0. { | ||
| return Affine::IDENTITY; | ||
| } | ||
|
|
||
| let raw_scalex = container.width / content.width; | ||
| let raw_scaley = container.height / content.height; | ||
| let raw_scalex = container_width / content_width; | ||
| let raw_scaley = container_height / content_height; | ||
|
|
||
| let (scalex, scaley) = match self { | ||
| Self::Contain => { | ||
|
|
@@ -115,10 +113,17 @@ impl ObjectFit { | |
| Self::Stretch => (raw_scalex, raw_scaley), | ||
| }; | ||
|
|
||
| let origin_x = (container.width - (content.width * scalex)) * 0.5; | ||
| let origin_y = (container.height - (content.height * scaley)) * 0.5; | ||
| let origin_x = container.x0 + (container_width - (content_width * scalex)) * 0.5; | ||
| let origin_y = container.y0 + (container_height - (content_height * scaley)) * 0.5; | ||
|
Comment on lines
+116
to
+117
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this new function adds a translation component to account for differences in Rect position? This need to be documented.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it now translates arbitrary origins instead of just assuming |
||
|
|
||
| Affine::new([scalex, 0., 0., scaley, origin_x, origin_y]) | ||
| Affine::new([ | ||
| scalex, | ||
| 0., | ||
| 0., | ||
| scaley, | ||
| origin_x - content.x0 * scalex, | ||
| origin_y - content.y0 * scaley, | ||
| ]) | ||
| } | ||
|
|
||
| /// Calculates the [`Length`] of `axis`. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Correctly translated" doesn't give me a strong intuition for how this function will behave given rects with non-zero origin.
My guess would have been "it just adds a applies of
container.origin - content.originto the affine", but the code seems to do something more complex than that?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it does do that, but also accounts for scale changes. In every case the
contentwill end up being inside ofcontainer, but depending on exact fit strategy, some ofcontentmight overflow.I'll give a brief example and its journey through this method.