Import Cobalt 25.master.0.1033734
diff --git a/third_party/skia/demos.skia.org/demos/textedit/index.html b/third_party/skia/demos.skia.org/demos/textedit/index.html
new file mode 100644
index 0000000..d6852c8
--- /dev/null
+++ b/third_party/skia/demos.skia.org/demos/textedit/index.html
@@ -0,0 +1,165 @@
+<!DOCTYPE html>
+<title>TextEdit demo in CanvasKit</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<script type="text/javascript" src="https://particles.skia.org/dist/canvaskit.js"></script>
+<script type="text/javascript" src="textapi_utils.js"></script>
+<script type="text/javascript" src="spiralshader.js"></script>
+
+<style>
+canvas {
+ border: 1px dashed grey;
+}
+</style>
+
+<body>
+ <h1>TextEdit in CanvasKit</h1>
+
+ <canvas id=para2 width=600 height=600 tabindex='-1'></canvas>
+</body>
+
+<script type="text/javascript" charset="utf-8">
+ let CanvasKit;
+ onload = async () => {
+ CanvasKit = await CanvasKitInit({ locateFile: (file) => 'https://particles.skia.org/dist/'+file });
+ ParagraphAPI2();
+ };
+
+ function ParagraphAPI2() {
+ const surface = CanvasKit.MakeCanvasSurface('para2');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const mouse = MakeMouse();
+ const cursor = MakeCursor(CanvasKit);
+ const canvas = surface.getCanvas();
+ const spiralEffect = MakeSpiralShaderEffect(CanvasKit);
+
+ const text0 = "In a hole in the ground there lived a hobbit. Not a nasty, dirty, " +
+ "wet hole full of worms and oozy smells. This was a hobbit-hole and " +
+ "that means good food, a warm hearth, and all the comforts of home.";
+ const LOC_X = 20,
+ LOC_Y = 20;
+
+ const bgPaint = new CanvasKit.Paint();
+ bgPaint.setColor([0.965, 0.965, 0.965, 1]);
+
+ const editor = MakeEditor(text0, {typeface:null, size:30}, cursor, 540);
+
+ editor.applyStyleToRange({size:130}, 0, 1);
+ editor.applyStyleToRange({italic:true}, 38, 38+6);
+ editor.applyStyleToRange({color:[1,0,0,1]}, 5, 5+4);
+
+ editor.setXY(LOC_X, LOC_Y);
+
+ function drawFrame(canvas) {
+ const lines = editor.getLines();
+
+ canvas.clear(CanvasKit.WHITE);
+
+ if (mouse.isActive()) {
+ const pos = mouse.getPos(-LOC_X, -LOC_Y);
+ const a = lines_pos_to_index(lines, pos[0], pos[1]);
+ const b = lines_pos_to_index(lines, pos[2], pos[3]);
+ if (a === b) {
+ editor.setIndex(a);
+ } else {
+ editor.setIndices(a, b);
+ }
+ }
+
+ canvas.drawRect(editor.bounds(), bgPaint);
+
+ {
+ // update our animated shaders
+ const rad_scale = Math.sin(Date.now() / 5000) / 2;
+ const shader0 = spiralEffect.makeShader([
+ rad_scale,
+ editor.width()/2, editor.width()/2,
+ 1,0,0,1, // color0
+ 0,0,1,1 // color1
+ ]);
+ editor.draw(canvas, [shader0]);
+ shader0.delete();
+ }
+
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+
+ function interact(e) {
+ const type = e.type;
+ if (type === 'pointerup') {
+ mouse.setUp(e.offsetX, e.offsetY);
+ } else if (type === 'pointermove') {
+ mouse.setMove(e.offsetX, e.offsetY);
+ } else if (type === 'pointerdown') {
+ mouse.setDown(e.offsetX, e.offsetY);
+ }
+ };
+
+ function keyhandler(e) {
+ switch (e.key) {
+ case 'ArrowLeft': editor.moveDX(-1); return;
+ case 'ArrowRight': editor.moveDX(1); return;
+ case 'ArrowUp':
+ e.preventDefault();
+ editor.moveDY(-1);
+ return;
+ case 'ArrowDown':
+ e.preventDefault();
+ editor.moveDY(1);
+ return;
+ case 'Backspace':
+ editor.deleteSelection(-1);
+ return;
+ case 'Delete':
+ editor.deleteSelection(1);
+ return;
+ case 'Shift':
+ return;
+ case 'Tab': // todo: figure out how to handle...
+ e.preventDefault();
+ return;
+ }
+ if (e.ctrlKey) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ switch (e.key) {
+ case 'r': editor.applyStyleToSelection({color:[1,0,0,1]}); return;
+ case 'g': editor.applyStyleToSelection({color:[0,0.6,0,1]}); return;
+ case 'u': editor.applyStyleToSelection({color:[0,0,1,1]}); return;
+ case 'k': editor.applyStyleToSelection({color:[0,0,0,1]}); return;
+
+ case 's': editor.applyStyleToSelection({shaderIndex:0}); return;
+
+ case 'i': editor.applyStyleToSelection({italic:'toggle'}); return;
+ case 'b': editor.applyStyleToSelection({bold:'toggle'}); return;
+ case 'w': editor.applyStyleToSelection({wavy:'toggle'}); return;
+
+ case ']': editor.applyStyleToSelection({size_add:1}); return;
+ case '[': editor.applyStyleToSelection({size_add:-1}); return;
+ case '}': editor.applyStyleToSelection({size_add:10}); return;
+ case '{': editor.applyStyleToSelection({size_add:-10}); return;
+ }
+ }
+ if (!e.ctrlKey && !e.metaKey) {
+ if (e.key.length == 1) { // avoid keys like "Escape" for now
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ editor.insert(e.key);
+ }
+ }
+ }
+
+ document.getElementById('para2').addEventListener('pointermove', interact);
+ document.getElementById('para2').addEventListener('pointerdown', interact);
+ document.getElementById('para2').addEventListener('pointerup', interact);
+ document.getElementById('para2').addEventListener('keydown', keyhandler);
+ return surface;
+ }
+
+</script>