@@ -189,6 +189,97 @@ protected function applyTransform($attributes)
189
189
}
190
190
}
191
191
192
+ /**
193
+ * Apply a viewBox transform to the element
194
+ *
195
+ * @param array $attributes
196
+ */
197
+ protected function applyViewbox ($ attributes ) {
198
+ if (!isset ($ attributes ["viewbox " ])) {
199
+ return ;
200
+ }
201
+
202
+ $ surface = $ this ->document ->getSurface ();
203
+ $ viewBox = preg_split ('/[\s,]+/is ' , trim ($ attributes ['viewbox ' ]));
204
+ if (count ($ viewBox ) != 4 ) {
205
+ return ;
206
+ }
207
+
208
+ // Computing the equivalent transform of an SVG viewport
209
+ // https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform
210
+
211
+ // 1. Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the viewBox attribute respectively.
212
+ [$ vbX , $ vbY , $ vbWidth , $ vbHeight ] = $ viewBox ;
213
+
214
+ if ($ vbWidth < 0 || $ vbHeight < 0 ) {
215
+ return ;
216
+ }
217
+
218
+ // correct solution is to not render, for now scaling to 0 below
219
+ //if ($vbWidth == 0 || $vbHeight == 0) {
220
+ //}
221
+
222
+ // 2. Let e-x, e-y, e-width, e-height be the position and size of the element respectively.
223
+ $ eX = $ attributes ["x " ] ?? 0 ;
224
+ $ eY = $ attributes ["y " ] ?? 0 ;
225
+ $ eWidth = $ attributes ["width " ] ?? $ this ->document ->getWidth ();
226
+ $ eHeight = $ attributes ["height " ] ?? $ this ->document ->getHeight ();
227
+
228
+ // 3. Let align be the align value of preserveAspectRatio, or 'xMidYMid' if preserveAspectRatio is not defined.
229
+ $ preserveAspectRatio = explode (" " , $ attributes ["preserveAspectRatio " ] ?? "xMidYMid meet " );
230
+ $ align = $ preserveAspectRatio [0 ];
231
+
232
+ // 4. Let meetOrSlice be the meetOrSlice value of preserveAspectRatio, or 'meet' if preserveAspectRatio is not defined or if meetOrSlice is missing from this value.
233
+ $ meetOrSlice = $ meetOrSlice ?? "meet " ;
234
+
235
+ // 5. Initialize scale-x to e-width/vb-width.
236
+ $ scaleX = $ vbWidth == 0 ? 0 : ($ eWidth / $ vbWidth );
237
+
238
+ // 6. Initialize scale-y to e-height/vb-height.
239
+ $ scaleY = $ vbHeight == 0 ? 0 : ($ eHeight / $ vbHeight );
240
+
241
+ // 7. If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to the smaller.
242
+ if ($ align !== "none " && $ meetOrSlice === "meet " ) {
243
+ $ scaleX = min ($ scaleX , $ scaleY );
244
+ $ scaleY = min ($ scaleX , $ scaleY );
245
+ }
246
+
247
+ // 8. Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x and scale-y to the larger.
248
+ elseif ($ align !== "none " && $ meetOrSlice === "slice " ) {
249
+ $ scaleX = max ($ scaleX , $ scaleY );
250
+ $ scaleY = max ($ scaleX , $ scaleY );
251
+ }
252
+
253
+ // 9. Initialize translate-x to e-x - (vb-x * scale-x).
254
+ $ translateX = $ eX - ($ vbX * $ scaleX );
255
+
256
+ // 10. Initialize translate-y to e-y - (vb-y * scale-y)
257
+ $ translateY = $ eY - ($ vbY * $ scaleY );
258
+
259
+ // 11. If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x.
260
+ if (strpos ($ align , "xMid " ) !== false ) {
261
+ $ translateX += ($ eWidth - $ vbWidth * $ scaleX ) / 2 ;
262
+ }
263
+
264
+ // 12. If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x.
265
+ if (strpos ($ align , "xMax " ) !== false ) {
266
+ $ translateX += ($ eWidth - $ vbWidth * $ scaleX );
267
+ }
268
+
269
+ // 13. If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y.
270
+ if (strpos ($ align , "yMid " ) !== false ) {
271
+ $ translateX += ($ eHeight - $ vbHeight * $ scaleY ) / 2 ;
272
+ }
273
+
274
+ // 14. If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y.
275
+ if (strpos ($ align , "yMid " ) !== false ) {
276
+ $ translateX += ($ eHeight - $ vbHeight * $ scaleY );
277
+ }
278
+
279
+ $ surface ->translate ($ translateX , $ translateY );
280
+ $ surface ->scale ($ scaleX , $ scaleY );
281
+ }
282
+
192
283
/**
193
284
* Convert the given size for the context of this current tag.
194
285
* Takes a pixel-based reference, which is usually specific to the context of the size,
0 commit comments