refactor text_renderer

This commit is contained in:
Jinhao
2019-06-20 04:35:29 +08:00
parent ad4c3a3fc3
commit 8a0475c98c
9 changed files with 170 additions and 150 deletions

View File

@@ -46,6 +46,7 @@ namespace nana
}
}
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
{
auto const drawable = graph_.handle();
@@ -66,7 +67,7 @@ namespace nana
auto text_align = text_align_;
// Checks if ellipsis is enabled and the total pixels of string is larger than the space.
if (ellipsis_px_ && (string_px > static_cast<int>(right_ - left_)))
if (ellipsis_px_ && (static_cast<int>(string_px) > right_ - left_))
{
//The string should be drawn from left most point no matter what text align is.
text_align = align::left;
@@ -99,7 +100,7 @@ namespace nana
dummy.bitblt(r, graph_, pos);
#ifdef _nana_std_has_string_view
dummy.string({}, { ent.begin, ent.end - ent.begin }, graph_.palette(true));
dummy.string({}, { ent.begin, static_cast<unsigned>(ent.end - ent.begin) }, graph_.palette(true));
#else
dummy.palette(true, graph_.palette(true));
dummy.string({}, ent.begin, ent.end - ent.begin);
@@ -151,46 +152,54 @@ namespace nana
struct draw_string_auto_changing_lines
{
graphics & graph;
int x, endpos;
align text_align;
const int left, right;
const align text_align;
draw_string_auto_changing_lines(graphics& graph, int x, int endpos, align ta)
: graph(graph), x(x), endpos(endpos), text_align(ta)
draw_string_auto_changing_lines(graphics& graph, int left, int right, align ta):
graph(graph),
left(left),
right(right),
text_align(ta)
{}
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
{
unsigned pixels = 0;
unsigned return_max_height = 0;
auto const dw = graph.handle();
unsigned str_w = 0;
auto const drawable = graph.handle();
unsigned string_px = 0;
std::vector<nana::size> ts_keeper;
std::vector<nana::size> word_metrics;
auto const reordered = unicode_reorder(buf, bufsize);
for(auto & i : reordered)
{
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
if(ts.height > pixels) pixels = ts.height;
ts_keeper.emplace_back(ts);
str_w += ts.width;
auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin);
word_metrics.emplace_back(word_sz);
string_px += word_sz.width;
if (return_max_height < word_sz.height)
return_max_height = word_sz.height;
}
const nana::size* wdm = word_metrics.data();
//Test whether the text needs the new line.
if(x + static_cast<int>(str_w) > endpos)
if(left + static_cast<int>(string_px) > right)
{
pixels = 0;
unsigned line_pixels = 0;
nana::point pos{ x, top };
int orig_top = top;
auto i_ts_keeper = ts_keeper.cbegin();
unsigned max_height = 0;
nana::point pos{ left, top };
const int orig_top = top;
for(auto & i : reordered)
{
if(line_pixels < i_ts_keeper->height)
line_pixels = i_ts_keeper->height;
if(max_height < wdm->height)
max_height = wdm->height;
bool beyond_edge = (pos.x + static_cast<int>(i_ts_keeper->width) > endpos);
bool beyond_edge = (pos.x + static_cast<int>(wdm->width) > right);
if(beyond_edge)
{
const std::size_t len = i.end - i.begin;
@@ -210,10 +219,10 @@ namespace nana
{
auto pxbuf = pixel_buf.get();
idx_splitted = find_splitted(idx_head, len, pos.x, endpos, pxbuf);
idx_splitted = find_splitted(idx_head, len, pos.x, right, pxbuf);
if(idx_splitted == len)
{
detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head);
detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head);
for(std::size_t i = idx_head; i < len; ++i)
pos.x += static_cast<int>(pxbuf[i]);
@@ -223,17 +232,16 @@ namespace nana
//Check the word whether it is splittable.
if(splittable(i.begin, idx_splitted))
{
detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head);
detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head);
idx_head = idx_splitted;
pos.x = x;
pos.y += static_cast<int>(line_pixels);
line_pixels = i_ts_keeper->height;
pos.x = left;
pos.y += static_cast<int>(max_height);
}
else
{
//Search the splittable character from idx_head to idx_splitted
const wchar_t * u = i.begin + idx_splitted;
const wchar_t * head = i.begin + idx_head;
const wchar_t * const head = i.begin + idx_head;
for(; head < u; --u)
{
@@ -243,98 +251,94 @@ namespace nana
if(u != head)
{
detail::draw_string(dw, pos, head, u - head);
detail::draw_string(drawable, pos, head, u - head);
idx_head += u - head;
pos.x = x;
pos.y += static_cast<int>(line_pixels);
line_pixels = i_ts_keeper->height;
pos.x = left;
pos.y += static_cast<int>(max_height);
}
else
{
u = i.begin + idx_splitted;
const wchar_t * end = i.begin + len;
for(; u < end; ++u)
for(; u < i.begin + len; ++u)
{
if(splittable(head, u - head))
break;
}
std::size_t splen = u - head;
pos.y += static_cast<int>(line_pixels);
pos.x = x;
detail::draw_string(dw, pos, head, splen);
line_pixels = i_ts_keeper->height;
pos.y += static_cast<int>(max_height);
pos.x = left;
detail::draw_string(drawable, pos, head, splen);
for(std::size_t k = idx_head; k < idx_head + splen; ++k)
pos.x += static_cast<int>(pxbuf[k]);
if (pos.x >= endpos)
if (pos.x >= right)
{
pos.x = x;
pos.y += static_cast<int>(line_pixels);
pos.x = left;
pos.y += static_cast<int>(wdm->height);
}
idx_head += splen;
}
}
max_height = wdm->height;
}while(idx_head < len);
}
else
{
pos.x = x;
pos.y += static_cast<int>(line_pixels);
detail::draw_string(dw, pos, i.begin, 1);
pos.x += static_cast<int>(i_ts_keeper->width);
pos.x = left;
pos.y += static_cast<int>(max_height);
detail::draw_string(drawable, pos, i.begin, 1);
pos.x += static_cast<int>(wdm->width);
}
line_pixels = 0;
max_height = 0;
}
else
{
detail::draw_string(dw, pos, i.begin, i.end - i.begin);
pos.x += static_cast<int>(i_ts_keeper->width);
detail::draw_string(drawable, pos, i.begin, i.end - i.begin);
pos.x += static_cast<int>(wdm->width);
}
++i_ts_keeper;
++wdm;
}
pixels = (top - orig_top) + line_pixels;
return_max_height = (top - orig_top) + max_height;
}
else
{
point pos{ left, top };
//The text could be drawn in a line.
if((align::left == text_align) || (align::center == text_align))
{
point pos{ x, top };
if(align::center == text_align)
pos.x += (endpos - x - static_cast<int>(str_w)) / 2;
auto i_ts_keeper = ts_keeper.cbegin();
pos.x += (right - left - static_cast<int>(string_px)) / 2;
for(auto & ent : reordered)
{
const nana::size & ts = *i_ts_keeper;
if (pos.x + static_cast<int>(wdm->width) > 0)
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
if (pos.x + static_cast<int>(ts.width) > 0)
detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin);
pos.x += static_cast<int>(ts.width);
++i_ts_keeper;
pos.x += static_cast<int>(wdm->width);
++wdm;
}
}
else if(align::right == text_align)
{
point pos{ endpos, top };
auto i_ts_keeper = ts_keeper.crbegin();
pos.x = right;
for(auto i = reordered.crbegin(); i != reordered.crend(); ++i)
{
if (pos.x < 0)
break;
auto & ent = *i;
std::size_t len = ent.end - ent.begin;
const nana::size & ts = *i_ts_keeper;
pos.x -= static_cast<int>(ts.width);
if (pos.x >= 0)
detail::draw_string(dw, pos, ent.begin, len);
++i_ts_keeper;
pos.x -= static_cast<int>(wdm->width);
detail::draw_string(drawable, pos, ent.begin, len);
++wdm;
}
}
}
return pixels;
return return_max_height;
}
static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf)
@@ -370,44 +374,53 @@ namespace nana
struct extent_auto_changing_lines
{
graphics & graph;
int x, endpos;
const int left, right;
unsigned extents;
extent_auto_changing_lines(graphics& graph, int x, int endpos)
: graph(graph), x(x), endpos(endpos), extents(0)
extent_auto_changing_lines(graphics& graph, int left, int right):
graph(graph),
left(left),
right(right),
extents(0)
{}
unsigned operator()(int top, const wchar_t * buf, std::size_t bufsize)
{
unsigned pixels = 0;
unsigned return_max_height = 0;
drawable_type dw = graph.handle();
unsigned str_w = 0;
std::vector<nana::size> ts_keeper;
auto drawable = graph.handle();
std::vector<nana::size> word_metrics;
unsigned string_px = 0;
auto const reordered = unicode_reorder(buf, bufsize);
for(auto & i : reordered)
{
nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin);
ts_keeper.emplace_back(ts);
str_w += ts.width;
auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin);
word_metrics.emplace_back(word_sz);
string_px += word_sz.width;
if (return_max_height < word_sz.height)
return_max_height = word_sz.height;
}
auto i_ts_keeper = ts_keeper.cbegin();
//Test whether the text needs the new line.
if(x + static_cast<int>(str_w) > endpos)
if(left + static_cast<int>(string_px) > right)
{
unsigned line_pixels = 0;
int xpos = x;
int orig_top = top;
unsigned max_height = 0;
int xpos = left;
const int orig_top = top;
auto wdm = word_metrics.data();
for(auto & i : reordered)
{
if(line_pixels < i_ts_keeper->height)
line_pixels = i_ts_keeper->height;
if(max_height < wdm->height)
max_height = wdm->height;
bool beyond_edge = (xpos + static_cast<int>(i_ts_keeper->width) > endpos);
bool beyond_edge = (xpos + static_cast<int>(wdm->width) > right);
if(beyond_edge)
{
std::size_t len = i.end - i.begin;
@@ -427,7 +440,7 @@ namespace nana
do
{
idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, endpos, pxbuf);
idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, right, pxbuf);
if(idx_splitted == len)
{
@@ -440,9 +453,9 @@ namespace nana
if(draw_string_auto_changing_lines::splittable(i.begin, idx_splitted))
{
idx_head = idx_splitted;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
xpos = left;
top += max_height;
max_height = wdm->height;
}
else
{
@@ -456,14 +469,11 @@ namespace nana
break;
}
if(u != head)
{
idx_head += u - head;
xpos = x;
top += line_pixels;
line_pixels = i_ts_keeper->height;
}
else
xpos = left;
top += max_height;
max_height = wdm->height;
if(u == head)
{
u = i.begin + idx_splitted;
const wchar_t * end = i.begin + len;
@@ -473,52 +483,45 @@ namespace nana
break;
}
std::size_t splen = u - head;
top += line_pixels;
xpos = x;
line_pixels = i_ts_keeper->height;
for(std::size_t k = idx_head; k < idx_head + splen; ++k)
xpos += static_cast<int>(pxbuf[k]);
if(xpos >= endpos)
if(xpos >= right)
{
xpos = x;
top += line_pixels;
xpos = left;
top += max_height;
}
idx_head += splen;
}
else
idx_head += u - head;
}
}while(idx_head < len);
}
else
xpos = x + static_cast<int>(i_ts_keeper->width);
xpos = left + static_cast<int>(wdm->width);
line_pixels = 0;
max_height = 0;
}
else
xpos += static_cast<int>(i_ts_keeper->width);
xpos += static_cast<int>(wdm->width);
++i_ts_keeper;
++wdm;
}
pixels = (top - orig_top) + line_pixels;
return_max_height = (top - orig_top) + max_height;
}
else
{
while(i_ts_keeper != ts_keeper.cend())
{
const nana::size & ts = *(i_ts_keeper++);
if(ts.height > pixels) pixels = ts.height;
}
}
extents += pixels;
return pixels;
extents += return_max_height;
return return_max_height;
}
};
}//end namespace helper
//class text_renderer
text_renderer::text_renderer(graph_reference graph, align ta)
: graph_(graph), text_align_(ta)
text_renderer::text_renderer(graph_reference graph, align ta):
graph_(graph),
text_align_(ta)
{}
nana::size text_renderer::extent_size(int x, int y, const wchar_t* str, std::size_t len, unsigned restricted_pixels) const
@@ -538,26 +541,25 @@ namespace nana
{
if (graph_)
{
helper::string_drawer sd{ graph_, pos.x, static_cast<int>(graph_.width()), text_align_, false };
helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast<int>(graph_.width()), text_align_, false };
helper::for_each_line(str, len, pos.y, sd);
}
}
void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned restricted_pixels, bool omitted)
void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned space_pixels, mode rendering_mode)
{
if (graph_)
if (graph_ && str && len && space_pixels)
{
helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), text_align_, omitted };
helper::for_each_line(str, len, pos.y, sd);
}
}
void text_renderer::render(const point& pos, const wchar_t * str, std::size_t len, unsigned restricted_pixels)
{
if (graph_)
{
helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), text_align_);
helper::for_each_line(str, len, pos.y, dsacl);
if (mode::truncate_letter_with_ellipsis == rendering_mode || mode::truncate_with_ellipsis == rendering_mode)
{
helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast<int>(space_pixels), text_align_, true };
helper::for_each_line(str, len, pos.y, sd);
}
else if (mode::word_wrap == rendering_mode)
{
helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast<int>(space_pixels), text_align_);
helper::for_each_line(str, len, pos.y, dsacl);
}
}
}
//end class text_renderer