Skip to content

Commit

Permalink
Improved CSS and HTML support:
Browse files Browse the repository at this point in the history
- better CSS class parsing
- added support for pre HTML tag
- added support for px font size
- added support for MParagraph background color
  • Loading branch information
ylussaud committed Dec 3, 2024
1 parent 4f01668 commit d1832e5
Show file tree
Hide file tree
Showing 37 changed files with 385 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016 Obeo.
* Copyright (c) 2016, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -23,7 +23,7 @@
import org.obeonetwork.m2doc.genconf.editor.GenconfEditorLauncher;

/**
* Initialize configurations for documention generation.
* Initialize configurations for documentation generation.
*
* @author <a href="mailto:nathalie.lepine@obeo.fr">Nathalie Lepine</a>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,16 @@ public class M2DocCSSParser extends Parser {
*/
private static final int ALL_FONT_MODIFIERS_MASK = 0xFFFFFFFF;

/**
* The {@link Pattern} that parse a CSS comment.
*/
private static final Pattern CSS_COMMENT_PATTERN = Pattern.compile("/\\*.*?\\*/");

/**
* The {@link Pattern} that parse a CSS class.
*/
private static final Pattern CSS_CLASS_PATTERN = Pattern.compile("([_a-zA-Z0-9.:]+\\s)+\\{([^\\}]*)\\}");
private static final Pattern CSS_CLASS_PATTERN = Pattern
.compile("(([_a-zA-Z0-9.:\\->,\\[\\]()\"=@^* #+~$\n\r]+\\s)+)\\{([^\\}]*)\\}");

/**
* The class name group from {@link #CSS_CLASS_PATTERN}.
Expand All @@ -256,7 +262,7 @@ public class M2DocCSSParser extends Parser {
/**
* The CSS styles group from {@link #CSS_CLASS_PATTERN}.
*/
private static final int CSS_CLASS_PATTERN_CSS_STYLES_GROUP = 2;
private static final int CSS_CLASS_PATTERN_CSS_STYLES_GROUP = 3;

/**
* The bold threshold for font weight.
Expand All @@ -268,6 +274,11 @@ public class M2DocCSSParser extends Parser {
*/
private static final String REG_EXP_SPACES = "\\s+";

/**
* The expression separating CSS class definition.
*/
private static final String CLASS_DEFINITION_SEPARATOR = ",";

