Skip to content

Commit 9343409

Browse files
authored
Merge pull request #515 from danfickle/svg_styles
#493 Auto extraction of SVG styles to pass to Batik SVG renderer.
2 parents cbb81da + 33ad1b5 commit 9343409

File tree

17 files changed

+752
-189
lines changed

17 files changed

+752
-189
lines changed

openhtmltopdf-core/src/main/java/com/openhtmltopdf/context/StyleReference.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.openhtmltopdf.css.extend.lib.DOMTreeResolver;
3737
import com.openhtmltopdf.css.newmatch.CascadedStyle;
3838
import com.openhtmltopdf.css.newmatch.PageInfo;
39+
import com.openhtmltopdf.css.newmatch.Selector;
3940
import com.openhtmltopdf.css.parser.CSSPrimitiveValue;
4041
import com.openhtmltopdf.css.sheet.PropertyDeclaration;
4142
import com.openhtmltopdf.css.sheet.Stylesheet;
@@ -196,7 +197,16 @@ public CascadedStyle getCascadedStyle(Element e, boolean restyle) {
196197
if (e == null) return CascadedStyle.emptyCascadedStyle;
197198
return _matcher.getCascadedStyle(e, restyle);
198199
}
199-
200+
201+
/**
202+
* Given an element, returns all selectors and their rulesets
203+
* for its descendants. Useful for getting the styles that should be
204+
* applied to SVG, etc.
205+
*/
206+
public String getCSSForAllDescendants(Element e) {
207+
return _matcher.getCSSForAllDescendants(e);
208+
}
209+
200210
public PageInfo getPageStyle(String pageName, String pseudoPage) {
201211
return _matcher.getPageCascadedStyle(pageName, pseudoPage);
202212
}
@@ -268,14 +278,7 @@ private List<StylesheetInfo> getStylesheets() {
268278

269279
return infos;
270280
}
271-
272-
@Deprecated
273-
public void removeStyle(Element e) {
274-
if (_matcher != null) {
275-
_matcher.removeStyle(e);
276-
}
277-
}
278-
281+
279282
public List<FontFaceRule> getFontFaceRules() {
280283
return _matcher.getFontFaceRules();
281284
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.openhtmltopdf.css.constants;
2+
3+
import java.util.Arrays;
4+
import java.util.Locale;
5+
import java.util.Set;
6+
import java.util.stream.Collectors;
7+
8+
/**
9+
* This is a partial list of common SVG properties that are not present in
10+
* the HTML renderer of this project. This list is here so we can suppress
11+
* warnings for these properties.
12+
*
13+
* List from:
14+
* https://css-tricks.com/svg-properties-and-css/
15+
*/
16+
public enum SVGProperty {
17+
CLIP,
18+
CLIP_PATH,
19+
CLIP_RULE,
20+
MASK,
21+
FILTER,
22+
STOP_COLOR,
23+
STOP_OPACITY,
24+
FILL,
25+
FILL_RULE,
26+
FILL_OPACITY,
27+
MARKER,
28+
MARKER_START,
29+
MARKER_MID,
30+
MARKER_END,
31+
STROKE,
32+
STROKE_DASHARRAY,
33+
STROKE_DASHOFFSET,
34+
STROKE_LINECAP,
35+
STROKE_LINEJOIN,
36+
STROKE_MITERLIMIT,
37+
STROKE_OPACITY,
38+
STROKE_WIDTH;
39+
40+
private static final Set<String> _set =
41+
Arrays.stream(values())
42+
.map(v -> v.name().toLowerCase(Locale.US).replace('_', '-'))
43+
.collect(Collectors.toSet());
44+
45+
public static Set<String> properties() {
46+
return _set;
47+
}
48+
}

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/newmatch/Condition.java

Lines changed: 113 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
abstract class Condition {
3838

3939
abstract boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes);
40+
abstract void toCSS(StringBuilder sb);
4041

4142
/**
4243
* the CSS condition [attribute]
@@ -217,6 +218,17 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
217218

218219
return compare(val, _value);
219220
}
221+
222+
protected void toCSS(StringBuilder sb, String type) {
223+
sb.append('[');
224+
sb.append(_name);
225+
sb.append(type);
226+
sb.append('=');
227+
sb.append('\"');
228+
sb.append(_value);
229+
sb.append('\"');
230+
sb.append(']');
231+
}
220232
}
221233

222234
private static class AttributeExistsCondition extends AttributeCompareCondition {
@@ -241,6 +253,13 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
241253
protected boolean compare(String attrValue, String conditionValue) {
242254
throw new UnsupportedOperationException();
243255
}
256+
257+
@Override
258+
void toCSS(StringBuilder sb) {
259+
sb.append('[');
260+
sb.append(_name);
261+
sb.append(']');
262+
}
244263
}
245264

246265
private static class AttributeEqualsCondition extends AttributeCompareCondition {
@@ -252,6 +271,11 @@ private static class AttributeEqualsCondition extends AttributeCompareCondition
252271
protected boolean compare(String attrValue, String conditionValue) {
253272
return attrValue.equals(conditionValue);
254273
}
274+
275+
@Override
276+
void toCSS(StringBuilder sb) {
277+
toCSS(sb, "");
278+
}
255279
}
256280

257281
private static class AttributePrefixCondition extends AttributeCompareCondition {
@@ -263,6 +287,11 @@ private static class AttributePrefixCondition extends AttributeCompareCondition
263287
protected boolean compare(String attrValue, String conditionValue) {
264288
return attrValue.startsWith(conditionValue);
265289
}
290+
291+
@Override
292+
void toCSS(StringBuilder sb) {
293+
toCSS(sb, "^");
294+
}
266295
}
267296

268297
private static class AttributeSuffixCondition extends AttributeCompareCondition {
@@ -274,6 +303,11 @@ private static class AttributeSuffixCondition extends AttributeCompareCondition
274303
protected boolean compare(String attrValue, String conditionValue) {
275304
return attrValue.endsWith(conditionValue);
276305
}
306+
307+
@Override
308+
void toCSS(StringBuilder sb) {
309+
toCSS(sb, "$");
310+
}
277311
}
278312

279313
private static class AttributeSubstringCondition extends AttributeCompareCondition {
@@ -285,8 +319,13 @@ private static class AttributeSubstringCondition extends AttributeCompareConditi
285319
protected boolean compare(String attrValue, String conditionValue) {
286320
return attrValue.indexOf(conditionValue) > -1;
287321
}
322+
323+
@Override
324+
void toCSS(StringBuilder sb) {
325+
toCSS(sb, "*");
326+
}
288327
}
289-
328+
290329
private static class AttributeMatchesListCondition extends AttributeCompareCondition {
291330
AttributeMatchesListCondition(String namespaceURI, String name, String value) {
292331
super(namespaceURI, name, value);
@@ -303,6 +342,11 @@ protected boolean compare(String attrValue, String conditionValue) {
303342
}
304343
return matched;
305344
}
345+
346+
@Override
347+
void toCSS(StringBuilder sb) {
348+
toCSS(sb, "~");
349+
}
306350
}
307351

308352
private static class AttributeMatchesFirstPartCondition extends AttributeCompareCondition {
@@ -318,6 +362,11 @@ protected boolean compare(String attrValue, String conditionValue) {
318362
}
319363
return false;
320364
}
365+
366+
@Override
367+
void toCSS(StringBuilder sb) {
368+
toCSS(sb, "|");
369+
}
321370
}
322371

323372
private static class ClassCondition extends Condition {
@@ -343,6 +392,12 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
343392
// in an XML DOM, space normalization in attributes is supposed to have happened already.
344393
return (" " + c + " ").indexOf(_paddedClassName) != -1;
345394
}
395+
396+
@Override
397+
public void toCSS(StringBuilder sb) {
398+
sb.append('.');
399+
sb.append(_paddedClassName.substring(1, _paddedClassName.length() - 1));
400+
}
346401
}
347402

348403
private static class IDCondition extends Condition {
@@ -363,6 +418,12 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
363418
}
364419
return true;
365420
}
421+
422+
@Override
423+
void toCSS(StringBuilder sb) {
424+
sb.append('#');
425+
sb.append(_id);
426+
}
366427
}
367428

368429
private static class LangCondition extends Condition {
@@ -390,6 +451,13 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
390451
}
391452
return false;
392453
}
454+
455+
@Override
456+
void toCSS(StringBuilder sb) {
457+
sb.append(":lang(");
458+
sb.append(_lang);
459+
sb.append(')');
460+
}
393461
}
394462

395463
private static class FirstChildCondition extends Condition {
@@ -401,6 +469,11 @@ private static class FirstChildCondition extends Condition {
401469
boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
402470
return treeRes.isFirstChildElement(e);
403471
}
472+
473+
@Override
474+
void toCSS(StringBuilder sb) {
475+
sb.append(":first-child");
476+
}
404477
}
405478

406479
private static class LastChildCondition extends Condition {
@@ -412,6 +485,11 @@ private static class LastChildCondition extends Condition {
412485
boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
413486
return treeRes.isLastChildElement(e);
414487
}
488+
489+
@Override
490+
void toCSS(StringBuilder sb) {
491+
sb.append(":last-child");
492+
}
415493
}
416494

417495
private static class NthChildCondition extends Condition {
@@ -420,10 +498,12 @@ private static class NthChildCondition extends Condition {
420498

421499
private final int a;
422500
private final int b;
501+
private final String input;
423502

424-
NthChildCondition(int a, int b) {
503+
NthChildCondition(int a, int b, String input) {
425504
this.a = a;
426505
this.b = b;
506+
this.input = input;
427507
}
428508

429509
@Override
@@ -442,16 +522,23 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
442522
}
443523
}
444524

525+
@Override
526+
void toCSS(StringBuilder sb) {
527+
sb.append(":nth-child(");
528+
sb.append(input);
529+
sb.append(')');
530+
}
531+
445532
static NthChildCondition fromString(String number) {
446533
number = number.trim().toLowerCase();
447534

448535
if ("even".equals(number)) {
449-
return new NthChildCondition(2, 0);
536+
return new NthChildCondition(2, 0, number);
450537
} else if ("odd".equals(number)) {
451-
return new NthChildCondition(2, 1);
538+
return new NthChildCondition(2, 1, number);
452539
} else {
453540
try {
454-
return new NthChildCondition(0, Integer.parseInt(number));
541+
return new NthChildCondition(0, Integer.parseInt(number), number);
455542
} catch (NumberFormatException e) {
456543
Matcher m = pattern.matcher(number);
457544

@@ -467,7 +554,7 @@ static NthChildCondition fromString(String number) {
467554
b *= -1;
468555
}
469556

470-
return new NthChildCondition(a, b);
557+
return new NthChildCondition(a, b, number);
471558
}
472559
}
473560
}
@@ -484,6 +571,11 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
484571
int position = treeRes.getPositionOfElement(e);
485572
return position >= 0 && position % 2 == 0;
486573
}
574+
575+
@Override
576+
void toCSS(StringBuilder sb) {
577+
sb.append(":nth-child(even)");
578+
}
487579
}
488580

489581
private static class OddChildCondition extends Condition {
@@ -496,6 +588,11 @@ boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
496588
int position = treeRes.getPositionOfElement(e);
497589
return position >= 0 && position % 2 == 1;
498590
}
591+
592+
@Override
593+
void toCSS(StringBuilder sb) {
594+
sb.append(":nth-child(odd)");
595+
}
499596
}
500597

501598
private static class LinkCondition extends Condition {
@@ -507,6 +604,11 @@ private static class LinkCondition extends Condition {
507604
boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
508605
return attRes.isLink(e);
509606
}
607+
608+
@Override
609+
void toCSS(StringBuilder sb) {
610+
sb.append(":link");
611+
}
510612
}
511613

512614
/**
@@ -521,6 +623,11 @@ private static class UnsupportedCondition extends Condition {
521623
boolean matches(Object e, AttributeResolver attRes, TreeResolver treeRes) {
522624
return false;
523625
}
626+
627+
@Override
628+
void toCSS(StringBuilder sb) {
629+
// Nothing we can do...
630+
}
524631
}
525632

526633
private static String[] split(String s, char ch) {

0 commit comments

Comments
 (0)