Skip to content

Commit

Permalink
Report correct utf-16 indices in Paragraph.getLineMetrics and Paragra…
Browse files Browse the repository at this point in the history
…ph.update* (closes #47), removed Paragraph.updateText
  • Loading branch information
tonsky committed Nov 28, 2020
1 parent 57ec197 commit b703f6e
Show file tree
Hide file tree
Showing 10 changed files with 339 additions and 126 deletions.
14 changes: 12 additions & 2 deletions examples/clojure/src/lwjgl/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[nrepl.server :as nrepl])
(:import
[org.jetbrains.skija BackendRenderTarget Canvas ColorSpace DirectContext FramebufferFormat Paint Rect Surface SurfaceColorFormat SurfaceOrigin]
[org.lwjgl.glfw GLFW]
[org.lwjgl.glfw Callbacks GLFW GLFWErrorCallback]
[org.lwjgl.opengl GL GL11]
[org.lwjgl.system MemoryUtil]))

Expand All @@ -21,6 +21,7 @@
(.drawRect canvas (Rect/makeXYWH -50 -50 100 100) paint)))

(defn -main [& args]
(.set (GLFWErrorCallback/createPrint System/err))
(GLFW/glfwInit)
(GLFW/glfwWindowHint GLFW/GLFW_VISIBLE GLFW/GLFW_FALSE)
(GLFW/glfwWindowHint GLFW/GLFW_RESIZABLE GLFW/GLFW_TRUE)
Expand Down Expand Up @@ -52,7 +53,16 @@
(.flush context)
(GLFW/glfwSwapBuffers window)
(GLFW/glfwPollEvents)
(recur))))))
(recur)))

(Callbacks/glfwFreeCallbacks window)
(GLFW/glfwHideWindow window)
(GLFW/glfwDestroyWindow window)
(GLFW/glfwPollEvents)
(GLFW/glfwTerminate)
(.free (GLFW/glfwSetErrorCallback nil))
(shutdown-agents)
)))

