| <!DOCTYPE HTML> |
| <head> |
| <meta charset="UTF-8"> |
| <style> |
| @font-face { |
| font-family: Libertine; |
| src: url('../../third_party/Libertine/LinLibertine_R.woff'); |
| } |
| </style> |
| </head> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script> |
| |
| const kAligns = [ "left", "right", "center", "start", "end" ]; |
| |
| const kTexts = [ |
| { text: "Hello", rtl: false }, |
| { text: "傳統是假的", rtl: false }, |
| { text: "フェミニズム", rtl: false }, |
| { text: "ليس", rtl: true }, |
| { text: "ليس في اسمنا", rtl: true }, |
| { text: "\u202EHello", rtl: true }, |
| { text: "\u202EHello World", rtl: true }, |
| { text: "الله", rtl: true }, // Special ligatures. |
| { text: "اين المكتبة؟", rtl: true }, // Special ligatures. |
| { text: "🏁🎶🏁", rtl: false }, // One glyph with two "characters". |
| { text: "एक आम भाषा", rtl: false }, // Special post-modifying characters. |
| { text: "a\u0301", rtl: false }, // Combining diacritical marks |
| ] |
| |
| function forEachExample(fn) { |
| for (const ex of kTexts) { |
| for (const align of kAligns) { |
| fn(ex, align); |
| } |
| } |
| } |
| |
| function isNonIncreasing(array) { |
| for (var i = 1; i < array.length; i++) { |
| if (array[i] > array[i-1]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| function isNonDecreasing(array) { |
| for (var i = 1; i < array.length; i++) { |
| if (array[i] < array[i-1]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| function getTextMetrics(ctx, text, align="left", direction="ltr") { |
| ctx.font = '25px Libertine'; |
| ctx.textAlign = align; |
| ctx.direction = direction; |
| return ctx.measureText(text); |
| } |
| |
| function testEmptyStringReturnsEmptyAdvances(ctx) { |
| const tm = getTextMetrics(ctx, ""); |
| assert_array_equals(tm.advances, [], "Empty string must return empty advances"); |
| } |
| |
| function testAllPositive(ctx) { |
| forEachExample((ex, align) => { |
| const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr", ); |
| assert_true(tm.advances.every(function isPositive(i) {return i >= 0; }), |
| "Advances must be all positive (" + ex.text + ")"); |
| }); |
| } |
| |
| function testNonIncreasingForRtl(ctx) { |
| forEachExample((ex, align) => { |
| if (ex.rtl) { |
| const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr"); |
| assert_true(isNonIncreasing(tm.advances), |
| "RTL advances must be non-increasing (" + ex.text + ")"); |
| } |
| }); |
| } |
| |
| function testNonDecreasingForLtr(ctx) { |
| forEachExample((ex, align) => { |
| if (! ex.rtl) { |
| const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr"); |
| assert_true(isNonDecreasing(tm.advances), |
| "LTR advances must be non-decreasing (" + ex.text + ")"); |
| } |
| }); |
| } |
| |
| function testLastAdvanceLessThanWith(ctx) { |
| forEachExample((ex, align) => { |
| const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr"); |
| assert_less_than(tm.advances.slice(-1)[0], tm.width, |
| "Last advance must be strictly less than total width (" + ex.text + ")"); |
| }); |
| } |
| |
| function testAdvances(ctx) { |
| testEmptyStringReturnsEmptyAdvances(ctx); |
| testAllPositive(ctx); |
| testNonIncreasingForRtl(ctx); |
| testNonDecreasingForLtr(ctx); |
| testLastAdvanceLessThanWith(ctx); |
| } |
| |
| async_test(t => { |
| var canvas = document.createElement('canvas'); |
| canvas.width = 100; |
| canvas.height = 100; |
| var ctx = canvas.getContext('2d'); |
| // Kick off loading of the font |
| ctx.font = '50px Libertine'; |
| ctx.fillText(" ", 0, 0); |
| document.fonts.ready.then(t.step_func_done(testAdvances(ctx))); |
| }, "Test TextMetrics advances."); |
| </script> |