Skip to content

Commit

Permalink
Add measureText() method (#1870)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon authored Sep 25, 2023
1 parent ead0e50 commit 0ec9dad
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 2 deletions.
Binary file added example/src/Tests/assets/DIN-Medium.ttf
Binary file not shown.
6 changes: 6 additions & 0 deletions example/src/Tests/useAssets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export const useAssets = () => {
require("./assets/NotoSansSC-Regular.otf"),
errorHandler
);
const DinMedium = useTypeface(
require("./assets/DIN-Medium.ttf"),
errorHandler
);
if (error) {
throw new Error("Failed to load assets: " + error.message);
}
Expand All @@ -44,6 +48,7 @@ export const useAssets = () => {
!NotoColorEmoji ||
!NotoSansSCRegular ||
!UberMoveMediumMono ||
!DinMedium ||
!skiaLogoJpeg ||
!skiaLogoPng ||
!mask
Expand All @@ -55,6 +60,7 @@ export const useAssets = () => {
NotoColorEmoji,
NotoSansSCRegular,
UberMoveMediumMono,
DinMedium,
oslo,
skiaLogoJpeg,
skiaLogoPng,
Expand Down
17 changes: 17 additions & 0 deletions package/cpp/api/JsiSkFont.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class JsiSkFont : public JsiSkWrappingSharedPtrHostObject<SkFont> {
return jsiWidths;
}

// TODO: deprecate
JSI_HOST_FUNCTION(getTextWidth) {
auto str = arguments[0].asString(runtime).utf8(runtime);
auto numGlyphIDs = getObject()->countText(str.c_str(), str.length(),
Expand All @@ -85,6 +86,21 @@ class JsiSkFont : public JsiSkWrappingSharedPtrHostObject<SkFont> {
return jsi::Value(std::accumulate(widthPtrs.begin(), widthPtrs.end(), 0));
}

JSI_HOST_FUNCTION(measureText) {
auto str = arguments[0].asString(runtime).utf8(runtime);
SkRect bounds;
if (count > 1) {
auto paint = JsiSkPaint::fromValue(runtime, arguments[1]);
getObject()->measureText(str.c_str(), str.length(), SkTextEncoding::kUTF8,
&bounds, paint.get());
} else {
getObject()->measureText(str.c_str(), str.length(), SkTextEncoding::kUTF8,
&bounds);
}
return jsi::Object::createFromHostObject(
runtime, std::make_shared<JsiSkRect>(getContext(), std::move(bounds)));
}

JSI_HOST_FUNCTION(getMetrics) {
SkFontMetrics fm;
getObject()->getMetrics(&fm);
Expand Down Expand Up @@ -260,6 +276,7 @@ class JsiSkFont : public JsiSkWrappingSharedPtrHostObject<SkFont> {
JSI_EXPORT_FUNC(JsiSkFont, setTypeface),
JSI_EXPORT_FUNC(JsiSkFont, getGlyphWidths),
JSI_EXPORT_FUNC(JsiSkFont, getTextWidth),
JSI_EXPORT_FUNC(JsiSkFont, measureText),
JSI_EXPORT_FUNC(JsiSkFont, dispose))

JsiSkFont(std::shared_ptr<RNSkPlatformContext> context, const SkFont &font)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 39 additions & 1 deletion package/src/renderer/__tests__/e2e/Text.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
itRunsCIAndNodeOnly,
itRunsE2eOnly,
} from "../../../__tests__/setup";
import { Fill, Group, Text, TextPath } from "../../components";
import { Fill, Group, Rect, Text, TextPath } from "../../components";
import { fonts, importSkia, surface } from "../setup";

describe("Text", () => {
Expand All @@ -30,6 +30,44 @@ describe("Text", () => {
);
expect(result).toBe(64);
});
itRunsE2eOnly("Should calculate text width correctly", async () => {
const font = fonts.DinMedium;
const result = await surface.eval(
(_Skia, ctx) => {
return ctx.font.measureText(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do"
).width;
},
{ font }
);
expect(result).toBeLessThan(1000);
});

itRunsE2eOnly("should draw the text bound measure correctly", async () => {
const font = fonts.DinMedium;
const bounds = await surface.eval(
(_Skia, ctx) => {
return ctx.font.measureText("Lorem ipsum");
},
{ font }
);
const image = await surface.draw(
<>
<Fill color="white" />
<Group>
<Rect
color="orange"
x={bounds.x + 0}
y={bounds.y + 64}
width={bounds.width}
height={bounds.height}
/>
<Text x={0} y={64} text="Lorem ipsum" font={font} />
</Group>
</>
);
checkImage(image, `snapshots/text/text-bounds-${surface.OS}.png`);
});

// We test it only on Android and iOS now because there might be no default font on Web
itRunsE2eOnly("The font property is optional", async () => {
Expand Down
4 changes: 4 additions & 0 deletions package/src/renderer/__tests__/setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export let fonts: {
NotoColorEmoji: SkFont;
NotoSansSCRegular: SkFont;
UberMoveMediumMono: SkFont;
DinMedium: SkFont;
};

beforeAll(async () => {
Expand All @@ -67,6 +68,7 @@ beforeAll(async () => {
"skia/__tests__/assets/UberMove-Medium_mono.ttf",
fontSize
);
const DinMedium = loadFont("skia/__tests__/assets/DIN-Medium.ttf", fontSize);
const oslo = loadImage("skia/__tests__/assets/oslo.jpg");
const skiaLogoPng = loadImage("skia/__tests__/assets/skia_logo.png");
const skiaLogoJpeg = loadImage("skia/__tests__/assets/skia_logo_jpeg.jpg");
Expand All @@ -77,13 +79,15 @@ beforeAll(async () => {
NotoColorEmoji,
NotoSansSCRegular,
UberMoveMediumMono,
DinMedium,
};
assets.set(mask, "mask");
assets.set(oslo, "oslo");
assets.set(RobotoMedium, "RobotoMedium");
assets.set(NotoColorEmoji, "NotoColorEmoji");
assets.set(NotoSansSCRegular, "NotoSansSCRegular");
assets.set(UberMoveMediumMono, "UberMoveMediumMono");
assets.set(DinMedium, "DinMedium");
assets.set(skiaLogoPng, "skiaLogoPng");
assets.set(skiaLogoJpeg, "skiaLogoJpeg");
});
Expand Down
Binary file not shown.
10 changes: 10 additions & 0 deletions package/src/skia/types/Font/Font.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,20 @@ export interface FontMetrics {
}

export interface SkFont extends SkJSIInstance<"Font"> {
/**
* Returns the advance width of text.
* The advance is the normal distance to move before drawing additional text.
* Returns the bounding box of text
* @param text
* @param paint
*/
measureText(text: string, paint?: SkPaint): SkRect;

/**
* Retrieves the total width of the provided text
* @param text
* @param paint
* @deprecated Use measureText or getGlyphWidths instead
*/
getTextWidth(text: string, paint?: SkPaint): number;

Expand Down
7 changes: 6 additions & 1 deletion package/src/skia/web/JsiSkFont.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import type {
SkFont,
SkPaint,
SkPoint,
SkRect,
SkTypeface,
} from "../types";

import { HostObject, ckEnum } from "./Host";
import { HostObject, NotImplementedOnRNWeb, ckEnum } from "./Host";
import { JsiSkPaint } from "./JsiSkPaint";
import { JsiSkPoint } from "./JsiSkPoint";
import { JsiSkRect } from "./JsiSkRect";
Expand All @@ -20,6 +21,10 @@ export class JsiSkFont extends HostObject<Font, "Font"> implements SkFont {
super(CanvasKit, ref, "Font");
}

measureText(_text: string, _paint?: SkPaint | undefined): SkRect {
throw new NotImplementedOnRNWeb();
}

dispose = () => {
this.ref.delete();
};
Expand Down

0 comments on commit 0ec9dad

Please sign in to comment.