Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/helpers/load-plugin-modules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export async function bundleSource(entry, outputName, external = [], plugins = [

let textUtilsModulePromise;
let idleScheduleModulePromise;
let textHaloModulePromise;

const stubObsidianPlugin = {
name: "stub-obsidian",
Expand Down Expand Up @@ -161,6 +162,13 @@ export function loadTextUtilsModule() {
return textUtilsModulePromise;
}

export function loadTextHaloModule() {
textHaloModulePromise ??= bundleSource("src/TextHalo.ts", "text-halo.cjs").then(
(outfile) => require(outfile)
);
return textHaloModulePromise;
}

export function loadTextToolbarControllerModule() {
textToolbarControllerModulePromise ??= bundleSource(
"src/powerpoint/textToolbarController.ts",
Expand Down
164 changes: 164 additions & 0 deletions tests/text-halo.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { loadTextHaloModule } from "./helpers/load-plugin-modules.mjs";

function parseSvg(svgString) {
const parser = new globalThis.DOMParser();
return parser.parseFromString(svgString, "image/svg+xml").documentElement;
}

test("table text halos inherit background color via SVG structure", async () => {
const { applyBackgroundAwareTextHalos, DEFAULT_TEXT_HALO_COLOR } = await loadTextHaloModule();

// A basic table-like SVG where a text element follows a rectangle.
const svg = parseSvg(`
<svg>
<g>
<rect fill="#ff0000" width="10" height="10" />
<text>Hello</text>
</g>
<g>
<rect fill="#0000ff" width="10" height="10" />
<g>
<text>World</text>
</g>
</g>
<g>
<text>Default</text>
</g>
</svg>
`);

applyBackgroundAwareTextHalos(svg, "table");

const texts = svg.getElementsByTagName("text");

// text "Hello" after "red" rect
assert.equal(texts[0].getAttribute("data-native-powerpoint-halo-color"), "rgb(255, 0, 0)");
assert.ok(texts[0].getAttribute("style").includes("--native-powerpoint-text-halo: rgb(255, 0, 0)"));

// text "World" in a group after a "blue" rect
assert.equal(texts[1].getAttribute("data-native-powerpoint-halo-color"), "rgb(0, 0, 255)");

// text "Default" without a preceding rect (inherits default)
assert.equal(texts[2].getAttribute("data-native-powerpoint-halo-color"), DEFAULT_TEXT_HALO_COLOR);
});

test("chart text halos inherit background color of largest rect", async () => {
const { applyBackgroundAwareTextHalos, DEFAULT_TEXT_HALO_COLOR } = await loadTextHaloModule();

const svg = parseSvg(`
<svg>
<rect fill="#00ff00" width="100" height="100" />
<rect fill="#ff0000" width="50" height="50" />
<text>Chart Title</text>
<g>
<rect fill="#0000ff" width="10" height="10" />
<text>Axis Label</text>
</g>
</svg>
`);

// #00ff00 (green) is 100x100 = 10000 area. Largest!
applyBackgroundAwareTextHalos(svg, "chart");

const texts = svg.getElementsByTagName("text");
assert.equal(texts[0].getAttribute("data-native-powerpoint-halo-color"), "rgb(0, 255, 0)");
assert.equal(texts[1].getAttribute("data-native-powerpoint-halo-color"), "rgb(0, 255, 0)");
});

test("color parsing handles opacity and fill-opacity", async () => {
const { applyBackgroundAwareTextHalos } = await loadTextHaloModule();

// Test compositeAgainstWhite
// Red rect, 50% opacity -> composed with white -> rgb(255, 128, 128)
const svg = parseSvg(`
<svg>
<rect fill="#ff0000" opacity="0.5" width="10" height="10" />
<text>Test</text>

<rect fill="#000000" fill-opacity="0.25" width="10" height="10" />
<text>Test2</text>
</svg>
`);

applyBackgroundAwareTextHalos(svg, "table");

const texts = svg.getElementsByTagName("text");

// red 0.5 composed with white:
// red = 255 * 0.5 + 255 * 0.5 = 255
// green = 0 * 0.5 + 255 * 0.5 = 128
// blue = 0 * 0.5 + 255 * 0.5 = 128
// rgb(255, 128, 128)
assert.equal(texts[0].getAttribute("data-native-powerpoint-halo-color"), "rgb(255, 128, 128)");

// black 0.25 composed with white:
// r, g, b = 0 * 0.25 + 255 * 0.75 = 191
// rgb(191, 191, 191)
assert.equal(texts[1].getAttribute("data-native-powerpoint-halo-color"), "rgb(191, 191, 191)");
});

test("color parsing handles transparent, none, and absent colors", async () => {
const { applyBackgroundAwareTextHalos, DEFAULT_TEXT_HALO_COLOR } = await loadTextHaloModule();

const svg = parseSvg(`
<svg>
<!-- Inherit from previous test/default -->
<rect fill="none" width="10" height="10" />
<text>A</text>

<rect fill="transparent" width="10" height="10" />
<text>B</text>

<rect width="10" height="10" />
<text>C</text>
</svg>
`);

applyBackgroundAwareTextHalos(svg, "table");

const texts = svg.getElementsByTagName("text");
assert.equal(texts[0].getAttribute("data-native-powerpoint-halo-color"), DEFAULT_TEXT_HALO_COLOR);
assert.equal(texts[1].getAttribute("data-native-powerpoint-halo-color"), DEFAULT_TEXT_HALO_COLOR);
assert.equal(texts[2].getAttribute("data-native-powerpoint-halo-color"), DEFAULT_TEXT_HALO_COLOR);
});

test("color parsing handles named colors and functions", async () => {
const { applyBackgroundAwareTextHalos } = await loadTextHaloModule();

const svg = parseSvg(`
<svg>
<rect fill="white" width="10" height="10" />
<text>White</text>

<rect fill="black" width="10" height="10" />
<text>Black</text>

<rect fill="rgb(0, 100, 200)" width="10" height="10" />
<text>RGB</text>

<rect fill="rgba(0, 100, 200, 0.5)" width="10" height="10" />
<text>RGBA</text>
</svg>
`);

applyBackgroundAwareTextHalos(svg, "table");

const texts = svg.getElementsByTagName("text");

// white
assert.equal(texts[0].getAttribute("data-native-powerpoint-halo-color"), "rgb(255, 255, 255)");

// black
assert.equal(texts[1].getAttribute("data-native-powerpoint-halo-color"), "rgb(0, 0, 0)");

// rgb(0, 100, 200)
assert.equal(texts[2].getAttribute("data-native-powerpoint-halo-color"), "rgb(0, 100, 200)");

// rgba(0, 100, 200, 0.5) against white
// red: 0*0.5 + 255*0.5 = 128
// green: 100*0.5 + 255*0.5 = 178
// blue: 200*0.5 + 255*0.5 = 228
assert.equal(texts[3].getAttribute("data-native-powerpoint-halo-color"), "rgb(128, 178, 228)");
});
22 changes: 1 addition & 21 deletions vendor/docx-editor-runtime/provenance.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,18 @@
"react": "1.9.0",
"i18n": "1.9.0"
},
"fileCount": 375,
"fileCount": 355,
"fileHashes": {
"core/dist/chunk-23ZV5H5O.mjs": "78817a45fdbda4ffa918a20f40d1de9c1ee2d5787708a29dc770184f14cb61ef",
"core/dist/chunk-2KHWHVTA.js": "cffd7e0e5508a05de0120be545e5b41a61b8fbbab154c09af5533a7b60aeda3f",
"core/dist/chunk-3ANZ3252.mjs": "313983963f640e5395e4039f18b172b82dc7c4d14d3437d8795991ad078a8ecc",
"core/dist/chunk-3COGZG7O.mjs": "24d2978fa2d6df895d0699d2ebe595482006481eb541396f793d745c19d3b647",
"core/dist/chunk-3HV4UKPW.mjs": "3113cbe81b65c6b1d4a654b576bc7ca072e063cc30fc31f2d5794b30c65f3a53",
"core/dist/chunk-3R7QHNI5.js": "b6e37b7e26d46161777ace1810168bb359e4e5418d6c84d69c77d7445c278e6e",
"core/dist/chunk-3SXJPJSV.mjs": "daf6b7f189549a897cb768b2c3992bcd5d89466fd6109e2b09d42b916fa00927",
"core/dist/chunk-47AG77IC.js": "4ae4f433c591db8ffae59295f29346049bfc12740e03908572c3212ac84bc8b8",
"core/dist/chunk-4DCTKHS5.js": "e18434c5c5462ad42f51899b236f022642fae24e22163ef835149bc52f83c2b8",
"core/dist/chunk-4IQQYC2J.mjs": "68f4dfcf91cd648ca0a9ed6d5c0fc3b2f9a75891bb50eb0b626029ca55b26e1e",
"core/dist/chunk-4VLKSJRK.mjs": "049eff8ce535f064867ecd0fbadc87145ddf8f1b188526425cb7eb9ebe40e670",
"core/dist/chunk-52DHZAZU.js": "d2a03738adb33366eaec23748edf6b8dc52ce8672db746aa344083c3c44089cf",
"core/dist/chunk-53VKL6CG.js": "8e8cc72e61ff6f6c0c945a976756d112732c499cd64fc5b207bb213fc84a1e40",
"core/dist/chunk-5HYP7TWL.js": "b47dc3a706c460acd7222f204e8e0fcba68760360a9233ce77e5083565ae6d98",
"core/dist/chunk-67LVRQIR.mjs": "f3d36e50a7046c5c3163e9a50de48617c904d7e2d5c5aafd41e8070ede7fbfca",
Expand All @@ -42,15 +40,12 @@
"core/dist/chunk-ASDTR7GJ.js": "3635ddaee10984350b8a9e9331f1be70266dcda6fe4f1278178cb9052654aec6",
"core/dist/chunk-B3SVS2AF.js": "e98f29c097843aa3aa4e48216c758373b81e85bbb96b90622f5819f7d9351df9",
"core/dist/chunk-BFQ2Z4OL.mjs": "0ebb5a861d4770e1f7a3d0c62afaef8894b7ca91bbed2cdaec14a43e40ce9333",
"core/dist/chunk-BGQMKNCR.mjs": "c0bf651fe6d5a02f735e649556c72a712b62a91d459349317aa7f8a43caf6c86",
"core/dist/chunk-BJSG6TEG.js": "833ea426757b778207b41ff3fff6d72a7aa2d6c648d2463023fa4354465f0a31",
"core/dist/chunk-BPZG7KT3.js": "185a16ad6fc31525dbcc22cc07a47700b04438a2621f1f25c83b9fe9a2856646",
"core/dist/chunk-BTBPQSIY.js": "6e5c8a9e1fe21d92c994e637549140aee2767931a94c333f313102538345d447",
"core/dist/chunk-BX5JNYNI.mjs": "e6470bc9bcdb88f59541f9de4375b0767655088f130deb471240761930b6962f",
"core/dist/chunk-C7YXIU2K.js": "fd60d68a68e7ba6975545ba4b4483da17edbb43e0c7360165815b8d2e7f7d04d",
"core/dist/chunk-CKKO4JWE.mjs": "c4c0927cfd794e891cce071baf910beb29a1eb549dd292f4201e61706a241b2c",
"core/dist/chunk-CLNQHDJD.mjs": "4c3e869156f691f3a9d8a52e77583569d076a3f7f60163ec9d5f2b66b86ca811",
"core/dist/chunk-CMDN3WCI.mjs": "e3811b8d97f209df8a44245beff6d76f5288487b5d3597ea1517094975790674",
"core/dist/chunk-CVCPLNFN.js": "56e6904670f7cbcc4318b4904a0dee15db626ea54c5c033ec2aed92a25260246",
"core/dist/chunk-CWZKRBRE.mjs": "73eae3e600d9ff47cf0a88a40fbbb6236ecd23f8e462c403bd21e846379820db",
"core/dist/chunk-DROCYKAR.js": "f1a10a7f72e9ac492b0ee245d38412e602221af3b69f78ec2307aaa33e43a44f",
Expand All @@ -62,21 +57,16 @@
"core/dist/chunk-FCJWLEKT.mjs": "8c2a3afc2c0c5af34b76b97fee6d0aad33b73b53ac98389ee90653a11d3a4054",
"core/dist/chunk-FDAGHNH2.js": "5c3937362f676cb572477be8d5d1729c91b78cd41c1a20c2b11e4e8de349e5c7",
"core/dist/chunk-FECFXS6U.mjs": "ad0a9e5d45c17f7741a563d5e776a0cc5d4436db3526b1e2660c00c78651e56c",
"core/dist/chunk-FGKHIVWI.mjs": "8915d7c288dc7123ebc9cc214b898f65af0d0928dd0d782768b20e5f6e8d7e66",
"core/dist/chunk-FWWBQ7WS.js": "a2cc9c7567ebb1e480206565a8a777e37806f5f3e17a262c04faebc1c67b3373",
"core/dist/chunk-FYH2KHXU.js": "01851bb3643f3ecf1defc325ef060290db5008d2f37a4d413a333ec01373a9cb",
"core/dist/chunk-GFIODXSG.js": "bc703e60dbe076a9d956f9f78cf3c2a832f52a5f45261eab178354496c06e39e",
"core/dist/chunk-GGPKPXON.js": "caa10b214052e1df2ea873400bad22ea473dd4787aa2fce4becfff1f4e7eb67e",
"core/dist/chunk-GLPOVLZD.mjs": "9bda5672a7ba83c21b8b810f0bb20ef64a79acfa6ac8f3cae1edf295ce6bfa91",
"core/dist/chunk-GMDBISS3.js": "c5b6bfc6095b5a586e3b8260281a7445859bde74f35fcc21859b53575e949081",
"core/dist/chunk-GWLM254S.js": "39fd6cebed71b202def48aff960e3ef94f9f8358dabfee5cafd3956438e5321a",
"core/dist/chunk-GYOKKCOQ.mjs": "13151635c0d2b2356113beca0346b7d953df7af9824bd6d4ce038c94d6cacc52",
"core/dist/chunk-H57LNDBH.js": "cae7ee69f4b81f24a9dda8421b6b92076c4035914a412ce80ef14407c247e010",
"core/dist/chunk-HBIH5VAA.js": "db07ae44e15fcd14c5204531c1f0a662f8883b20ff7c9c909054d0cc7b04c089",
"core/dist/chunk-HBIXLNXV.js": "9d62a67b6067d3144d1427aba7f1884c3d60f54815d201baa8e4a236205c1799",
"core/dist/chunk-HJCGTPSA.js": "ba0d1001659e24fbd20d4f690ae3d1d34ed0dc03e07d92997f97a1217c92f554",
"core/dist/chunk-HJE46MS3.mjs": "4b7402ea957f438a6c0d8fdaf2d3f7900586d7f4238adabe81f4ddc138831af3",
"core/dist/chunk-HJIKLTL4.mjs": "b5ef2cff5c2fd151b6f176b2ca3f471344cf5ffa5e1c0e208c62e2c75f06ff38",
"core/dist/chunk-HL7JS6FV.mjs": "99dc4f6282098b4d0f3403e3d7b297681e1ec5e174c62da9eff033e7e285c250",
"core/dist/chunk-HPJBZL37.mjs": "89ed2976cffa899505a33187ffda9402ed27b54468f389314caf778039b0388f",
"core/dist/chunk-HXZTROSY.mjs": "48f94f22a893f3991223e860d0c55f919e8ae7008072955ab1d525f1921f9186",
Expand All @@ -90,23 +80,19 @@
"core/dist/chunk-JHIEVXPS.js": "5d52bacc7358333bc004874df35f54f048c6c6044238fa0dd18477c3ffb9d55a",
"core/dist/chunk-JR557W27.mjs": "3ade205f0bac96a38ed4ca61f523c5b9a827c69746d45d5a10d3b1ed0d2c89d2",
"core/dist/chunk-JY5EFI4D.js": "7ac448dbf32c3c241a71b7dfcbda130e6a79b7dde04547ba7fe418303f94ceb4",
"core/dist/chunk-KEQNZYXE.js": "57e49f0f09b0a662822a1229b1b10422129151b257d71e953f9e9b80aa754087",
"core/dist/chunk-KESNGXGO.js": "aa31285d1db53e7c46065a0ff51161b4cdd3015bba71ab2ce1cebf6edb6cfcd7",
"core/dist/chunk-KGRBI4EM.mjs": "385ed109a48cdec8db60aff406e5276c227a28705237acd7b0267fd0fd7d736f",
"core/dist/chunk-KNY7SXPJ.mjs": "812f64c9e7ca83aa458b77014acf38782df01fbcf3ed2c74afb968cf0f8d012f",
"core/dist/chunk-KQTB5Y7P.mjs": "9f70c796431631e16b1ccd6d106985d109592f57de3197530b3db4d876bcfe7e",
"core/dist/chunk-LB2OEMYL.js": "8b7700398d587e6d53eb12cdf230c1460c6fa99be04308029bd076dae74bb28e",
"core/dist/chunk-LUPZQCMG.mjs": "d6dab833c0e55eb505a737cdd9282cb2aa788848c23bf2672a54f96e2184727e",
"core/dist/chunk-LVUL7O27.js": "377ea97861d530fcc5e90a322d3ae7aef7eb8c56bf7cba21d9ff09ab684904f0",
"core/dist/chunk-M5T2IDXM.js": "6d4cb74273893bc79b625f4fe92225341847af4c26dcea91f4f144612fe5eb96",
"core/dist/chunk-MJ5FQX7Q.js": "bf5cfd61359e7956c51139dbbf1b930fed53d8fc117c4fbdcc5b71c9bb29f5b2",
"core/dist/chunk-MKSI2DWW.js": "74fcc87fd3de3f91f56b232df6616c684a9e58709c6509b5871f2803dd2b6202",
"core/dist/chunk-MM3OP6FN.js": "7a758a92884395329435b597287807017a536838b1463b8a26ed562a1b13f9a3",
"core/dist/chunk-MVZOTKNL.mjs": "328c348c18c4bb1a9afe1d0ff32b6336e86a58e8b18223d47d6956daa96ad96c",
"core/dist/chunk-MXPJ76MM.js": "0e12eb90acaba9b5ce1a00c70b31ca83c8da2c10721ba1ec799891f80ce23cc1",
"core/dist/chunk-MYWHXY7S.mjs": "c775e8eaf0906cc9ed31bc026290cee043381820b36d11df34b5dce1751353cc",
"core/dist/chunk-MZ7LW5CH.js": "1d830bfbe09bacb7121db31f518cd552be830e479ee6dd7002cd55ef47c80fab",
"core/dist/chunk-NF4RWYIL.js": "4fdc64e1db93a118413d113b1e7e55746f99a927701bf543e2415bf2d8ee5863",
"core/dist/chunk-NRWQ65NX.js": "879c67688f83d188f492c1c8b14f58712ec7d15712857903286ae95d89f25938",
"core/dist/chunk-NXLJVVVE.js": "9eed4cb93e15c167ca4ff37fd21c519f640f482d4970c1f1328fdff1462da72f",
"core/dist/chunk-O2XFH626.js": "d4eb94d09e19bc698ae5b037e5b4fb0b8d810f91f71e34c7bd03315015fd97d4",
Expand All @@ -115,11 +101,8 @@
"core/dist/chunk-OATN3RKU.mjs": "68c11fe65a60820f435b1b1a5ffac5afa56181522e5587d044cf2f374904d682",
"core/dist/chunk-OBMN4VSM.mjs": "60a6c2e9824d0599c6bedb959f5c3fe2791f5bc3a18f32f8b252b8b6e7b1b6cf",
"core/dist/chunk-OO6FBGRK.mjs": "fa10941f4d64b6f56402f19c3586878200737b00ac060fcb036c469fee826119",
"core/dist/chunk-OYA45VXM.js": "f201fca8c147abf860ba99be060f013cae2c36c5143bd3b3a2ca68f78e37d57e",
"core/dist/chunk-OZMNIX6U.mjs": "0400fb28e069fe5f099c34549dffb3cd2d4f020850d9f13a7cbabad86c7e81a2",
"core/dist/chunk-PGWY6UFK.js": "5bba809d47fee9442a6d017d978efb3841229e6d65c8349729910d96a9f2fb22",
"core/dist/chunk-PN7VQNTW.mjs": "d8283ad624cb164618d4516183dd3a8794f39fcbe903f89bd780c7eef71147c0",
"core/dist/chunk-PNXUYXSM.mjs": "d7d0b32c86fd7e04379c0471b96311fbc4100194d2dce65ad6eb97c88aed16fe",
"core/dist/chunk-PRRM64JO.mjs": "bfcd73fe80b082df0d691c98a48e89f2f0883fb177a72ad2385af2875af50d81",
"core/dist/chunk-PSZHULFD.mjs": "216dd3eaeb165255f7dfc3ba6984a98d327a912933119fa329474e9473d9dfd9",
"core/dist/chunk-Q3O72CRO.js": "76cdbb5ed9c526132c648054764714e4ab2d3db5bedc7bcacb676d5f1f196240",
Expand All @@ -129,12 +112,10 @@
"core/dist/chunk-QKNLMXKB.mjs": "efa8a54a29fa04a4658a0d2030bb21463b9351ddd5124018f075e2ca41cd9178",
"core/dist/chunk-QPFJJPIC.mjs": "cf390832b62f3c846649ee56f9132ab427b9c88fa8429682a92387ad4966b70e",
"core/dist/chunk-R5AWBUSP.js": "2a300034c97574cff7ad53627169460c4fd4735dae2a6f64af0827f006cad6bc",
"core/dist/chunk-RFBNBWRE.js": "369f83d540aab577b0119db07cff1684444272ea0387c4be7c165a7353bda66f",
"core/dist/chunk-RNAU5NCU.mjs": "38cd5bda7f042495dfafc3c37ec82dbbdb72679e2083513ec2ca412ee2c74a82",
"core/dist/chunk-RNOXNNSD.mjs": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"core/dist/chunk-RPIQG46O.mjs": "602cd4f7ef88d8e0b7754fecc4ef3f122b43bc824e6f725b1f57546d01a33ba6",
"core/dist/chunk-RWAOWRVF.js": "d12ce57ed5210753cd26b1839f81570452ace189eabe3d6fddeced31ed000507",
"core/dist/chunk-SOBIB675.js": "f396d1e183567b74e0665228695895381d6e6815dc948e6b929128e31802e32e",
"core/dist/chunk-SUXJNWM4.mjs": "eb2a4a6ebb957be056c964442b0a4b9ef16aa5c4d3370c72457e61699256f96e",
"core/dist/chunk-TCNH27CF.mjs": "89d0ac88fab3a9cf4f7ff64fa921a09d333f8199bf4d821ee71e1f59cd6fabb2",
"core/dist/chunk-TGN6VVCD.js": "8222619b8680c27b07ffd119fdcd2a0e43dafdcb64bd93e639b9f9d6ebfcc315",
Expand All @@ -158,7 +139,6 @@
"core/dist/chunk-XXU7YQVV.js": "52f5d07fa17ad8eee2f48081b5aeab483dbcec32693e94c8442f029272b69bae",
"core/dist/chunk-Z4UH6E77.mjs": "bebded4cd988320acc9fc8e08d4849cc53d104c24835eac6aa221f64bc5edb47",
"core/dist/chunk-ZJNHN633.mjs": "0e5a0b11f7eef76e8f6db735e61ebe398b5ad4bac5ad72bc1b755bf8c606c91e",
"core/dist/chunk-ZL6V6FQI.mjs": "164dbc9ffbad1d392c44e7b07d4f6ffa03752f67259d1b1a86a888f315682fb7",
"core/dist/contentControls/index.js": "c52563bdf48770953ab18a8cb2f50a5b4c293112378e9006cf3e6b74cdd7a191",
"core/dist/contentControls/index.mjs": "88fb51bedeb06a011a928276e242e4a54a2cdb2151ff703dce94857fab2f9f45",
"core/dist/core-plugins.js": "9f104b00530d9559496924a0eefdc25765216cc05b20c5f1edbcc3b0aef19a37",
Expand Down
Loading