/**
* The style attribute.
*/
Expand All @@ -283,18 +294,56 @@ public class M2DocCSSParser extends Parser {
public Map<String, Map<String, List<String>>> parseClasses(String cssClasses) {
Map<String, Map<String, List<String>>> res = new LinkedHashMap<>();

final Matcher matcher = CSS_CLASS_PATTERN.matcher(cssClasses);
final String cssNoComments = CSS_COMMENT_PATTERN.matcher(cssClasses).replaceAll("");
final String cssNoAtRule = removeAtRules(cssNoComments);

final Matcher matcher = CSS_CLASS_PATTERN.matcher(cssNoAtRule);
while (matcher.find()) {
final String classNames = matcher.group(CSS_CLASS_PATTERN_NAME_GROUP);
for (String className : classNames.split(REG_EXP_SPACES)) {
final Map<String, List<String>> styles = parseStyles(matcher.group(CSS_CLASS_PATTERN_CSS_STYLES_GROUP));
res.computeIfAbsent(className, n -> new LinkedHashMap<String, List<String>>()).putAll(styles);
final Map<String, List<String>> styles = parseStyles(matcher.group(CSS_CLASS_PATTERN_CSS_STYLES_GROUP));
for (String name : classNames.split(CLASS_DEFINITION_SEPARATOR)) {
final String className = name.trim();
if (className != null && !className.isEmpty()) {
res.computeIfAbsent(className.trim(), n -> new LinkedHashMap<String, List<String>>())
.putAll(styles);
}
}
}

return res;
}

/**
* Removes @ rules (@media, @scope, ...) form the given CSS.
*
* @param cssNoComments
* the CSS without comment
* @return the CSS without @ rules
*/
private String removeAtRules(String cssNoComments) {
final StringBuilder res = new StringBuilder();

boolean inAtRule = false;
int curlyBraceDepth = 0;
for (int i = 0; i < cssNoComments.length(); i++) {
final char current = cssNoComments.charAt(i);
if (current == '@') {
inAtRule = true;
} else if (inAtRule) {
if (current == '{') {
curlyBraceDepth++;
} else if (current == '}') {
curlyBraceDepth--;
inAtRule = curlyBraceDepth > 0;
}
} else {
res.append(current);
}
}

return res.toString();
}

/**
* Merges the source CSS styles to the target CSS styles.
*
Expand Down Expand Up @@ -519,9 +568,9 @@ public void setStyle(Map<String, List<String>> cssProperties, MStyle mStyle) {
final List<String> cssFontSizes = cssProperties.get(CSS_FONT_SIZE);
if (cssFontSizes != null) {
for (String cssFontSize : cssFontSizes) {
final int pixelSize = getPixels(cssFontSize);
if (pixelSize != -1) {
mStyle.setFontSize(pixelSize);
final int fontSize = fontSizeToPoint(cssFontSize);
if (fontSize != -1) {
mStyle.setFontSize(fontSize);
}
}
}
Expand Down Expand Up @@ -560,25 +609,37 @@ public void setStyle(Map<String, List<String>> cssProperties, MStyle mStyle) {
* the {@link MCell}
*/
public void setStyle(Map<String, List<String>> cssProperties, MCell mCell) {
setContainerBackgroundColor(cssProperties, mCell);
final List<String> cssWidths = cssProperties.get(CSS_WIDTH);
if (cssWidths != null) {
for (String cssWidth : cssWidths) {
setCellWidth(mCell, cssWidth);
}
}
setContainerStyle(cssProperties, mCell);
}

/**
* Sets the given {@link MElementContainer} {@link MElementContainer#getBackgroundColor() background color}.
*
* @param cssProperties
* the CSS properties
* @param mContainer
* the {@link MElementContainer}
*/
public void setContainerBackgroundColor(Map<String, List<String>> cssProperties, MElementContainer mContainer) {
final List<String> cssBackgroundColors = cssProperties.get(CSS_BACKGROUND_COLOR);
if (cssBackgroundColors != null) {
for (String cssBackgroundColor : cssBackgroundColors) {
mCell.setBackgroundColor(htmlToColor(cssBackgroundColor));
mContainer.setBackgroundColor(htmlToColor(cssBackgroundColor));
}
}
final List<String> cssBackgrounds = cssProperties.get(CSS_BACKGROUND);
if (cssBackgrounds != null) {
for (String cssBackground : cssBackgrounds) {
mCell.setBackgroundColor(htmlToColor(cssBackground));
mContainer.setBackgroundColor(htmlToColor(cssBackground));
}
}
final List<String> cssWidths = cssProperties.get(CSS_WIDTH);
if (cssWidths != null) {
for (String cssWidth : cssWidths) {
setCellWidth(mCell, cssWidth);
}
}
setContainerStyle(cssProperties, mCell);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ public class M2DocHTMLParser extends Parser {
*/
private static final String BR_TAG = "br";

/**
* The {@link Set} of <br>
* continue tags.
*/
private static final Set<String> BR_CONTINUE_TAGS = initializeBrContinueTags();

/**
Expand Down Expand Up @@ -215,6 +219,11 @@ public class M2DocHTMLParser extends Parser {
*/
private static final String CENTER_TAG = "center";

/**
* The pre HTML tag.
*/
private static final String PRE_TAG = "pre";

/**
* Courier New font.
*/
Expand Down Expand Up @@ -1481,7 +1490,11 @@ private String trimFirst(String text) {
private String text(TextNode textNode) {
final String string = textNode.getWholeText();
StringBuilder sb = new StringBuilder(string.length());
appendNormalisedWhitespace(sb, string, false);
if (PRE_TAG.equals(textNode.parent().nodeName())) {
sb.append(string);
} else {
appendNormalisedWhitespace(sb, string, false);
}
return sb.toString();
}

Expand Down Expand Up @@ -1549,6 +1562,9 @@ private MParagraph startElement(MParagraph parent, Context context, Element elem
boolean isNumbering = false;
if (P_TAG.equals(nodeName)) {
res = createMParagraph(context, parent, element, null, null);
} else if (PRE_TAG.equals(nodeName)) {
res = createMParagraph(context, parent, element, null, null);
CSS_PARSER.setContainerBackgroundColor(context.cssProperties, (MParagraph) res);
} else if (BLOCKQUOTE_TAG.equals(nodeName)) {
if (element.childNodeSize() > 0 && element.childNode(0) instanceof TextNode) {
TextNode textNode = (TextNode) element.childNode(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public abstract class Parser {
/**
* The font size regex.
*/
private static final Pattern FONT_SIZE_PATTERN = Pattern.compile("([0-9]+(\\.[0-9]+)?)(pt)?");
private static final Pattern FONT_SIZE_PATTERN = Pattern.compile("([0-9]+(\\.[0-9]+)?)(pt|px|em|%)?");

/**
* The value group for {@link #FONT_SIZE_PATTERN}.
Expand Down Expand Up @@ -365,7 +365,7 @@ protected int fontSizeToPoint(String fontSize) {
final String unit = matcher.group(FONT_SIZE_PATTERN_UNIT_GROUP);

if (unit == null || "pt".equals(unit)) {
// CHECKSTYLE:OFF
// CHECKSTYLE:OFF unit conversion
switch ((int) value) {
case 1:
res = 7;
Expand Down Expand Up @@ -395,14 +395,19 @@ protected int fontSizeToPoint(String fontSize) {
res = 36;
break;
}
} else if ("px".equals(unit)) {
res = (int) (0.75d * value);
} else if ("em".equals(unit)) {
res = (int) (value * Double.valueOf(DEFAULT_FONT_SIZE));
} else if ("%".equals(unit)) {
res = (int) ((value / 100d) * Double.valueOf(DEFAULT_FONT_SIZE));
} else {
res = -1;
}
// CHECKSTYLE:ON
} else {
res = -1;
}
// CHECKSTYLE:ON

return res;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018 Obeo.
* Copyright (c) 2018, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -11,6 +11,8 @@
*******************************************************************************/
package org.obeonetwork.m2doc.element;

import java.awt.Color;

/**
* A container for {@link MElement}.
*
Expand Down Expand Up @@ -107,4 +109,19 @@ enum HAlignment {
*/
void setHAlignment(HAlignment alignment);

/**
* Gets the background {@link Color}.
*
* @return the background {@link Color} if any, <code>null</code> otherwise
*/
Color getBackgroundColor();

/**
* Sets the background {@link Color}.
*
* @param color
* the new background {@link Color}, <code>null</code> for default
*/
void setBackgroundColor(Color color);

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*******************************************************************************/
package org.obeonetwork.m2doc.element;

import java.awt.Color;
import java.util.Collections;
import java.util.List;

Expand Down Expand Up @@ -232,21 +231,6 @@ enum WidthType {
PCT
}

/**
* Gets the background {@link Color}.
*
* @return the background {@link Color} if any, <code>null</code> otherwise
*/
Color getBackgroundColor();

/**
* Sets the background {@link Color}.
*
* @param color
* the new background {@link Color}
*/
void setBackgroundColor(Color color);

/**
* Gets the {@link VAlignment vertical alignment}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018 Obeo.
* Copyright (c) 2018, 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -11,6 +11,8 @@
*******************************************************************************/
package org.obeonetwork.m2doc.element.impl;

import java.awt.Color;

import org.obeonetwork.m2doc.element.MElement;
import org.obeonetwork.m2doc.element.MElementContainer;

Expand All @@ -31,6 +33,11 @@ public abstract class AbstractMElementContainer implements MElementContainer {
*/
private HAlignment hAlign;

/**
* The background {@link Color}.
*/
private Color backgroundColor;

/**
* Constructor.
*
Expand Down Expand Up @@ -61,4 +68,14 @@ public void setHAlignment(HAlignment alignement) {
hAlign = alignement;
}

@Override
public Color getBackgroundColor() {
return backgroundColor;
}

@Override
public void setBackgroundColor(Color color) {
backgroundColor = color;
}

}
Loading

0 comments on commit d1832e5

Please sign in to comment.