(comment
(reset! lwjgl.main/*rect-color (lwjgl.main/color 0xFF33CC33)))
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ private void loop() {
scenes.put("Image Filters", new ImageFiltersScene());
scenes.put("Mask Filters", new MaskFiltersScene());
scenes.put("Paragraph", new ParagraphScene());
scenes.put("Paragraph Metrics",new ParagraphMetricsScene());
scenes.put("Paragraph Style", new ParagraphStyleScene());
scenes.put("Path Effects", new PathEffectsScene());
scenes.put("Paths", new PathsScene());
Expand All @@ -336,7 +337,7 @@ private void loop() {
scenes.put("Text Style", new TextStyleScene());
scenes.put("Wall of Text", new WallOfTextScene());
scenes.put("Watches", new WatchesScene());
currentScene = "Font";
currentScene = "Paragraph Style";
var interRegular = Typeface.makeFromFile("fonts/InterHinted-Regular.ttf");
interRegular13tnum = new Font(interRegular, 13); // , new FontFeature("tnum"));
t0 = System.nanoTime();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package org.jetbrains.skija.examples.lwjgl;

import org.jetbrains.skija.*;
import org.jetbrains.skija.shaper.*;
import org.jetbrains.skija.paragraph.*;

public class ParagraphMetricsScene implements Scene {
public FontCollection fc = new FontCollection();
public long lastUpdate = 0;

public Font inter13;
public Paint detailsFill;
public Paint boundariesStroke;

public ParagraphMetricsScene() {
fc.setDefaultFontManager(FontMgr.getDefault());

TypefaceFontProvider fm = new TypefaceFontProvider();
Typeface jbMono = Typeface.makeFromFile("fonts/JetBrainsMono-Regular.ttf");
fm.registerTypeface(jbMono);
Typeface inter = Typeface.makeFromFile("fonts/InterHinted-Regular.ttf");
fm.registerTypeface(inter, "Interface");
fc.setAssetFontManager(fm);

inter13 = new Font(inter, 13);
detailsFill = new Paint().setColor(0xFFCC3333);
boundariesStroke = new Paint().setColor(0xFFFAA6B2).setMode(PaintMode.STROKE).setStrokeWidth(1f);
}

@Override
public void draw(Canvas canvas, int width, int height, float dpi, int xpos, int ypos) {
canvas.translate(30, 30);
drawSelection(canvas, xpos - 30f, ypos - 30f);
canvas.translate(0, 30);
drawIndices(canvas);
}

public void drawSelection(Canvas canvas, float dx, float dy) {
try (TextStyle defaultTs = new TextStyle().setFontSize(24).setColor(0xFF000000);
TextStyle largeTs = new TextStyle().setFontSize(36).setColor(0xFF000000);
TextStyle smallTs = new TextStyle().setFontSize(12).setColor(0xFF000000);
TextStyle ligaTs = new TextStyle().setFontSize(24).setColor(0xFF000000).setFontFamilies(new String[] { "Interface" });
ParagraphStyle ps = new ParagraphStyle();
ParagraphBuilder pb = new ParagraphBuilder(ps, fc);
ParagraphStyle ps2 = new ParagraphStyle().setAlignment(Alignment.RIGHT);)
{
// default style
pb.pushStyle(defaultTs);

pb.addText("123 567 ");
pb.pushStyle(ligaTs);
pb.addText("<-> ");
pb.popStyle();
pb.addText("👩 👩👩 🧑🏿 🧑🏿🧑🏿 👮‍♀️ 👮‍♀️👮‍♀️ 👩‍👩‍👧‍👧 👩‍👩‍👧‍👧👩‍👩‍👧‍👧\n");

pb.addText("The following ");
pb.pushStyle(largeTs);
pb.addText("sentence");
pb.popStyle();
pb.addText(" is true\n");

pb.pushStyle(largeTs);
pb.addText("The previous ");
pb.popStyle();
pb.addText("sentence");
pb.pushStyle(largeTs);
pb.addText(" is false\n");
pb.popStyle();

pb.setParagraphStyle(ps2);
pb.pushStyle(defaultTs);
pb.addText("— Vicious circularity, \n");
pb.pushStyle(smallTs);
pb.addText(" or infinite regress");
pb.popStyle();

try (Paragraph p = pb.build();) {
p.layout(600f);

// getLineMetrics
for (LineMetrics lm: p.getLineMetrics()) {
canvas.drawRect(Rect.makeXYWH((float) lm.getLeft(),
(float) (lm.getBaseline() - lm.getAscent()),
(float) lm.getWidth(),
(float) (lm.getAscent() + lm.getDescent())), boundariesStroke);
canvas.drawLine((float) lm.getLeft(), (float) lm.getBaseline(), (float) (lm.getLeft() + lm.getWidth()), (float) lm.getBaseline(), boundariesStroke);
}

// getGlyphPositionAtCoordinate
int glyphx = p.getGlyphPositionAtCoordinate(dx, dy).getPosition();

try (var blue = new Paint().setColor(0x80b3d7ff);
var orange = new Paint().setColor(0x80ffd7b3);) {

// getRectsForRange
for (TextBox box: p.getRectsForRange(0, glyphx, RectHeightMode.TIGHT, RectWidthMode.TIGHT)) {
canvas.drawRect(box.getRect(), blue);
}

// getWordBoundary
IRange word = p.getWordBoundary(glyphx);
for (TextBox box: p.getRectsForRange(word.getStart(), word.getEnd(), RectHeightMode.TIGHT, RectWidthMode.TIGHT)) {
canvas.drawRect(box.getRect(), orange);
}
}
p.paint(canvas, 0, 0);
canvas.drawString("idx: " + glyphx, 630, 20, inter13, detailsFill);
canvas.translate(0, p.getHeight());
}
}
}

public void paintParagraph(Canvas canvas, Paragraph paragraph) {
paragraph.layout(600f);
paragraph.paint(canvas, 0, 0);
for (LineMetrics lm: paragraph.getLineMetrics()) {
canvas.drawRect(Rect.makeXYWH((float) lm.getLeft(),
(float) (lm.getBaseline() - lm.getAscent()),
(float) lm.getWidth(),
(float) (lm.getAscent() + lm.getDescent())), boundariesStroke);
canvas.drawLine((float) lm.getLeft(), (float) lm.getBaseline(), (float) (lm.getLeft() + lm.getWidth()), (float) lm.getBaseline(), boundariesStroke);

canvas.drawString(
String.format("start=%d, end w/o space=%d, end=%d, end w/ newline=%d",
lm.getStartIndex(),
lm.getEndExcludingWhitespaces(),
lm.getEndIndex(),
lm.getEndIncludingNewline()),
150, (float) lm.getBaseline(), inter13, detailsFill);
}
canvas.translate(0, paragraph.getHeight());
}

public void drawIndices(Canvas canvas) {
try (TextStyle defaultTs = new TextStyle().setFontSize(16).setColor(0xFF000000).setFontFamilies(new String[] { "Interface" }).setHeight(1.5f);
ParagraphStyle ps = new ParagraphStyle();
ParagraphBuilder pb = new ParagraphBuilder(ps, fc);)
{
pb.pushStyle(defaultTs);

String text = "12345\n"
+ "абвгд\n"
+ "space \n"
+ "\\r\\n\r\n"
+ "\\n\\n\n\n"
+ "👩👩👩👩👩\n"
+ "<-><->\n"
+ "🧑🏿🧑🏿🧑🏿🧑🏿🧑🏿\n"
+ "👮‍♀️👮‍♀️👮‍♀️👮‍♀️👮‍♀️\n"
+ "👩‍👩‍👧‍👧👩‍👩‍👧‍👧👩‍👩‍👧‍👧👩‍👩‍👧‍👧👩‍👩‍👧‍👧";

pb.addText(text);
try (Paragraph paragraph = pb.build();) {
paintParagraph(canvas, paragraph);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ public void draw(Canvas canvas, int width, int height, float dpi, int xpos, int
}

canvas.translate(30, 30);
drawSonnet(canvas);
canvas.translate(0, 500);
drawMetrics(canvas, xpos - 30f, ypos - 530f);
}

public void drawSonnet(Canvas canvas) {
canvas.save();

try (TextStyle defaultTs = new TextStyle().setColor(0xFF000000);
ParagraphStyle ps = new ParagraphStyle();
Expand Down Expand Up @@ -173,85 +166,5 @@ public void drawSonnet(Canvas canvas) {
}
}
}

canvas.restore();
}

public void drawMetrics(Canvas canvas, float dx, float dy) {
try (TextStyle defaultTs = new TextStyle().setFontSize(24).setColor(0xFF000000);
TextStyle largeTs = new TextStyle().setFontSize(36).setColor(0xFF000000);
TextStyle smallTs = new TextStyle().setFontSize(12).setColor(0xFF000000);
ParagraphStyle ps = new ParagraphStyle();
ParagraphBuilder pb = new ParagraphBuilder(ps, fc);
ParagraphStyle ps2 = new ParagraphStyle().setAlignment(Alignment.RIGHT);
Paint boundaries = new Paint().setColor(0xFFFAA6B2).setMode(PaintMode.STROKE).setStrokeWidth(1f);)
{
// default style
pb.pushStyle(defaultTs);

pb.addText("The following ");
pb.pushStyle(largeTs);
pb.addText("sentence");
pb.popStyle();
pb.addText(" is true\n");

pb.pushStyle(largeTs);
pb.addText("The previous ");
pb.popStyle();
pb.addText("sentence");
pb.pushStyle(largeTs);
pb.addText(" is false\n");
pb.popStyle();

pb.setParagraphStyle(ps2);
pb.pushStyle(defaultTs);
pb.addText("— Vicious circularity, \n");
pb.pushStyle(smallTs);
pb.addText(" or infinite regress");
pb.popStyle();

try (Paragraph p = pb.build();) {
p.layout(600f);

// getLineMetrics
for (LineMetrics lm: p.getLineMetrics()) {
canvas.drawRect(Rect.makeXYWH((float) lm.getLeft(),
(float) (lm.getBaseline() - lm.getAscent()),
(float) lm.getWidth(),
(float) (lm.getAscent() + lm.getDescent())), boundaries);
canvas.drawLine((float) lm.getLeft(), (float) lm.getBaseline(), (float) (lm.getLeft() + lm.getWidth()), (float) lm.getBaseline(), boundaries);
}

// getGlyphPositionAtCoordinate
int glyphx = p.getGlyphPositionAtCoordinate(dx, dy).getPosition();

try (var blue = new Paint().setColor(0x80b3d7ff);
var orange = new Paint().setColor(0x80ffd7b3);) {

// getRectsForRange
for (TextBox box: p.getRectsForRange(0, glyphx, RectHeightMode.TIGHT, RectWidthMode.TIGHT)) {
canvas.drawRect(box.getRect(), blue);
}

// getWordBoundary
IRange word = p.getWordBoundary(glyphx);
for (TextBox box: p.getRectsForRange(word.getStart(), word.getEnd(), RectHeightMode.TIGHT, RectWidthMode.TIGHT)) {
canvas.drawRect(box.getRect(), orange);
}
}
p.paint(canvas, 0, 0);
canvas.translate(0, p.getHeight());

try (var typeface = Typeface.makeDefault();
var font = new Font(typeface, 16);
var shaper = Shaper.make();
var blob = shaper.shape("idx: " + glyphx, font);
var paint = new Paint().setColor(0xFFcc3333);)
{
canvas.drawTextBlob(blob, 0, 0, font, paint);
canvas.translate(0, blob.getBounds().getHeight());
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package org.jetbrains.skija.examples.lwjgl;

import java.util.Arrays;
import org.jetbrains.skija.Canvas;
import org.jetbrains.skija.FontMgr;
import org.jetbrains.skija.FontStyle;
import org.jetbrains.skija.Typeface;

import org.jetbrains.skija.*;
import org.jetbrains.skija.paragraph.*;

public class ParagraphStyleScene implements Scene {
Expand All @@ -32,6 +28,12 @@ public void drawLine(Canvas canvas, String text, ParagraphStyle ps, float width)
@Override
public void draw(Canvas canvas, int width, int height, float dpi, int xpos, int ypos) {
canvas.translate(30, 30);
drawStyles(canvas, width);
canvas.translate(0, 30);
drawUpdates(canvas);
}

public void drawStyles(Canvas canvas, int width) {
try (TextStyle ts = new TextStyle().setColor(0xFF000000);) {

try (ParagraphStyle ps = new ParagraphStyle().setTextStyle(ts)) {
Expand Down Expand Up @@ -109,4 +111,36 @@ public void draw(Canvas canvas, int width, int height, float dpi, int xpos, int
// Yet him for this my love no whit disdaineth;
// Suns of the world may stain when heaven’s sun staineth.
}

public void drawUpdates(Canvas canvas) {
try (TextStyle ts = new TextStyle().setColor(0xFF000000).setFontSize(16);
ParagraphStyle ps = new ParagraphStyle().setTextStyle(ts);
ParagraphBuilder pb = new ParagraphBuilder(ps, fc);
Paint red = new Paint().setColor(0xFFCC3333);
Paint redBg = new Paint().setColor(0xFFFFEEEE);)
{
pb.addText("тут размер, тут цвет, а тут фон, вот");
try (Paragraph p = pb.build();) {
p.layout(Float.POSITIVE_INFINITY);
p.paint(canvas, 0, 0);
canvas.translate(0, p.getHeight());

p.updateFontSize(4, 10, 24);
p.layout(Float.POSITIVE_INFINITY);
p.paint(canvas, 0, 0);
canvas.translate(0, p.getHeight());

p.updateForegroundPaint(16, 20, red);
p.layout(Float.POSITIVE_INFINITY);
p.paint(canvas, 0, 0);
canvas.translate(0, p.getHeight());

p.updateBackgroundPaint(28, 31, redBg);
p.layout(Float.POSITIVE_INFINITY);
p.paint(canvas, 0, 0);
canvas.translate(0, p.getHeight());
}
}

}
}
Loading

0 comments on commit b703f6e

Please sign in to comment.