forked from flyingsaucerproject/flyingsaucer
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented MediaFeatureName enum and MediaQueryExpression class in p…
…reparation for media query support. Code is based on that from webkit.
- Loading branch information
Showing
3 changed files
with
313 additions
and
21 deletions.
There are no files selected for viewing
70 changes: 70 additions & 0 deletions
70
flying-saucer-core/src/main/java/org/xhtmlrenderer/css/mediaquery/MediaFeatureName.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package org.xhtmlrenderer.css.mediaquery; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public enum MediaFeatureName | ||
{ | ||
COLOR("color"), | ||
COLOR_INDEX("color-index"), | ||
GRID("grid"), | ||
MONOCHROME("monochrome"), | ||
HEIGHT("height"), | ||
HOVER("hover"), | ||
WIDTH("width"), | ||
ORIENTATION("orientation"), | ||
ASPECT_RATIO("aspect-ratio"), | ||
DEVICE_ASPECT_RATIO("device-aspect-ratio"), | ||
DEVICE_HEIGHT("device-height"), | ||
DEVICE_WIDTH("device-width"), | ||
MAX_COLOR("max-color"), | ||
MAX_COLOR_INDEX("max-color-index"), | ||
MAX_ASPECT_RATIO("max-aspect-ratio"), | ||
MAX_DEVICE_ASPECT_RATIO("max-device-aspect-ratio"), | ||
MAX_DEVICE_HEIGHT("max-device-height"), | ||
MAX_DEVICE_WIDTH("max-device-width"), | ||
MAX_HEIGHT("max-height"), | ||
MAX_MONOCHROME("max-monochrome"), | ||
MAX_WIDTH("max-width"), | ||
MAX_RESOLUTION("max-resolution"), | ||
MIN_COLOR("min-color"), | ||
MIN_COLOR_INDEX("min-color-index"), | ||
MIN_ASPECT_RATIO("min-aspect-ratio"), | ||
MIN_DEVICE_ASPECT_RATIO("min-device-aspect-ratio"), | ||
MIN_DEVICE_HEIGHT("min-device-height"), | ||
MIN_DEVICE_WIDTH("min-device-width"), | ||
MIN_HEIGHT("min-height"), | ||
MIN_MONOCHROME("min-monochrome"), | ||
MIN_WIDTH("min-width"), | ||
MIN_RESOLUTION("min-resolution"), | ||
POINTER("pointer"), | ||
RESOLUTION("resolution"); | ||
|
||
private final String cssName; | ||
|
||
private MediaFeatureName(String name) | ||
{ | ||
cssName = name; | ||
} | ||
|
||
@Override | ||
public String toString() | ||
{ | ||
return cssName; | ||
} | ||
|
||
private static final Map<String, MediaFeatureName> map = new HashMap<>(values().length); | ||
|
||
static | ||
{ | ||
for (MediaFeatureName nm : values()) | ||
{ | ||
map.put(nm.cssName, nm); | ||
} | ||
} | ||
|
||
public static MediaFeatureName fsValueOf(String mediaFeatureStr) | ||
{ | ||
return map.get(mediaFeatureStr); | ||
} | ||
} |
222 changes: 222 additions & 0 deletions
222
flying-saucer-core/src/main/java/org/xhtmlrenderer/css/mediaquery/MediaQueryExpression.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
package org.xhtmlrenderer.css.mediaquery; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import org.w3c.dom.css.CSSPrimitiveValue; | ||
import org.xhtmlrenderer.css.constants.IdentValue; | ||
import org.xhtmlrenderer.css.parser.PropertyValue; | ||
import org.xhtmlrenderer.css.parser.Token; | ||
import org.xhtmlrenderer.css.parser.property.BuilderUtil; | ||
|
||
public class MediaQueryExpression | ||
{ | ||
private final MediaFeatureName _mediaFeature; | ||
private final PropertyValue _cssValue; | ||
private final boolean _isValid; | ||
|
||
public boolean isValid() | ||
{ | ||
return _isValid; | ||
} | ||
|
||
public MediaFeatureName mediaFeature() | ||
{ | ||
return _mediaFeature; | ||
} | ||
|
||
public PropertyValue value() | ||
{ | ||
return _cssValue; | ||
} | ||
|
||
public boolean isViewportDependent() | ||
{ | ||
return _mediaFeature == MediaFeatureName.WIDTH | ||
|| _mediaFeature == MediaFeatureName.HEIGHT | ||
|| _mediaFeature == MediaFeatureName.MIN_WIDTH | ||
|| _mediaFeature == MediaFeatureName.MIN_HEIGHT | ||
|| _mediaFeature == MediaFeatureName.MAX_WIDTH | ||
|| _mediaFeature == MediaFeatureName.MAX_HEIGHT | ||
|| _mediaFeature == MediaFeatureName.ORIENTATION | ||
|| _mediaFeature == MediaFeatureName.ASPECT_RATIO | ||
|| _mediaFeature == MediaFeatureName.MIN_ASPECT_RATIO | ||
|| _mediaFeature == MediaFeatureName.MAX_ASPECT_RATIO; | ||
} | ||
|
||
private static boolean featureWithCSSValueID(MediaFeatureName mediaFeature, PropertyValue value) | ||
{ | ||
IdentValue result = IdentValue.fsValueOf(value.getStringValue()); | ||
|
||
if (result == null) | ||
return false; | ||
|
||
return mediaFeature == MediaFeatureName.ORIENTATION | ||
|| mediaFeature == MediaFeatureName.POINTER; | ||
} | ||
|
||
private static boolean featureWithValidPositiveLenghtOrNumber(MediaFeatureName mediaFeature, PropertyValue value) | ||
{ | ||
if (!BuilderUtil.isLength(value) && value.getPrimitiveType() != CSSPrimitiveValue.CSS_PERCENTAGE) | ||
return false; | ||
|
||
if (value.getFloatValue() < 0) | ||
return false; | ||
|
||
return mediaFeature == MediaFeatureName.HEIGHT | ||
|| mediaFeature == MediaFeatureName.MAX_HEIGHT | ||
|| mediaFeature == MediaFeatureName.MIN_HEIGHT | ||
|| mediaFeature == MediaFeatureName.WIDTH | ||
|| mediaFeature == MediaFeatureName.MAX_WIDTH | ||
|| mediaFeature == MediaFeatureName.MIN_WIDTH | ||
|| mediaFeature == MediaFeatureName.DEVICE_HEIGHT | ||
|| mediaFeature == MediaFeatureName.MAX_DEVICE_HEIGHT | ||
|| mediaFeature == MediaFeatureName.MIN_DEVICE_HEIGHT | ||
|| mediaFeature == MediaFeatureName.DEVICE_WIDTH | ||
|| mediaFeature == MediaFeatureName.MAX_DEVICE_WIDTH | ||
|| mediaFeature == MediaFeatureName.MIN_DEVICE_WIDTH; | ||
} | ||
|
||
private static boolean featureWithValidDensity(MediaFeatureName mediaFeature, PropertyValue value) | ||
{ | ||
// TODO: Support these types... | ||
//if ((value.getPrimitiveType() != CSSPrimitiveValue.CSS_DPPX && value.getPrimitiveType() != CSSPrimitiveValue.CSS_DPI && value.getPrimitiveType() != CSSPrimitiveValue.CSS_DPCM) || value.getFloatValue() <= 0) | ||
// return false; | ||
|
||
return mediaFeature == MediaFeatureName.RESOLUTION | ||
|| mediaFeature == MediaFeatureName.MAX_RESOLUTION | ||
|| mediaFeature == MediaFeatureName.MIN_RESOLUTION; | ||
} | ||
|
||
|
||
private static boolean featureWithPositiveInteger(MediaFeatureName mediaFeature, PropertyValue value) | ||
{ | ||
if ((value.getFloatValue() % 1f) != 0f || value.getFloatValue() < 0) | ||
return false; | ||
|
||
return mediaFeature == MediaFeatureName.COLOR | ||
|| mediaFeature == MediaFeatureName.MAX_COLOR | ||
|| mediaFeature == MediaFeatureName.MIN_COLOR | ||
|| mediaFeature == MediaFeatureName.COLOR_INDEX | ||
|| mediaFeature == MediaFeatureName.MAX_COLOR_INDEX | ||
|| mediaFeature == MediaFeatureName.MIN_COLOR_INDEX | ||
|| mediaFeature == MediaFeatureName.MIN_MONOCHROME | ||
|| mediaFeature == MediaFeatureName.MAX_MONOCHROME; | ||
} | ||
|
||
private static boolean featureWithPositiveNumber(MediaFeatureName mediaFeature, PropertyValue value) | ||
{ | ||
if (value.getPrimitiveType() != CSSPrimitiveValue.CSS_NUMBER || value.getFloatValue() < 0) | ||
return false; | ||
|
||
// No non-webkit specific media expressions fit this cirteria. | ||
return false; | ||
} | ||
|
||
private static boolean featureWithZeroOrOne(MediaFeatureName mediaFeature, PropertyValue value) | ||
{ | ||
if ((value.getFloatValue() % 1f) != 0f || !(value.getFloatValue() == 1 || value.getFloatValue() == 0)) | ||
return false; | ||
|
||
return mediaFeature == MediaFeatureName.GRID | ||
|| mediaFeature == MediaFeatureName.HOVER; | ||
} | ||
|
||
private static boolean featureWithAspectRatio(MediaFeatureName mediaFeature) | ||
{ | ||
return mediaFeature == MediaFeatureName.ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.DEVICE_ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.MIN_ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.MAX_ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.MIN_DEVICE_ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.MAX_DEVICE_ASPECT_RATIO; | ||
} | ||
|
||
private static boolean featureWithoutValue(MediaFeatureName mediaFeature) | ||
{ | ||
// Media features that are prefixed by min/max cannot be used without a value. | ||
return mediaFeature == MediaFeatureName.MONOCHROME | ||
|| mediaFeature == MediaFeatureName.COLOR | ||
|| mediaFeature == MediaFeatureName.COLOR_INDEX | ||
|| mediaFeature == MediaFeatureName.GRID | ||
|| mediaFeature == MediaFeatureName.HEIGHT | ||
|| mediaFeature == MediaFeatureName.WIDTH | ||
|| mediaFeature == MediaFeatureName.DEVICE_HEIGHT | ||
|| mediaFeature == MediaFeatureName.DEVICE_WIDTH | ||
|| mediaFeature == MediaFeatureName.ORIENTATION | ||
|| mediaFeature == MediaFeatureName.ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.DEVICE_ASPECT_RATIO | ||
|| mediaFeature == MediaFeatureName.HOVER | ||
|| mediaFeature == MediaFeatureName.POINTER | ||
|| mediaFeature == MediaFeatureName.RESOLUTION; | ||
} | ||
|
||
@Override | ||
public String toString() | ||
{ | ||
StringBuilder result = new StringBuilder(); | ||
result.append('('); | ||
result.append(_mediaFeature.toString()); | ||
if (_cssValue != null) { | ||
result.append(": "); | ||
result.append(_cssValue.getCssText()); | ||
} | ||
result.append(')'); | ||
|
||
return result.toString(); | ||
} | ||
|
||
public MediaQueryExpression(String mediaFeatureStr, List<PropertyValue> valueList) | ||
{ | ||
_mediaFeature = MediaFeatureName.fsValueOf(mediaFeatureStr); | ||
|
||
// Initialize media query expression that must have 1 or more values. | ||
if (valueList == null && | ||
featureWithoutValue(_mediaFeature)) | ||
{ | ||
_isValid = true; | ||
_cssValue = null; | ||
return; | ||
} | ||
|
||
if (valueList.size() == 1) | ||
{ | ||
_cssValue = valueList.get(0); | ||
|
||
if (featureWithCSSValueID(_mediaFeature, _cssValue) || | ||
featureWithValidDensity(_mediaFeature, _cssValue) || | ||
featureWithValidPositiveLenghtOrNumber(_mediaFeature, _cssValue) || | ||
featureWithPositiveInteger(_mediaFeature, _cssValue) || | ||
featureWithPositiveNumber(_mediaFeature, _cssValue) || | ||
featureWithZeroOrOne(_mediaFeature, _cssValue)) | ||
{ | ||
_isValid = true; | ||
return; | ||
} | ||
} | ||
else if (valueList.size() == 2 && featureWithAspectRatio(_mediaFeature)) | ||
{ | ||
PropertyValue top = valueList.get(0); | ||
PropertyValue bottom = valueList.get(1); | ||
|
||
List<PropertyValue> values = Arrays.asList(top, bottom); | ||
|
||
_cssValue = new PropertyValue(values); | ||
|
||
// The aspect-ratio must be <integer> (whitespace)? / (whitespace)? <integer>. | ||
if (top.getFloatValue() % 1f == 0f && | ||
bottom.getFloatValue() %1f == 0f && | ||
bottom.getOperator() == Token.TK_VIRGULE) | ||
{ | ||
_isValid = true; | ||
return; | ||
} | ||
} | ||
else | ||
{ | ||
_cssValue = null; | ||
} | ||
|
||
_isValid = false; | ||
} | ||
} |
Oops, something went wrong.