Skip to content

Commit 32f990b

Browse files
committed
Calculate paragraph bounding box
1 parent 8e38749 commit 32f990b

File tree

6 files changed

+81
-3
lines changed

6 files changed

+81
-3
lines changed

package/cpp/api/JsiSkParagraph.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ class JsiSkParagraph : public JsiSkHostObject {
5555
return static_cast<double>(_paragraph->getMaxWidth());
5656
}
5757

58+
JSI_HOST_FUNCTION(getMaxIntrinsicWidth) {
59+
return static_cast<double>(_paragraph->getMaxIntrinsicWidth());
60+
}
61+
62+
JSI_HOST_FUNCTION(getMinIntrinsicWidth) {
63+
return static_cast<double>(_paragraph->getMinIntrinsicWidth());
64+
}
65+
5866
JSI_HOST_FUNCTION(getGlyphPositionAtCoordinate) {
5967
auto dx = getArgumentAsNumber(runtime, arguments, count, 0);
6068
auto dy = getArgumentAsNumber(runtime, arguments, count, 1);
@@ -113,6 +121,8 @@ class JsiSkParagraph : public JsiSkHostObject {
113121
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkParagraph, layout),
114122
JSI_EXPORT_FUNC(JsiSkParagraph, paint),
115123
JSI_EXPORT_FUNC(JsiSkParagraph, getMaxWidth),
124+
JSI_EXPORT_FUNC(JsiSkParagraph, getMinIntrinsicWidth),
125+
JSI_EXPORT_FUNC(JsiSkParagraph, getMaxIntrinsicWidth),
116126
JSI_EXPORT_FUNC(JsiSkParagraph, getHeight),
117127
JSI_EXPORT_FUNC(JsiSkParagraph, getRectsForPlaceholders),
118128
JSI_EXPORT_FUNC(JsiSkParagraph,
24.7 KB
Loading
26.7 KB
Loading

package/src/renderer/__tests__/e2e/Paragraphs.spec.tsx

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ describe("Paragraphs", () => {
453453
);
454454
});
455455

456-
itRunsE2eOnly("should draw the bounding box", async () => {
456+
itRunsE2eOnly("should draw the bounding box (1)", async () => {
457457
const img = await surface.drawOffscreen(
458458
(Skia, canvas, { bold, boldItalic, italic }) => {
459459
const para = Skia.ParagraphBuilder.Make()
@@ -474,10 +474,12 @@ describe("Paragraphs", () => {
474474
.pop()
475475
.build();
476476
para.layout(150);
477-
const height = para.getHeight();
478477
const paint = Skia.Paint();
479478
paint.setColor(Skia.Color("cyan"));
480-
canvas.drawRect(Skia.XYWHRect(0, 0, 150, height), paint);
479+
canvas.drawRect(
480+
Skia.XYWHRect(0, 0, para.getMaxWidth(), para.getHeight()),
481+
paint
482+
);
481483
para.paint(canvas, 0, 0);
482484
},
483485
{
@@ -492,6 +494,46 @@ describe("Paragraphs", () => {
492494
);
493495
});
494496

497+
it("should draw the bounding box (2)", async () => {
498+
const img = await surface.drawOffscreen(
499+
(Skia, canvas, ctx) => {
500+
const robotoRegular = Skia.Typeface.MakeFreeTypeFaceFromData(
501+
Skia.Data.fromBytes(new Uint8Array(ctx.RobotoRegular))
502+
)!;
503+
const provider = Skia.TypefaceFontProvider.Make();
504+
provider.registerFont(robotoRegular, "Roboto");
505+
const para = Skia.ParagraphBuilder.Make(
506+
{
507+
textStyle: {
508+
color: Skia.Color("black"),
509+
fontSize: 30,
510+
},
511+
},
512+
provider
513+
)
514+
.addText("Say Hello to React Native Skia")
515+
.build();
516+
para.layout(150);
517+
const paint = Skia.Paint();
518+
paint.setColor(Skia.Color("cyan"));
519+
const maxWidth = para.getMaxWidth();
520+
const height = para.getHeight();
521+
const maxIntrinsicWidth = para.getMaxIntrinsicWidth();
522+
// The width of the bounding box is the smaller of the maximum width or the maximum intrinsic width
523+
const width = Math.min(maxWidth, maxIntrinsicWidth);
524+
canvas.drawRect(Skia.XYWHRect(0, 0, width, height), paint);
525+
para.paint(canvas, 0, 0);
526+
},
527+
{
528+
RobotoRegular,
529+
}
530+
);
531+
checkImage(
532+
img,
533+
`snapshots/paragraph/paragraph-bounding-box-${surface.OS}.png`
534+
);
535+
});
536+
495537
itRunsE2eOnly("should return the paragraph height", async () => {
496538
const { width, height } = await surface.eval((Skia) => {
497539
const para = Skia.ParagraphBuilder.Make()

package/src/skia/types/Paragraph/Paragraph.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ export interface SkParagraph extends SkJSIInstance<"Paragraph"> {
3232
* method to have been called first.
3333
*/
3434
getMaxWidth(): number;
35+
/**
36+
* Returns the minimum intrinsic width of the paragraph.
37+
* The minimum intrinsic width is the width beyond which increasing the width of the paragraph
38+
* does not decrease the height. This is effectively the width at which the paragraph
39+
* can no longer wrap lines and is forced to overflow.
40+
* This method requires the layout method to have been called first.
41+
* @returns {number} The minimum intrinsic width of the paragraph.
42+
*/
43+
getMinIntrinsicWidth(): number;
44+
/**
45+
* Returns the maximum intrinsic width of the paragraph.
46+
* The maximum intrinsic width is the width at which the paragraph can layout its content without line breaks,
47+
* meaning it's the width of the widest line or the widest word if the widest line is shorter than that.
48+
* This width represents the ideal width for the paragraph to display all content in a single line without overflow.
49+
* This method requires the layout method to have been called first.
50+
* @returns {number} The maximum intrinsic width of the paragraph.
51+
*/
52+
getMaxIntrinsicWidth(): number;
53+
3554
/**
3655
* Returns the index of the glyph at the given position. This method requires
3756
* the layout method to have been called first.

package/src/skia/web/JsiSkParagraph.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ export class JsiSkParagraph
1212
constructor(CanvasKit: CanvasKit, ref: Paragraph) {
1313
super(CanvasKit, ref, "Paragraph");
1414
}
15+
getMinIntrinsicWidth(): number {
16+
return this.ref.getMinIntrinsicWidth();
17+
}
18+
19+
getMaxIntrinsicWidth(): number {
20+
return this.ref.getMaxIntrinsicWidth();
21+
}
1522

1623
layout(width: number): void {
1724
this.ref.layout(width);

0 commit comments

Comments
 (0)