Skip to content

Commit

Permalink
Add support for the not prefix in media queries (mikke89#564)
Browse files Browse the repository at this point in the history
  • Loading branch information
Paril authored Jan 10, 2024
1 parent f9b8f6b commit 4c7ba7a
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 20 deletions.
10 changes: 8 additions & 2 deletions Include/RmlUi/Core/StyleSheetTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,20 @@ struct DecoratorDeclarationList {
String value;
};

enum class MediaQueryModifier {
None,
Not // passes only if the query is false instead of true
};

struct MediaBlock {
MediaBlock() {}
MediaBlock(PropertyDictionary _properties, SharedPtr<StyleSheet> _stylesheet) :
properties(std::move(_properties)), stylesheet(std::move(_stylesheet))
MediaBlock(PropertyDictionary _properties, SharedPtr<StyleSheet> _stylesheet, MediaQueryModifier _modifier) :
properties(std::move(_properties)), stylesheet(std::move(_stylesheet)), modifier(_modifier)
{}

PropertyDictionary properties; // Media query properties
SharedPtr<StyleSheet> stylesheet;
MediaQueryModifier modifier = MediaQueryModifier::None;
};
using MediaBlockList = Vector<MediaBlock>;

Expand Down
10 changes: 6 additions & 4 deletions Source/Core/StyleSheetContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ bool StyleSheetContainer::UpdateCompiledStyleSheet(const Context* context)
{
const MediaBlock& media_block = media_blocks[media_block_index];
bool all_match = true;
bool expected_match_value = media_block.modifier == MediaQueryModifier::Not ? false : true;

for (const auto& property : media_block.properties.GetProperties())
{
const MediaQueryId id = static_cast<MediaQueryId>(property.first);
Expand Down Expand Up @@ -138,11 +140,11 @@ bool StyleSheetContainer::UpdateCompiledStyleSheet(const Context* context)
case MediaQueryId::NumDefinedIds: break;
}

if (!all_match)
if (all_match != expected_match_value)
break;
}

if (all_match)
if (all_match == expected_match_value)
new_active_media_block_indices.push_back(media_block_index);
}

