mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-14 04:02:22 +02:00
72 lines
3.1 KiB
Python
72 lines
3.1 KiB
Python
import json
|
|
import subprocess
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MODULE = (ROOT / "static/js/editor/layer-clipping.js").as_uri()
|
|
|
|
|
|
def run_node(body: str):
|
|
script = textwrap.dedent(
|
|
f"""
|
|
import {{canToggleLayerClipping,clippingBaseForLayer,drawLayerStack,normalizeLayerClipping}} from {json.dumps(MODULE)};
|
|
{body}
|
|
"""
|
|
)
|
|
result = subprocess.run(
|
|
["node", "--input-type=module", "-e", script], cwd=ROOT,
|
|
text=True, capture_output=True, check=True,
|
|
)
|
|
return json.loads(result.stdout)
|
|
|
|
|
|
def test_clipping_topology_stays_inside_group_scope_and_repairs_invalid_flags():
|
|
result = run_node(
|
|
"""
|
|
const layers=['root','group-base','group-clip','after'].map(id=>({id,clipped:id!=='root'}));
|
|
const state={layers,layerGroups:[{id:'g',layerIds:['group-base','group-clip']}]};
|
|
const before={
|
|
groupBase:clippingBaseForLayer(state,'group-clip')?.id || null,
|
|
afterBase:clippingBaseForLayer(state,'after')?.id || null,
|
|
canRoot:canToggleLayerClipping(state,'root'),
|
|
};
|
|
const cleared=normalizeLayerClipping(state);
|
|
console.log(JSON.stringify({before,cleared,clipped:layers.map(layer=>layer.clipped)}));
|
|
"""
|
|
)
|
|
assert result["before"] == {"groupBase": None, "afterBase": None, "canRoot": False}
|
|
assert result["cleared"] == ["group-base", "after"]
|
|
assert result["clipped"] == [False, False, True, False]
|
|
|
|
|
|
def test_clipped_layer_is_masked_by_base_alpha_before_its_opacity_and_blend():
|
|
result = run_node(
|
|
"""
|
|
const operations=[];
|
|
const makeCtx=tag=>({
|
|
tag,_alpha:1,_gco:'source-over',
|
|
clearRect(){operations.push([tag,'clear']);},
|
|
drawImage(image,x=0,y=0){operations.push([tag,'draw',image.tag,x,y,this._alpha,this._gco]);},
|
|
set globalAlpha(value){this._alpha=value;},get globalAlpha(){return this._alpha;},
|
|
set globalCompositeOperation(value){this._gco=value;},get globalCompositeOperation(){return this._gco;},
|
|
});
|
|
const scratch={tag:'clip-scratch',width:0,height:0,getContext:()=>scratchCtx};
|
|
const scratchCtx=makeCtx('clip-scratch');
|
|
globalThis.document={createElement:()=>scratch};
|
|
const target=makeCtx('target');
|
|
const layers=[
|
|
{id:'base',visible:true,opacity:.4,blendMode:'source-over',clipped:false},
|
|
{id:'color',visible:true,opacity:.7,blendMode:'multiply',clipped:true},
|
|
];
|
|
const state={imgWidth:100,imgHeight:80,layers,layerGroups:[],layerOffsets:new Map([['base',{x:3,y:4}],['color',{x:8,y:9}]])};
|
|
drawLayerStack(target,state,layers,layer=>({tag:layer.id}));
|
|
console.log(JSON.stringify(operations));
|
|
"""
|
|
)
|
|
assert ["target", "draw", "base", 3, 4, 0.4, "source-over"] in result
|
|
assert ["clip-scratch", "draw", "color", 8, 9, 1, "source-over"] in result
|
|
assert ["clip-scratch", "draw", "base", 3, 4, 1, "destination-in"] in result
|
|
assert ["target", "draw", "clip-scratch", 0, 0, 0.7, "multiply"] in result
|