summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author+merlan #flirora <uruwi@protonmail.com>2024-05-30 03:58:07 -0400
committerGitHub <noreply@github.com>2024-05-30 07:58:07 +0000
commitb15aa664f2aa5f25cdf81e0f3bf277938383cf59 (patch)
tree0ff9d37e595367901795d970caa6818b479e580c
parent702271dacb205d43f91736386e5575590f2c3af2 (diff)
Allow `measure` to accept available size (#4264)
-rw-r--r--crates/typst/src/layout/measure.rs46
-rw-r--r--tests/suite/layout/measure.typ13
2 files changed, 51 insertions, 8 deletions
diff --git a/crates/typst/src/layout/measure.rs b/crates/typst/src/layout/measure.rs
index 89054925..7e8ebf58 100644
--- a/crates/typst/src/layout/measure.rs
+++ b/crates/typst/src/layout/measure.rs
@@ -2,17 +2,19 @@ use comemo::Tracked;
use crate::diag::{At, SourceResult};
use crate::engine::Engine;
-use crate::foundations::{dict, func, Content, Context, Dict, StyleChain, Styles};
-use crate::layout::{Abs, Axes, LayoutMultiple, Regions, Size};
+use crate::foundations::{
+ dict, func, Content, Context, Dict, Resolve, Smart, StyleChain, Styles,
+};
+use crate::layout::{Abs, Axes, LayoutMultiple, Length, Regions, Size};
use crate::syntax::Span;
/// Measures the layouted size of content.
///
-/// The `measure` function lets you determine the layouted size of content. Note
-/// that an infinite space is assumed, therefore the measured height/width may
-/// not necessarily match the final height/width of the measured content. If you
-/// want to measure in the current layout dimensions, you can combine `measure`
-/// and [`layout`].
+/// The `measure` function lets you determine the layouted size of content.
+/// By default an infinite space is assumed, so the measured dimensions may
+/// not necessarily match the final dimensions of the content.
+/// If you want to measure in the current layout dimensions, you can combine
+/// `measure` and [`layout`].
///
/// # Example
/// The same content can have a different size depending on the [context] that
@@ -48,6 +50,29 @@ pub fn measure(
context: Tracked<Context>,
/// The callsite span.
span: Span,
+ /// The width available to layout the content.
+ ///
+ /// Defaults to `{auto}`, which denotes an infinite width.
+ ///
+ /// Using the `width` and `height` parameters of this function is
+ /// different from measuring a [`box`] containing the content;
+ /// the former will get the dimensions of the inner content
+ /// instead of the dimensions of the box:
+ ///
+ /// ```example
+ /// #context measure(lorem(100), width: 400pt)
+ ///
+ /// #context measure(block(lorem(100), width: 400pt))
+ /// ```
+ #[named]
+ #[default(Smart::Auto)]
+ width: Smart<Length>,
+ /// The height available to layout the content.
+ ///
+ /// Defaults to `{auto}`, which denotes an infinite height.
+ #[named]
+ #[default(Smart::Auto)]
+ height: Smart<Length>,
/// The content whose size to measure.
content: Content,
/// _Compatibility:_ This argument only exists for compatibility with
@@ -60,7 +85,12 @@ pub fn measure(
None => context.styles().at(span)?,
};
- let pod = Regions::one(Axes::splat(Abs::inf()), Axes::splat(false));
+ let available = Axes::new(
+ width.resolve(styles).unwrap_or(Abs::inf()),
+ height.resolve(styles).unwrap_or(Abs::inf()),
+ );
+
+ let pod = Regions::one(available, Axes::splat(false));
let frame = content.measure(engine, styles, pod)?.into_frame();
let Size { x, y } = frame.size();
Ok(dict! { "width" => x, "height" => y })
diff --git a/tests/suite/layout/measure.typ b/tests/suite/layout/measure.typ
index 5f82e915..10c3c818 100644
--- a/tests/suite/layout/measure.typ
+++ b/tests/suite/layout/measure.typ
@@ -7,3 +7,16 @@
}
#text(10pt, f(6pt, 8pt))
#text(20pt, f(13pt, 14pt))
+
+--- measure-given-area ---
+// Test `measure` given an area.
+#let text = lorem(100)
+
+#context {
+ let d1 = measure(text)
+ assert(d1.width > 2000pt)
+ assert(d1.height < 10pt)
+ let d2 = measure(width: 400pt, height: auto, text)
+ assert(d2.width < 400pt)
+ assert(d2.height > 50pt)
+}