Expand Down Expand Up @@ -194,7 +196,7 @@ SharedPtr<StyleSheetContainer> StyleSheetContainer::CombineStyleSheetContainer(c

for (const MediaBlock& media_block : media_blocks)
{
new_sheet->media_blocks.emplace_back(media_block.properties, media_block.stylesheet);
new_sheet->media_blocks.emplace_back(media_block.properties, media_block.stylesheet, media_block.modifier);
}

new_sheet->MergeStyleSheetContainer(container);
Expand Down Expand Up @@ -234,7 +236,7 @@ void StyleSheetContainer::MergeStyleSheetContainer(const StyleSheetContainer& ot
for (auto it = it_other_begin; it != other.media_blocks.end(); ++it)
{
const MediaBlock& block_other = *it;
media_blocks.emplace_back(block_other.properties, block_other.stylesheet);
media_blocks.emplace_back(block_other.properties, block_other.stylesheet, block_other.modifier);
}
}

Expand Down
49 changes: 37 additions & 12 deletions Source/Core/StyleSheetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ static UniquePtr<SpritesheetPropertyParser> spritesheet_property_parser;

/*
* Media queries need a special parser because they have unique properties that
* aren't admissible in other property declaration contexts and the syntax of
* aren't admissible in other property declaration contexts.
*/
class MediaQueryPropertyParser final : public AbstractPropertyParser {
private:
Expand Down Expand Up @@ -398,27 +398,49 @@ bool StyleSheetParser::ParseDecoratorBlock(const String& at_name, DecoratorSpeci
return true;
}

bool StyleSheetParser::ParseMediaFeatureMap(PropertyDictionary& properties, const String& rules)
bool StyleSheetParser::ParseMediaFeatureMap(const String& rules, PropertyDictionary& properties, MediaQueryModifier &modifier)
{
media_query_property_parser->SetTargetProperties(&properties);

enum ParseState { Global, Name, Value };
ParseState state = Name;
ParseState state = Global;

char character = 0;

size_t cursor = 0;

String name;

String current_string;

while (cursor++ < rules.length())
modifier = MediaQueryModifier::None;

for (size_t cursor = 0; cursor < rules.length(); cursor++)
{
character = rules[cursor];

switch (character)
{
case ' ':
{
if (state == Global)
{
current_string = StringUtilities::StripWhitespace(StringUtilities::ToLower(std::move(current_string)));

if (current_string == "not")
{
// we can only ever see one "not" on the entire global query.
if (modifier != MediaQueryModifier::None)
{
Log::Message(Log::LT_WARNING, "Unexpected '%s' in @media query list at %s:%d.", current_string.c_str(), stream_file_name.c_str(), line_number);
return false;
}

modifier = MediaQueryModifier::Not;
current_string.clear();
}
}

break;
}
case '(':
{
if (state != Global)
Expand All @@ -429,7 +451,9 @@ bool StyleSheetParser::ParseMediaFeatureMap(PropertyDictionary& properties, cons

current_string = StringUtilities::StripWhitespace(StringUtilities::ToLower(std::move(current_string)));

if (current_string != "and")
// allow an empty string to pass through only if we had just parsed a modifier.
if (current_string != "and" &&
(properties.GetNumProperties() != 0 || !current_string.empty()))
{
Log::Message(Log::LT_WARNING, "Unexpected '%s' in @media query list at %s:%d. Expected 'and'.", current_string.c_str(),
stream_file_name.c_str(), line_number);
Expand Down Expand Up @@ -529,7 +553,7 @@ bool StyleSheetParser::Parse(MediaBlockList& style_sheets, Stream* _stream, int
// Initialize current block if not present
if (!current_block.stylesheet)
{
current_block = MediaBlock{PropertyDictionary{}, UniquePtr<StyleSheet>(new StyleSheet())};
current_block = MediaBlock{PropertyDictionary{}, UniquePtr<StyleSheet>(new StyleSheet()), MediaQueryModifier::None};
}

const int rule_line_number = line_number;
Expand Down Expand Up @@ -586,7 +610,7 @@ bool StyleSheetParser::Parse(MediaBlockList& style_sheets, Stream* _stream, int
// Initialize current block if not present
if (!current_block.stylesheet)
{
current_block = {PropertyDictionary{}, UniquePtr<StyleSheet>(new StyleSheet())};
current_block = {PropertyDictionary{}, UniquePtr<StyleSheet>(new StyleSheet()), MediaQueryModifier::None};
}

const String at_rule_identifier = StringUtilities::StripWhitespace(pre_token_str.substr(0, pre_token_str.find(' ')));
Expand Down Expand Up @@ -654,8 +678,9 @@ bool StyleSheetParser::Parse(MediaBlockList& style_sheets, Stream* _stream, int

// parse media query list into block
PropertyDictionary feature_map;
ParseMediaFeatureMap(feature_map, at_rule_name);
current_block = {std::move(feature_map), UniquePtr<StyleSheet>(new StyleSheet())};
MediaQueryModifier modifier;
ParseMediaFeatureMap(at_rule_name, feature_map, modifier);
current_block = {std::move(feature_map), UniquePtr<StyleSheet>(new StyleSheet()), modifier};

inside_media_block = true;
state = State::Global;
Expand Down Expand Up @@ -684,7 +709,7 @@ bool StyleSheetParser::Parse(MediaBlockList& style_sheets, Stream* _stream, int
// Initialize current block if not present
if (!current_block.stylesheet)
{
current_block = {PropertyDictionary{}, UniquePtr<StyleSheet>(new StyleSheet())};
current_block = {PropertyDictionary{}, UniquePtr<StyleSheet>(new StyleSheet()), MediaQueryModifier::None};
}

// Each keyframe in keyframes has its own block which is processed here
Expand Down
7 changes: 5 additions & 2 deletions Source/Core/StyleSheetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ class StyleSheetParser {
bool ParseDecoratorBlock(const String& at_name, DecoratorSpecificationMap& decorator_map, const StyleSheet& style_sheet,
const SharedPtr<const PropertySource>& source);

// Attempts to parse the properties of a @media query
bool ParseMediaFeatureMap(PropertyDictionary& properties, const String& rules);
/// Attempts to parse the properties of a @media query.
/// @param[in] rules The rules to parse.
/// @param[out] properties Parsed properties representing all values to be matched.
/// @param[out] modifier Media query modifier.
bool ParseMediaFeatureMap(const String& rules, PropertyDictionary& properties, MediaQueryModifier &modifier);

// Attempts to find one of the given character tokens in the active stream
// If it's found, buffer is filled with all content up until the token
Expand Down
Loading

0 comments on commit 4c7ba7a

Please sign in to comment.