summaryrefslogtreecommitdiff
path: root/libs/litehtml/src/formatting_context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/litehtml/src/formatting_context.cpp')
-rw-r--r--libs/litehtml/src/formatting_context.cpp441
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;
+}