StyleSheetContainer.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "../../Include/RmlUi/Core/StyleSheetContainer.h"
  2. #include "../../Include/RmlUi/Core/ComputedValues.h"
  3. #include "../../Include/RmlUi/Core/Context.h"
  4. #include "../../Include/RmlUi/Core/Profiling.h"
  5. #include "../../Include/RmlUi/Core/PropertyDictionary.h"
  6. #include "../../Include/RmlUi/Core/StyleSheet.h"
  7. #include "../../Include/RmlUi/Core/Utilities.h"
  8. #include "ComputeProperty.h"
  9. #include "StyleSheetParser.h"
  10. namespace Rml {
  11. StyleSheetContainer::StyleSheetContainer() {}
  12. StyleSheetContainer::~StyleSheetContainer() {}
  13. bool StyleSheetContainer::LoadStyleSheetContainer(Stream* stream, int begin_line_number)
  14. {
  15. StyleSheetParser parser;
  16. bool result = parser.Parse(media_blocks, stream, begin_line_number);
  17. return result;
  18. }
  19. bool StyleSheetContainer::UpdateCompiledStyleSheet(const Context* context)
  20. {
  21. RMLUI_ZoneScoped;
  22. const float dp_ratio = context->GetDensityIndependentPixelRatio();
  23. const Vector2i vp_dimensions_i(context->GetDimensions());
  24. const Vector2f vp_dimensions(vp_dimensions_i);
  25. Vector<int> new_active_media_block_indices;
  26. const float font_size = DefaultComputedValues().font_size();
  27. for (int media_block_index = 0; media_block_index < (int)media_blocks.size(); media_block_index++)
  28. {
  29. const MediaBlock& media_block = media_blocks[media_block_index];
  30. bool all_match = true;
  31. bool expected_match_value = media_block.modifier == MediaQueryModifier::Not ? false : true;
  32. for (const auto& property : media_block.properties.GetProperties())
  33. {
  34. const MediaQueryId id = static_cast<MediaQueryId>(property.first);
  35. Vector2i ratio;
  36. switch (id)
  37. {
  38. case MediaQueryId::Width:
  39. if (vp_dimensions.x != ComputeLength(property.second.GetNumericValue(), font_size, font_size, dp_ratio, vp_dimensions))
  40. all_match = false;
  41. break;
  42. case MediaQueryId::MinWidth:
  43. if (vp_dimensions.x < ComputeLength(property.second.GetNumericValue(), font_size, font_size, dp_ratio, vp_dimensions))
  44. all_match = false;
  45. break;
  46. case MediaQueryId::MaxWidth:
  47. if (vp_dimensions.x > ComputeLength(property.second.GetNumericValue(), font_size, font_size, dp_ratio, vp_dimensions))
  48. all_match = false;
  49. break;
  50. case MediaQueryId::Height:
  51. if (vp_dimensions.y != ComputeLength(property.second.GetNumericValue(), font_size, font_size, dp_ratio, vp_dimensions))
  52. all_match = false;
  53. break;
  54. case MediaQueryId::MinHeight:
  55. if (vp_dimensions.y < ComputeLength(property.second.GetNumericValue(), font_size, font_size, dp_ratio, vp_dimensions))
  56. all_match = false;
  57. break;
  58. case MediaQueryId::MaxHeight:
  59. if (vp_dimensions.y > ComputeLength(property.second.GetNumericValue(), font_size, font_size, dp_ratio, vp_dimensions))
  60. all_match = false;
  61. break;
  62. case MediaQueryId::AspectRatio:
  63. ratio = Vector2i(property.second.Get<Vector2f>());
  64. if (vp_dimensions_i.x * ratio.y != vp_dimensions_i.y * ratio.x)
  65. all_match = false;
  66. break;
  67. case MediaQueryId::MinAspectRatio:
  68. ratio = Vector2i(property.second.Get<Vector2f>());
  69. if (vp_dimensions_i.x * ratio.y < vp_dimensions_i.y * ratio.x)
  70. all_match = false;
  71. break;
  72. case MediaQueryId::MaxAspectRatio:
  73. ratio = Vector2i(property.second.Get<Vector2f>());
  74. if (vp_dimensions_i.x * ratio.y > vp_dimensions_i.y * ratio.x)
  75. all_match = false;
  76. break;
  77. case MediaQueryId::Resolution:
  78. if (dp_ratio != property.second.Get<float>())
  79. all_match = false;
  80. break;
  81. case MediaQueryId::MinResolution:
  82. if (dp_ratio < property.second.Get<float>())
  83. all_match = false;
  84. break;
  85. case MediaQueryId::MaxResolution:
  86. if (dp_ratio > property.second.Get<float>())
  87. all_match = false;
  88. break;
  89. case MediaQueryId::Orientation:
  90. // Landscape (x > y) = 0
  91. // Portrait (x <= y) = 1
  92. if ((vp_dimensions.x <= vp_dimensions.y) != property.second.Get<bool>())
  93. all_match = false;
  94. break;
  95. case MediaQueryId::Theme:
  96. if (!context->IsThemeActive(property.second.Get<String>()))
  97. all_match = false;
  98. break;
  99. // Invalid properties
  100. case MediaQueryId::Invalid:
  101. case MediaQueryId::NumDefinedIds: break;
  102. }
  103. if (all_match != expected_match_value)
  104. break;
  105. }
  106. if (all_match == expected_match_value)
  107. new_active_media_block_indices.push_back(media_block_index);
  108. }
  109. const bool style_sheet_changed = (new_active_media_block_indices != active_media_block_indices || !compiled_style_sheet);
  110. if (style_sheet_changed)
  111. {
  112. StyleSheet* first_sheet = nullptr;
  113. UniquePtr<StyleSheet> new_sheet;
  114. for (int index : new_active_media_block_indices)
  115. {
  116. MediaBlock& media_block = media_blocks[index];
  117. if (!first_sheet)
  118. first_sheet = media_block.stylesheet.get();
  119. else if (!new_sheet)
  120. new_sheet = first_sheet->CombineStyleSheet(*media_block.stylesheet);
  121. else
  122. new_sheet->MergeStyleSheet(*media_block.stylesheet);
  123. }
  124. if (!first_sheet)
  125. {
  126. new_sheet.reset(new StyleSheet);
  127. first_sheet = new_sheet.get();
  128. }
  129. compiled_style_sheet = (new_sheet ? new_sheet.get() : first_sheet);
  130. combined_compiled_style_sheet = std::move(new_sheet);
  131. compiled_style_sheet->BuildNodeIndex();
  132. }
  133. active_media_block_indices = std::move(new_active_media_block_indices);
  134. return style_sheet_changed;
  135. }
  136. StyleSheet* StyleSheetContainer::GetCompiledStyleSheet()
  137. {
  138. return compiled_style_sheet;
  139. }
  140. SharedPtr<StyleSheetContainer> StyleSheetContainer::CombineStyleSheetContainer(const StyleSheetContainer& container) const
  141. {
  142. RMLUI_ZoneScoped;
  143. SharedPtr<StyleSheetContainer> new_sheet = MakeShared<StyleSheetContainer>();
  144. for (const MediaBlock& media_block : media_blocks)
  145. {
  146. new_sheet->media_blocks.emplace_back(media_block.properties, media_block.stylesheet, media_block.modifier);
  147. }
  148. new_sheet->MergeStyleSheetContainer(container);
  149. return new_sheet;
  150. }
  151. void StyleSheetContainer::MergeStyleSheetContainer(const StyleSheetContainer& other)
  152. {
  153. RMLUI_ZoneScoped;
  154. // Style sheet container must not be merged after it's been compiled. This will invalidate references to the compiled style sheet.
  155. RMLUI_ASSERT(!compiled_style_sheet);
  156. auto it_other_begin = other.media_blocks.begin();
  157. #if 0
  158. // If the last block here has the same media requirements as the first block in other, we can safely merge them
  159. // while retaining correct specificity of all properties. This is essentially an optimization to avoid more
  160. // style sheet merging later on.
  161. if (!media_blocks.empty() && !other.media_blocks.empty())
  162. {
  163. MediaBlock& block_local = media_blocks.back();
  164. const MediaBlock& block_other = other.media_blocks.front();
  165. if (block_local.properties.GetProperties() == block_other.properties.GetProperties())
  166. {
  167. // Now we can safely merge the two style sheets.
  168. block_local.stylesheet = block_local.stylesheet->CombineStyleSheet(*block_other.stylesheet);
  169. // And we need to skip the first media block in the 'other' style sheet, since we merged it just now.
  170. ++it_other_begin;
  171. }
  172. }
  173. #endif
  174. // Add all the other blocks into ours.
  175. for (auto it = it_other_begin; it != other.media_blocks.end(); ++it)
  176. {
  177. const MediaBlock& block_other = *it;
  178. media_blocks.emplace_back(block_other.properties, block_other.stylesheet, block_other.modifier);
  179. }
  180. }
  181. } // namespace Rml