diff options
Diffstat (limited to 'libs/litehtml/src/formatting_context.cpp')
-rw-r--r-- | libs/litehtml/src/formatting_context.cpp | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/libs/litehtml/src/formatting_context.cpp b/libs/litehtml/src/formatting_context.cpp new file mode 100644 index 0000000000..e85e990c9c --- /dev/null +++ b/libs/litehtml/src/formatting_context.cpp @@ -0,0 +1,441 @@ +#include "html.h" +#include "render_item.h" +#include "formatting_context.h" + +void litehtml::formatting_context::add_float(const std::shared_ptr<render_item> &el, int min_width, int context) +{ + floated_box fb; + fb.pos.x = el->left() + m_current_left; + fb.pos.y = el->top() + m_current_top; + fb.pos.width = el->width(); + fb.pos.height = el->height(); + fb.float_side = el->src_el()->css().get_float(); + fb.clear_floats = el->src_el()->css().get_clear(); + fb.el = el; + fb.context = context; + fb.min_width = min_width; + + if(fb.float_side == float_left) + { + if(m_floats_left.empty()) + { + m_floats_left.push_back(fb); + } else + { + bool inserted = false; + for(auto i = m_floats_left.begin(); i != m_floats_left.end(); i++) + { + if(fb.pos.right() > i->pos.right()) + { + m_floats_left.insert(i, std::move(fb)); + inserted = true; + break; + } + } + if(!inserted) + { + m_floats_left.push_back(std::move(fb)); + } + } + m_cache_line_left.invalidate(); + } else if(fb.float_side == float_right) + { + if(m_floats_right.empty()) + { + m_floats_right.push_back(std::move(fb)); + } else + { + bool inserted = false; + for(auto i = m_floats_right.begin(); i != m_floats_right.end(); i++) + { + if(fb.pos.left() < i->pos.left()) + { + m_floats_right.insert(i, std::move(fb)); + inserted = true; + break; + } + } + if(!inserted) + { + m_floats_right.push_back(fb); + } + } + m_cache_line_right.invalidate(); + } +} + +int litehtml::formatting_context::get_floats_height(element_float el_float) const +{ + int h = m_current_top; + + for(const auto& fb : m_floats_left) + { + bool process = false; + switch(el_float) + { + case float_none: + process = true; + break; + case float_left: + if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) + { + process = true; + } + break; + case float_right: + if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) + { + process = true; + } + break; + } + if(process) + { + if(el_float == float_none) + { + h = std::max(h, fb.pos.bottom()); + } else + { + h = std::max(h, fb.pos.top()); + } + } + } + + + for(const auto& fb : m_floats_right) + { + int process = false; + switch(el_float) + { + case float_none: + process = true; + break; + case float_left: + if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) + { + process = true; + } + break; + case float_right: + if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) + { + process = true; + } + break; + } + if(process) + { + if(el_float == float_none) + { + h = std::max(h, fb.pos.bottom()); + } else + { + h = std::max(h, fb.pos.top()); + } + } + } + + return h - m_current_top; +} + +int litehtml::formatting_context::get_left_floats_height() const +{ + int h = 0; + if(!m_floats_left.empty()) + { + for (const auto& fb : m_floats_left) + { + h = std::max(h, fb.pos.bottom()); + } + } + return h - m_current_top; +} + +int litehtml::formatting_context::get_right_floats_height() const +{ + int h = 0; + if(!m_floats_right.empty()) + { + for(const auto& fb : m_floats_right) + { + h = std::max(h, fb.pos.bottom()); + } + } + return h - m_current_top; +} + +int litehtml::formatting_context::get_line_left(int y ) +{ + y += m_current_top; + + if(m_cache_line_left.is_valid && m_cache_line_left.hash == y) + { + if(m_cache_line_left.val - m_current_left < 0) + { + return 0; + } + return m_cache_line_left.val - m_current_left; + } + + int w = 0; + for(const auto& fb : m_floats_left) + { + if (y >= fb.pos.top() && y < fb.pos.bottom()) + { + w = std::max(w, fb.pos.right()); + if (w < fb.pos.right()) + { + break; + } + } + } + m_cache_line_left.set_value(y, w); + w -= m_current_left; + if(w < 0) return 0; + return w; +} + +int litehtml::formatting_context::get_line_right(int y, int def_right ) +{ + y += m_current_top; + def_right += m_current_left; + if(m_cache_line_right.is_valid && m_cache_line_right.hash == y) + { + if(m_cache_line_right.is_default) + { + return def_right - m_current_left; + } else + { + int w = std::min(m_cache_line_right.val, def_right) - m_current_left; + if(w < 0) return 0; + return w; + } + } + + int w = def_right; + m_cache_line_right.is_default = true; + for(const auto& fb : m_floats_right) + { + if(y >= fb.pos.top() && y < fb.pos.bottom()) + { + w = std::min(w, fb.pos.left()); + m_cache_line_right.is_default = false; + if(w > fb.pos.left()) + { + break; + } + } + } + m_cache_line_right.set_value(y, w); + w -= m_current_left; + if(w < 0) return 0; + return w; +} + + +void litehtml::formatting_context::clear_floats(int context) +{ + auto iter = m_floats_left.begin(); + while(iter != m_floats_left.end()) + { + if(iter->context >= context) + { + iter = m_floats_left.erase(iter); + m_cache_line_left.invalidate(); + } else + { + iter++; + } + } + + iter = m_floats_right.begin(); + while(iter != m_floats_right.end()) + { + if(iter->context >= context) + { + iter = m_floats_right.erase(iter); + m_cache_line_right.invalidate(); + } else + { + iter++; + } + } +} + +int litehtml::formatting_context::get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const +{ + switch(el->src_el()->css().get_clear()) + { + case clear_left: + { + int fh = get_left_floats_height(); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + case clear_right: + { + int fh = get_right_floats_height(); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + case clear_both: + { + int fh = get_floats_height(float_none); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + default: + if(el->src_el()->css().get_float() != float_none) + { + int fh = get_floats_height(el->src_el()->css().get_float()); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + } + return line_top; +} + +int litehtml::formatting_context::find_next_line_top(int top, int width, int def_right ) +{ + top += m_current_top; + def_right += m_current_left; + + int new_top = top; + int_vector points; + + for(const auto& fb : m_floats_left) + { + if(fb.pos.top() >= top) + { + if(find(points.begin(), points.end(), fb.pos.top()) == points.end()) + { + points.push_back(fb.pos.top()); + } + } + if (fb.pos.bottom() >= top) + { + if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) + { + points.push_back(fb.pos.bottom()); + } + } + } + + for (const auto& fb : m_floats_right) + { + if (fb.pos.top() >= top) + { + if (find(points.begin(), points.end(), fb.pos.top()) == points.end()) + { + points.push_back(fb.pos.top()); + } + } + if (fb.pos.bottom() >= top) + { + if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) + { + points.push_back(fb.pos.bottom()); + } + } + } + + if(!points.empty()) + { + sort(points.begin(), points.end(), std::less<int>( )); + new_top = points.back(); + + for(auto pt : points) + { + int pos_left = 0; + int pos_right = def_right; + get_line_left_right(pt - m_current_top, def_right - m_current_left, pos_left, pos_right); + + if(pos_right - pos_left >= width) + { + new_top = pt; + break; + } + } + } + return new_top - m_current_top; +} + +void litehtml::formatting_context::update_floats(int dy, const std::shared_ptr<render_item> &parent) +{ + bool reset_cache = false; + for(auto fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++) + { + if(fb->el->src_el()->is_ancestor(parent->src_el())) + { + reset_cache = true; + fb->pos.y += dy; + } + } + if(reset_cache) + { + m_cache_line_left.invalidate(); + } + reset_cache = false; + for(auto fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++) + { + if(fb->el->src_el()->is_ancestor(parent->src_el())) + { + reset_cache = true; + fb->pos.y += dy; + } + } + if(reset_cache) + { + m_cache_line_right.invalidate(); + } +} + +void litehtml::formatting_context::apply_relative_shift(const containing_block_context &containing_block_size) +{ + for (const auto& fb : m_floats_left) + { + fb.el->apply_relative_shift(containing_block_size); + } +} + +int litehtml::formatting_context::find_min_left(int y, int context_idx) +{ + y += m_current_top; + int min_left = m_current_left; + for(const auto& fb : m_floats_left) + { + if (y >= fb.pos.top() && y < fb.pos.bottom() && fb.context == context_idx) + { + min_left += fb.min_width; + } + } + if(min_left < m_current_left) return 0; + return min_left - m_current_left; +} + +int litehtml::formatting_context::find_min_right(int y, int right, int context_idx) +{ + y += m_current_top; + int min_right = right + m_current_left; + for(const auto& fb : m_floats_right) + { + if (y >= fb.pos.top() && y < fb.pos.bottom() && fb.context == context_idx) + { + min_right -= fb.min_width; + } + } + if(min_right < m_current_left) return 0; + return min_right - m_current_left; +} |