#include "html.h"
#include "flex_item.h"
#include "render_item.h"
#include "flex_line.h"
#include
void litehtml::flex_item::init(const litehtml::containing_block_context &self_size,
litehtml::formatting_context *fmt_ctx, flex_align_items align_items)
{
grow = (int) std::nearbyint(el->css().get_flex_grow() * 1000.0);
// Negative numbers are invalid.
// https://www.w3.org/TR/css-flexbox-1/#valdef-flex-grow-number
if(grow < 0) grow = 0;
shrink = (int) std::nearbyint(el->css().get_flex_shrink() * 1000.0);
// Negative numbers are invalid.
// https://www.w3.org/TR/css-flexbox-1/#valdef-flex-shrink-number
if(shrink < 0) shrink = 1000;
el->calc_outlines(self_size.render_width);
order = el->css().get_order();
direction_specific_init(self_size, fmt_ctx);
if (el->css().get_flex_align_self() == flex_align_items_auto)
{
align = align_items;
} else
{
align = el->css().get_flex_align_self();
}
main_size = base_size;
scaled_flex_shrink_factor = base_size * shrink;
frozen = false;
}
void litehtml::flex_item::place(flex_line &ln, int main_pos,
const containing_block_context &self_size,
formatting_context *fmt_ctx)
{
apply_main_auto_margins();
set_main_position(main_pos);
if(!apply_cross_auto_margins(ln.cross_size))
{
switch (align & 0xFF)
{
case flex_align_items_baseline:
align_baseline(ln, self_size, fmt_ctx);
break;
case flex_align_items_flex_end:
if(ln.reverse_cross)
{
/// If cross axis is reversed position item from start
set_cross_position(ln.cross_start);
} else
{
set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
}
break;
case flex_align_items_end:
set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
break;
case flex_align_items_center:
set_cross_position(ln.cross_start + ln.cross_size / 2 - get_el_cross_size() / 2);
break;
case flex_align_items_flex_start:
if(ln.reverse_cross) /// If cross axis is reversed position item from end
{
set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
} else
{
set_cross_position(ln.cross_start);
}
break;
case flex_align_items_start:
set_cross_position(ln.cross_start);
break;
default:
align_stretch(ln, self_size, fmt_ctx);
break;
}
}
}
int litehtml::flex_item::get_last_baseline(baseline::_baseline_type type) const
{
if(type == baseline::baseline_type_top)
{
return el->get_last_baseline();
} else if(type == baseline::baseline_type_bottom)
{
return el->height() - el->get_last_baseline();
}
return 0;
}
int litehtml::flex_item::get_first_baseline(litehtml::baseline::_baseline_type type) const
{
if(type == baseline::baseline_type_top)
{
return el->get_first_baseline();
} else if(type == baseline::baseline_type_bottom)
{
return el->height() - el->get_first_baseline();
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////
void litehtml::flex_item_row_direction::direction_specific_init(const litehtml::containing_block_context &self_size,
litehtml::formatting_context *fmt_ctx)
{
if(el->css().get_margins().left.is_predefined())
{
auto_margin_main_start = 0;
}
if(el->css().get_margins().right.is_predefined())
{
auto_margin_main_end = 0;
}
if(el->css().get_margins().top.is_predefined())
{
auto_margin_cross_start = true;
}
if(el->css().get_margins().bottom.is_predefined())
{
auto_margin_cross_end = true;
}
def_value content_size(0);
if (el->css().get_min_width().is_predefined())
{
min_size = el->render(0, 0,
self_size.new_width(el->content_offset_width(),
containing_block_context::size_mode_content), fmt_ctx);
content_size = min_size;
} else
{
min_size = el->css().get_min_width().calc_percent(self_size.render_width) +
el->content_offset_width();
}
if (!el->css().get_max_width().is_predefined())
{
max_size = el->css().get_max_width().calc_percent(self_size.render_width) +
el->content_offset_width();
}
bool flex_basis_predefined = el->css().get_flex_basis().is_predefined();
int predef = flex_basis_auto;
if(flex_basis_predefined)
{
predef = el->css().get_flex_basis().predef();
} else
{
if(el->css().get_flex_basis().val() < 0)
{
flex_basis_predefined = true;
}
}
if (flex_basis_predefined)
{
if(predef == flex_basis_auto && el->css().get_width().is_predefined())
{
// if width is not predefined, use content size as base size
predef = flex_basis_content;
}
switch (predef)
{
case flex_basis_auto:
base_size = el->css().get_width().calc_percent(self_size.render_width) +
el->render_offset_width();
break;
case flex_basis_fit_content:
case flex_basis_content:
base_size = el->render(0, 0, self_size.new_width(self_size.render_width + el->content_offset_width(),
containing_block_context::size_mode_content |
containing_block_context::size_mode_exact_width),
fmt_ctx);
break;
case flex_basis_min_content:
if(content_size.is_default())
{
content_size = el->render(0, 0,
self_size.new_width(el->content_offset_width(),
containing_block_context::size_mode_content),
fmt_ctx);
}
base_size = content_size;
break;
case flex_basis_max_content:
el->render(0, 0, self_size, fmt_ctx);
base_size = el->width();
break;
default:
base_size = 0;
break;
}
} else
{
base_size = el->css().get_flex_basis().calc_percent(self_size.render_width) +
el->content_offset_width();
base_size = std::max(base_size, min_size);
}
}
void litehtml::flex_item_row_direction::apply_main_auto_margins()
{
// apply auto margins to item
if(!auto_margin_main_start.is_default())
{
el->get_margins().left = auto_margin_main_start;
el->pos().x += auto_margin_main_start;
}
if(!auto_margin_main_end.is_default()) el->get_margins().right = auto_margin_main_end;
}
bool litehtml::flex_item_row_direction::apply_cross_auto_margins(int cross_size)
{
if(auto_margin_cross_end || auto_margin_cross_start)
{
int margins_num = 0;
if(auto_margin_cross_end)
{
margins_num++;
}
if(auto_margin_cross_start)
{
margins_num++;
}
int margin = (cross_size - el->height()) / margins_num;
if(auto_margin_cross_start)
{
el->get_margins().top = margin;
el->pos().y = el->content_offset_top();
}
if(auto_margin_cross_end)
{
el->get_margins().bottom = margin;
}
return true;
}
return false;
}
void litehtml::flex_item_row_direction::set_main_position(int pos)
{
el->pos().x = pos + el->content_offset_left();
}
void litehtml::flex_item_row_direction::set_cross_position(int pos)
{
el->pos().y = pos + el->content_offset_top();
}
void litehtml::flex_item_row_direction::align_stretch(flex_line &ln, const containing_block_context &self_size,
formatting_context *fmt_ctx)
{
set_cross_position(ln.cross_start);
if (el->css().get_height().is_predefined())
{
el->render(el->left(), el->top(), self_size.new_width_height(
el->pos().width + el->box_sizing_width(),
ln.cross_size - el->content_offset_height() + el->box_sizing_height(),
containing_block_context::size_mode_exact_width |
containing_block_context::size_mode_exact_height
), fmt_ctx);
apply_main_auto_margins();
}
}
void litehtml::flex_item_row_direction::align_baseline(litehtml::flex_line &ln,
const containing_block_context &/*self_size*/,
formatting_context */*fmt_ctx*/)
{
if (align & flex_align_items_last)
{
set_cross_position(ln.cross_start + ln.last_baseline.get_offset_from_top(ln.cross_size) - el->get_last_baseline());
} else
{
set_cross_position(ln.cross_start + ln.first_baseline.get_offset_from_top(ln.cross_size) - el->get_first_baseline());
}
}
int litehtml::flex_item_row_direction::get_el_main_size()
{
return el->width();
}
int litehtml::flex_item_row_direction::get_el_cross_size()
{
return el->height();
}
////////////////////////////////////////////////////////////////////////////////////
void litehtml::flex_item_column_direction::direction_specific_init(const litehtml::containing_block_context &self_size,
litehtml::formatting_context *fmt_ctx)
{
if(el->css().get_margins().top.is_predefined())
{
auto_margin_main_start = 0;
}
if(el->css().get_margins().bottom.is_predefined())
{
auto_margin_main_end = 0;
}
if(el->css().get_margins().left.is_predefined())
{
auto_margin_cross_start = true;
}
if(el->css().get_margins().right.is_predefined())
{
auto_margin_cross_end = true;
}
if (el->css().get_min_height().is_predefined())
{
el->render(0, 0, self_size.new_width(self_size.render_width, containing_block_context::size_mode_content), fmt_ctx);
min_size = el->height();
} else
{
min_size = el->css().get_min_height().calc_percent(self_size.height) +
el->content_offset_height();
}
if (!el->css().get_max_height().is_predefined())
{
max_size = el->css().get_max_height().calc_percent(self_size.height) +
el->content_offset_width();
}
bool flex_basis_predefined = el->css().get_flex_basis().is_predefined();
int predef = flex_basis_auto;
if(flex_basis_predefined)
{
predef = el->css().get_flex_basis().predef();
} else
{
if(el->css().get_flex_basis().val() < 0)
{
flex_basis_predefined = true;
}
}
if (flex_basis_predefined)
{
if(predef == flex_basis_auto && el->css().get_height().is_predefined())
{
predef = flex_basis_fit_content;
}
switch (predef)
{
case flex_basis_auto:
base_size = el->css().get_height().calc_percent(self_size.height) +
el->content_offset_height();
break;
case flex_basis_max_content:
case flex_basis_fit_content:
el->render(0, 0, self_size, fmt_ctx);
base_size = el->height();
break;
case flex_basis_min_content:
base_size = min_size;
break;
default:
base_size = 0;
}
} else
{
if(el->css().get_flex_basis().units() == css_units_percentage)
{
if(self_size.height.type == containing_block_context::cbc_value_type_absolute)
{
base_size = el->css().get_flex_basis().calc_percent(self_size.height) +
el->content_offset_height();
} else
{
base_size = 0;
}
} else
{
base_size = (int) el->css().get_flex_basis().val() + el->content_offset_height();
}
base_size = std::max(base_size, min_size);
}
}
void litehtml::flex_item_column_direction::apply_main_auto_margins()
{
// apply auto margins to item
if(!auto_margin_main_start.is_default())
{
el->get_margins().top = auto_margin_main_start;
el->pos().y += auto_margin_main_start;
}
if(!auto_margin_main_end.is_default()) el->get_margins().bottom = auto_margin_main_end;
}
bool litehtml::flex_item_column_direction::apply_cross_auto_margins(int cross_size)
{
if(auto_margin_cross_end || auto_margin_cross_start)
{
int margins_num = 0;
if(auto_margin_cross_end)
{
margins_num++;
}
if(auto_margin_cross_start)
{
margins_num++;
}
int margin = (cross_size - el->width()) / margins_num;
if(auto_margin_cross_start)
{
el->get_margins().left = margin;
el->pos().x += el->content_offset_left();
}
if(auto_margin_cross_end)
{
el->get_margins().right = margin;
}
}
return false;
}
void litehtml::flex_item_column_direction::set_main_position(int pos)
{
el->pos().y = pos + el->content_offset_top();
}
void litehtml::flex_item_column_direction::set_cross_position(int pos)
{
el->pos().x = pos + el->content_offset_left();
}
void litehtml::flex_item_column_direction::align_stretch(flex_line &ln, const containing_block_context &self_size,
formatting_context *fmt_ctx)
{
/// MAIN: Y
/// CROSS: X
if (!el->css().get_width().is_predefined())
{
el->render(ln.cross_start,
el->pos().y - el->content_offset_top(),
self_size.new_width_height(ln.cross_size - el->content_offset_width() + el->box_sizing_width(),
main_size - el->content_offset_height() + el->box_sizing_height(),
containing_block_context::size_mode_exact_height),
fmt_ctx, false);
} else
{
el->render(ln.cross_start,
el->pos().y - el->content_offset_top(),
self_size.new_width_height(
ln.cross_size - el->content_offset_width() + el->box_sizing_width(),
main_size - el->content_offset_height() + el->box_sizing_height(),
containing_block_context::size_mode_exact_width |
containing_block_context::size_mode_exact_height),
fmt_ctx, false);
}
/// Apply auto margins after rendering
apply_main_auto_margins();
}
void litehtml::flex_item_column_direction::align_baseline(litehtml::flex_line &ln,
const containing_block_context &/*self_size*/,
formatting_context */*fmt_ctx*/)
{
// The fallback alignment for first baseline is start, the one for last baseline is end.
if(align & flex_align_items_last)
{
if(ln.reverse_cross)
{
set_cross_position(ln.cross_start);
} else
{
set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
}
} else
{
if(!ln.reverse_cross)
{
set_cross_position(ln.cross_start);
} else
{
set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
}
}
}
int litehtml::flex_item_column_direction::get_el_main_size()
{
return el->height();
}
int litehtml::flex_item_column_direction::get_el_cross_size()
{
return el->width();
}