mirror of
https://github.com/pdf2htmlEX/pdf2htmlEX.git
synced 2024-07-05 01:28:39 +00:00
fix space optimization
This commit is contained in:
parent
0268a9d966
commit
495b04f046
|
@ -29,7 +29,7 @@ using std::endl;
|
||||||
using std::find;
|
using std::find;
|
||||||
using std::abs;
|
using std::abs;
|
||||||
|
|
||||||
void HTMLRenderer::TextLineBuffer::reset(GfxState * state)
|
void HTMLRenderer::TextLineBuffer::set_pos(GfxState * state)
|
||||||
{
|
{
|
||||||
state->transform(state->getCurX(), state->getCurY(), &x, &y);
|
state->transform(state->getCurX(), state->getCurY(), &x, &y);
|
||||||
tm_id = renderer->transform_matrix_manager.get_id();
|
tm_id = renderer->transform_matrix_manager.get_id();
|
||||||
|
@ -94,15 +94,15 @@ void HTMLRenderer::TextLineBuffer::flush(void)
|
||||||
offsets.push_back(Offset({text.size(), 0}));
|
offsets.push_back(Offset({text.size(), 0}));
|
||||||
|
|
||||||
ostream & out = renderer->f_pages.fs;
|
ostream & out = renderer->f_pages.fs;
|
||||||
renderer->height_manager.install(max_ascent);
|
long long hid = renderer->height_manager.install(max_ascent);
|
||||||
renderer->left_manager .install(x);
|
long long lid = renderer->left_manager .install(x);
|
||||||
renderer->bottom_manager.install(y);
|
long long bid = renderer->bottom_manager.install(y);
|
||||||
|
|
||||||
out << "<div class=\"" << CSS::LINE_CN
|
out << "<div class=\"" << CSS::LINE_CN
|
||||||
<< " " << CSS::TRANSFORM_MATRIX_CN << tm_id
|
<< " " << CSS::TRANSFORM_MATRIX_CN << tm_id
|
||||||
<< " " << CSS::LEFT_CN << renderer->left_manager .get_id()
|
<< " " << CSS::LEFT_CN << lid
|
||||||
<< " " << CSS::HEIGHT_CN << renderer->height_manager.get_id()
|
<< " " << CSS::HEIGHT_CN << hid
|
||||||
<< " " << CSS::BOTTOM_CN << renderer->bottom_manager.get_id()
|
<< " " << CSS::BOTTOM_CN << bid
|
||||||
<< "\">";
|
<< "\">";
|
||||||
|
|
||||||
auto cur_state_iter = states.begin();
|
auto cur_state_iter = states.begin();
|
||||||
|
@ -180,10 +180,7 @@ void HTMLRenderer::TextLineBuffer::flush(void)
|
||||||
|
|
||||||
if(!done)
|
if(!done)
|
||||||
{
|
{
|
||||||
auto & wm = renderer->whitespace_manager;
|
long long wid = renderer->whitespace_manager.install(target, &actual_offset);
|
||||||
wm.install(target);
|
|
||||||
auto wid = wm.get_id();
|
|
||||||
actual_offset = wm.get_actual_value();
|
|
||||||
|
|
||||||
if(!equal(actual_offset, 0))
|
if(!equal(actual_offset, 0))
|
||||||
{
|
{
|
||||||
|
@ -217,11 +214,9 @@ void HTMLRenderer::TextLineBuffer::flush(void)
|
||||||
|
|
||||||
out << "</div>";
|
out << "</div>";
|
||||||
|
|
||||||
|
|
||||||
states.clear();
|
states.clear();
|
||||||
offsets.clear();
|
offsets.clear();
|
||||||
text.clear();
|
text.clear();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLRenderer::TextLineBuffer::set_state (State & state)
|
void HTMLRenderer::TextLineBuffer::set_state (State & state)
|
||||||
|
@ -242,9 +237,6 @@ void HTMLRenderer::TextLineBuffer::set_state (State & state)
|
||||||
|
|
||||||
void HTMLRenderer::TextLineBuffer::optimize(void)
|
void HTMLRenderer::TextLineBuffer::optimize(void)
|
||||||
{
|
{
|
||||||
// need more work
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(!states.empty());
|
assert(!states.empty());
|
||||||
|
|
||||||
// set proper hash_umask
|
// set proper hash_umask
|
||||||
|
@ -291,43 +283,45 @@ void HTMLRenderer::TextLineBuffer::optimize(void)
|
||||||
avg_width += iter->width;
|
avg_width += iter->width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
avg_width /= posive_offset_count;
|
|
||||||
|
|
||||||
// now check if the width of offsets are close enough
|
if(posive_offset_count > 0)
|
||||||
// TODO: it might make more sense if the threshold is proportion to the font size
|
|
||||||
bool ok = true;
|
|
||||||
double accum_off = 0;
|
|
||||||
double orig_accum_off = 0;
|
|
||||||
for(auto iter = offsets.begin(); iter != offsets.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
orig_accum_off += iter->width;
|
avg_width /= posive_offset_count;
|
||||||
accum_off += avg_width;
|
|
||||||
if(is_positive(iter->width) && abs(orig_accum_off - accum_off) >= renderer->param->h_eps)
|
// now check if the width of offsets are close enough
|
||||||
{
|
// TODO: it might make more sense if the threshold is proportion to the font size
|
||||||
ok = false;
|
bool ok = true;
|
||||||
break;
|
double accum_off = 0;
|
||||||
}
|
double orig_accum_off = 0;
|
||||||
}
|
|
||||||
if(ok)
|
|
||||||
{
|
|
||||||
// ok, make all offsets equi-width
|
|
||||||
for(auto iter = offsets.begin(); iter != offsets.end(); ++iter)
|
for(auto iter = offsets.begin(); iter != offsets.end(); ++iter)
|
||||||
{
|
{
|
||||||
if(is_positive(iter->width))
|
orig_accum_off += iter->width;
|
||||||
iter->width = avg_width;
|
accum_off += avg_width;
|
||||||
|
if(is_positive(iter->width) && abs(orig_accum_off - accum_off) >= renderer->param->h_eps)
|
||||||
|
{
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// set new word_space
|
if(ok)
|
||||||
for(auto iter = states.begin(); iter != states.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
double new_word_space = avg_width - iter->single_space_offset() + iter->word_space;
|
// ok, make all offsets equi-width
|
||||||
|
for(auto iter = offsets.begin(); iter != offsets.end(); ++iter)
|
||||||
|
{
|
||||||
|
if(is_positive(iter->width))
|
||||||
|
iter->width = avg_width;
|
||||||
|
}
|
||||||
|
// set new word_space
|
||||||
|
for(auto iter = states.begin(); iter != states.end(); ++iter)
|
||||||
|
{
|
||||||
|
iter->word_space = 0;
|
||||||
|
double new_word_space = avg_width - iter->single_space_offset();
|
||||||
|
|
||||||
// install new word_space
|
// install new word_space
|
||||||
// we might introduce more variance here
|
// we might introduce more variance here
|
||||||
auto & wm = renderer->word_space_manager;
|
iter->ids[State::WORD_SPACE_ID] = renderer->word_space_manager.install(new_word_space, &(iter->word_space));
|
||||||
wm.install(new_word_space);
|
iter->hash_umask &= (~word_space_umask);
|
||||||
iter->ids[State::WORD_SPACE_ID] = wm.get_id();
|
}
|
||||||
iter->word_space = wm.get_actual_value();
|
|
||||||
iter->hash_umask &= (~word_space_umask);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
double width;
|
double width;
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset(GfxState * state);
|
void set_pos(GfxState * state);
|
||||||
void append_unicodes(const Unicode * u, int l);
|
void append_unicodes(const Unicode * u, int l);
|
||||||
void append_offset(double width);
|
void append_offset(double width);
|
||||||
void append_state(void);
|
void append_state(void);
|
||||||
|
|
|
@ -372,7 +372,7 @@ void HTMLRenderer::css_draw_rectangle(double x, double y, double w, double h, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transform_matrix_manager.install(new_tm);
|
transform_matrix_manager.update(new_tm);
|
||||||
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN
|
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN
|
||||||
<< ' ' << CSS::TRANSFORM_MATRIX_CN << transform_matrix_manager.get_id()
|
<< ' ' << CSS::TRANSFORM_MATRIX_CN << transform_matrix_manager.get_id()
|
||||||
<< "\" style=\"";
|
<< "\" style=\"";
|
||||||
|
|
|
@ -203,17 +203,15 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
||||||
const char * used_map = nullptr;
|
const char * used_map = nullptr;
|
||||||
|
|
||||||
info.em_size = ffw_get_em_size();
|
info.em_size = ffw_get_em_size();
|
||||||
|
info.space_width = 0;
|
||||||
|
|
||||||
if(!font->isCIDFont())
|
if(!font->isCIDFont())
|
||||||
{
|
{
|
||||||
font_8bit = dynamic_cast<Gfx8BitFont*>(font);
|
font_8bit = dynamic_cast<Gfx8BitFont*>(font);
|
||||||
info.space_width = font_8bit->getWidth(' ');
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
font_cid = dynamic_cast<GfxCIDFont*>(font);
|
font_cid = dynamic_cast<GfxCIDFont*>(font);
|
||||||
char buf[2] = {0, ' '};
|
|
||||||
info.space_width = font_cid->getWidth(buf, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(get_metric_only)
|
if(get_metric_only)
|
||||||
|
@ -343,47 +341,44 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
||||||
* Traverse all possible codes
|
* Traverse all possible codes
|
||||||
*/
|
*/
|
||||||
bool retried = false; // avoid infinite loop
|
bool retried = false; // avoid infinite loop
|
||||||
for(int i = 0; i <= maxcode; ++i)
|
for(int cur_code = 0; cur_code <= maxcode; ++cur_code)
|
||||||
{
|
{
|
||||||
if(!used_map[i])
|
if(!used_map[cur_code])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip glyphs without names (only for non-ttf fonts)
|
* Skip glyphs without names (only for non-ttf fonts)
|
||||||
*/
|
*/
|
||||||
if(!is_truetype && (font_8bit != nullptr)
|
if(!is_truetype && (font_8bit != nullptr)
|
||||||
&& (font_8bit->getCharName(i) == nullptr))
|
&& (font_8bit->getCharName(cur_code) == nullptr))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int k = i;
|
int mapped_code = cur_code;
|
||||||
if(code2GID)
|
if(code2GID)
|
||||||
{
|
{
|
||||||
// for fonts with GID (e.g. TTF) we need to map GIDs instead of codes
|
// for fonts with GID (e.g. TTF) we need to map GIDs instead of codes
|
||||||
if((k = code2GID[i]) == 0) continue;
|
if((mapped_code = code2GID[cur_code]) == 0) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(k > max_key)
|
if(mapped_code > max_key)
|
||||||
max_key = k;
|
max_key = mapped_code;
|
||||||
|
|
||||||
Unicode u, *pu=&u;
|
Unicode u, *pu=&u;
|
||||||
if(info.use_tounicode)
|
if(info.use_tounicode)
|
||||||
{
|
{
|
||||||
int n = ctu ? (ctu->mapToUnicode(i, &pu)) : 0;
|
int n = ctu ? (ctu->mapToUnicode(cur_code, &pu)) : 0;
|
||||||
u = check_unicode(pu, n, i, font);
|
u = check_unicode(pu, n, cur_code, font);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u = unicode_from_font(i, font);
|
u = unicode_from_font(cur_code, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(u == ' ')
|
|
||||||
has_space = true;
|
|
||||||
|
|
||||||
if(codeset.insert(u).second)
|
if(codeset.insert(u).second)
|
||||||
{
|
{
|
||||||
cur_mapping[k] = u;
|
cur_mapping[mapped_code] = u;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -400,7 +395,7 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
||||||
//TODO: constant for the length
|
//TODO: constant for the length
|
||||||
memset(cur_mapping, -1, 0x10000 * sizeof(*cur_mapping));
|
memset(cur_mapping, -1, 0x10000 * sizeof(*cur_mapping));
|
||||||
memset(width_list, -1, 0x10000 * sizeof(*width_list));
|
memset(width_list, -1, 0x10000 * sizeof(*width_list));
|
||||||
i = -1;
|
cur_code = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,16 +407,26 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(font_8bit)
|
|
||||||
{
|
{
|
||||||
width_list[k] = (int)floor(font_8bit->getWidth(i) * info.em_size + 0.5);
|
double cur_width = 0;
|
||||||
}
|
if(font_8bit)
|
||||||
else
|
{
|
||||||
{
|
cur_width = font_8bit->getWidth(cur_code);
|
||||||
char buf[2];
|
}
|
||||||
buf[0] = (i >> 8) & 0xff;
|
else
|
||||||
buf[1] = (i & 0xff);
|
{
|
||||||
width_list[k] = (int)floor(font_cid->getWidth(buf, 2) * info.em_size + 0.5);
|
char buf[2];
|
||||||
|
buf[0] = (cur_code >> 8) & 0xff;
|
||||||
|
buf[1] = (cur_code & 0xff);
|
||||||
|
cur_width = font_cid->getWidth(buf, 2) ;
|
||||||
|
}
|
||||||
|
width_list[mapped_code] = (int)floor(cur_width * info.em_size + 0.5);
|
||||||
|
|
||||||
|
if(u == ' ')
|
||||||
|
{
|
||||||
|
has_space = true;
|
||||||
|
info.space_width = cur_width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,6 +439,15 @@ void HTMLRenderer::embed_font(const string & filepath, GfxFont * font, FontInfo
|
||||||
// Might be a problem if ' ' is in the font, but not empty
|
// Might be a problem if ' ' is in the font, but not empty
|
||||||
if(!has_space)
|
if(!has_space)
|
||||||
{
|
{
|
||||||
|
if(font_8bit)
|
||||||
|
{
|
||||||
|
info.space_width = font_8bit->getWidth(' ');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buf[2] = {0, ' '};
|
||||||
|
info.space_width = font_cid->getWidth(buf, 2);
|
||||||
|
}
|
||||||
ffw_add_empty_char((int32_t)' ', (int)floor(info.space_width * info.em_size + 0.5));
|
ffw_add_empty_char((int32_t)' ', (int)floor(info.space_width * info.em_size + 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,12 +164,12 @@ void HTMLRenderer::startPage(int pageNum, GfxState *state, XRef * xref)
|
||||||
|
|
||||||
this->pageNum = pageNum;
|
this->pageNum = pageNum;
|
||||||
|
|
||||||
width_manager.install(state->getPageWidth());
|
long long wid = width_manager.install(state->getPageWidth());
|
||||||
height_manager.install(state->getPageHeight());
|
long long hid = height_manager.install(state->getPageHeight());
|
||||||
f_pages.fs
|
f_pages.fs
|
||||||
<< "<div class=\"" << CSS::PAGE_DECORATION_CN
|
<< "<div class=\"" << CSS::PAGE_DECORATION_CN
|
||||||
<< " " << CSS::WIDTH_CN << width_manager.get_id()
|
<< " " << CSS::WIDTH_CN << wid
|
||||||
<< " " << CSS::HEIGHT_CN << height_manager.get_id()
|
<< " " << CSS::HEIGHT_CN << hid
|
||||||
<< "\">"
|
<< "\">"
|
||||||
<< "<div id=\"" << CSS::PAGE_FRAME_CN << pageNum
|
<< "<div id=\"" << CSS::PAGE_FRAME_CN << pageNum
|
||||||
<< "\" class=\"" << CSS::PAGE_FRAME_CN
|
<< "\" class=\"" << CSS::PAGE_FRAME_CN
|
||||||
|
|
|
@ -205,7 +205,7 @@ void HTMLRenderer::processLink(AnnotLink * al)
|
||||||
f_pages.fs << ">";
|
f_pages.fs << ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
transform_matrix_manager.install(default_ctm);
|
transform_matrix_manager.update(default_ctm);
|
||||||
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN << ' ' << CSS::TRANSFORM_MATRIX_CN
|
f_pages.fs << "<div class=\"" << CSS::CSS_DRAW_CN << ' ' << CSS::TRANSFORM_MATRIX_CN
|
||||||
<< transform_matrix_manager.get_id()
|
<< transform_matrix_manager.get_id()
|
||||||
<< "\" style=\"";
|
<< "\" style=\"";
|
||||||
|
|
|
@ -253,11 +253,11 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||||
draw_text_scale = new_draw_text_scale;
|
draw_text_scale = new_draw_text_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(font_size_manager.install(new_draw_font_size))
|
if(font_size_manager.update(new_draw_font_size))
|
||||||
{
|
{
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||||
}
|
}
|
||||||
if(transform_matrix_manager.install(new_draw_text_tm))
|
if(transform_matrix_manager.update(new_draw_text_tm))
|
||||||
{
|
{
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_DIV);
|
new_line_state = max<NewLineState>(new_line_state, NLS_DIV);
|
||||||
}
|
}
|
||||||
|
@ -334,7 +334,7 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||||
// letter space
|
// letter space
|
||||||
// depends: draw_text_scale
|
// depends: draw_text_scale
|
||||||
if((all_changed || letter_space_changed || draw_text_scale_changed)
|
if((all_changed || letter_space_changed || draw_text_scale_changed)
|
||||||
&& (letter_space_manager.install(state->getCharSpace() * draw_text_scale)))
|
&& (letter_space_manager.update(state->getCharSpace() * draw_text_scale)))
|
||||||
{
|
{
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||||
}
|
}
|
||||||
|
@ -342,7 +342,7 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||||
// word space
|
// word space
|
||||||
// depends draw_text_scale
|
// depends draw_text_scale
|
||||||
if((all_changed || word_space_changed || draw_text_scale_changed)
|
if((all_changed || word_space_changed || draw_text_scale_changed)
|
||||||
&& (word_space_manager.install(state->getWordSpace() * draw_text_scale)))
|
&& (word_space_manager.update(state->getWordSpace() * draw_text_scale)))
|
||||||
{
|
{
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||||
}
|
}
|
||||||
|
@ -360,11 +360,11 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||||
{
|
{
|
||||||
GfxRGB new_color;
|
GfxRGB new_color;
|
||||||
state->getFillRGB(&new_color);
|
state->getFillRGB(&new_color);
|
||||||
changed = fill_color_manager.install(new_color);
|
changed = fill_color_manager.update(new_color);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
changed = fill_color_manager.install_transparent();
|
changed = fill_color_manager.update_transparent();
|
||||||
}
|
}
|
||||||
if(changed)
|
if(changed)
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||||
|
@ -384,11 +384,11 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||||
{
|
{
|
||||||
GfxRGB new_color;
|
GfxRGB new_color;
|
||||||
state->getStrokeRGB(&new_color);
|
state->getStrokeRGB(&new_color);
|
||||||
changed = stroke_color_manager.install(new_color);
|
changed = stroke_color_manager.update(new_color);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
changed = stroke_color_manager.install_transparent();
|
changed = stroke_color_manager.update_transparent();
|
||||||
}
|
}
|
||||||
if(changed)
|
if(changed)
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||||
|
@ -397,7 +397,7 @@ void HTMLRenderer::check_state_change(GfxState * state)
|
||||||
// rise
|
// rise
|
||||||
// depends draw_text_scale
|
// depends draw_text_scale
|
||||||
if((all_changed || rise_changed || draw_text_scale_changed)
|
if((all_changed || rise_changed || draw_text_scale_changed)
|
||||||
&& (rise_manager.install(state->getRise() * draw_text_scale)))
|
&& (rise_manager.update(state->getRise() * draw_text_scale)))
|
||||||
{
|
{
|
||||||
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
||||||
}
|
}
|
||||||
|
@ -416,7 +416,7 @@ void HTMLRenderer::prepare_text_line(GfxState * state)
|
||||||
{
|
{
|
||||||
close_text_line();
|
close_text_line();
|
||||||
|
|
||||||
text_line_buf->reset(state);
|
text_line_buf->set_pos(state);
|
||||||
|
|
||||||
//resync position
|
//resync position
|
||||||
draw_ty = cur_ty;
|
draw_ty = cur_ty;
|
||||||
|
|
|
@ -38,23 +38,44 @@ public:
|
||||||
|
|
||||||
// usually called at the beginning of a page
|
// usually called at the beginning of a page
|
||||||
void reset(void) {
|
void reset(void) {
|
||||||
_install(imp->default_value());
|
cur_value = imp->default_value();
|
||||||
|
cur_id = install(cur_value, &cur_actual_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* install new_value if changed (equal() should be faster than map::lower_bound)
|
* update the current state, which will be installed automatically
|
||||||
* return if the state has been indeed changed
|
* return if the state has been indeed changed
|
||||||
*/
|
*/
|
||||||
bool install(double new_value) {
|
bool update(double new_value) {
|
||||||
if(equal(new_value, value))
|
if(equal(new_value, cur_value))
|
||||||
return false;
|
return false;
|
||||||
_install(new_value);
|
cur_value = new_value;
|
||||||
|
cur_id = install(cur_value, &cur_actual_value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long get_id (void) const { return id; }
|
// install new_value into the map, but do not update the state
|
||||||
double get_value (void) const { return value; }
|
// return the corresponding id, and set
|
||||||
double get_actual_value (void) const { return actual_value; }
|
long long install(double new_value, double * actual_value_ptr = nullptr) {
|
||||||
|
auto iter = value_map.lower_bound(new_value - eps);
|
||||||
|
if((iter != value_map.end()) && (abs(iter->first - new_value) <= eps))
|
||||||
|
{
|
||||||
|
if(actual_value_ptr != nullptr)
|
||||||
|
*actual_value_ptr = iter->first;
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long id = value_map.size();
|
||||||
|
double v = value_map.insert(std::make_pair(new_value, id)).first->first;
|
||||||
|
if(actual_value_ptr != nullptr)
|
||||||
|
*actual_value_ptr = v;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current state
|
||||||
|
long long get_id (void) const { return cur_id; }
|
||||||
|
double get_value (void) const { return cur_value; }
|
||||||
|
double get_actual_value (void) const { return cur_actual_value; }
|
||||||
|
|
||||||
void dump_css(std::ostream & out) {
|
void dump_css(std::ostream & out) {
|
||||||
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
|
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
|
||||||
|
@ -75,34 +96,19 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// this version of install does not check if value has been updated
|
|
||||||
// return if a new entry has been created
|
|
||||||
bool _install(double new_value) {
|
|
||||||
value = new_value;
|
|
||||||
|
|
||||||
auto iter = value_map.lower_bound(new_value - eps);
|
|
||||||
if((iter != value_map.end()) && (abs(iter->first - value) <= eps))
|
|
||||||
{
|
|
||||||
actual_value = iter->first;
|
|
||||||
id = iter->second;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
id = value_map.size();
|
|
||||||
actual_value = value_map.insert(std::make_pair(new_value, id)).first->first;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
double eps;
|
double eps;
|
||||||
Imp * imp;
|
Imp * imp;
|
||||||
|
|
||||||
long long id;
|
long long cur_id;
|
||||||
double value; // the value we are tracking
|
double cur_value; // the value we are tracking
|
||||||
double actual_value; // the value we actually exported to HTML
|
double cur_actual_value; // the value we actually exported to HTML
|
||||||
std::map<double, long long> value_map;
|
std::map<double, long long> value_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Be careful about the mixed usage of Matrix and const double *
|
// Be careful about the mixed usage of Matrix and const double *
|
||||||
|
// the input is usually double *, which might be changed, so we have to copy the content out
|
||||||
|
// in the map we use Matrix instead of double * such that the array may be automatically release when deconstructign
|
||||||
|
// since the address of cur_value.m cannot be changed, we can export double * instead of Matrix
|
||||||
template <class Imp>
|
template <class Imp>
|
||||||
class StateManager<Matrix, Imp>
|
class StateManager<Matrix, Imp>
|
||||||
{
|
{
|
||||||
|
@ -112,21 +118,24 @@ public:
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void reset(void) {
|
void reset(void) {
|
||||||
_install(imp->default_value());
|
memcpy(cur_value.m, imp->default_value(), sizeof(cur_value.m));
|
||||||
|
cur_id = install(cur_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return if changed
|
// return if changed
|
||||||
bool install(const double * new_value) {
|
bool update(const double * new_value) {
|
||||||
// For a transform matrix m
|
// For a transform matrix m
|
||||||
// m[4] & m[5] have been taken care of
|
// m[4] & m[5] have been taken care of
|
||||||
if(tm_equal(new_value, value.m, 4))
|
if(tm_equal(new_value, cur_value.m, 4))
|
||||||
return false;
|
return false;
|
||||||
_install(new_value);
|
|
||||||
|
memcpy(cur_value.m, new_value, sizeof(cur_value.m));
|
||||||
|
cur_id = install(cur_value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long get_id (void) const { return id; }
|
long long get_id (void) const { return cur_id; }
|
||||||
const Matrix & get_value (void) const { return value; }
|
const double * get_value (void) const { return cur_value.m; }
|
||||||
|
|
||||||
void dump_css(std::ostream & out) {
|
void dump_css(std::ostream & out) {
|
||||||
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
|
for(auto iter = value_map.begin(); iter != value_map.end(); ++iter)
|
||||||
|
@ -140,26 +149,23 @@ public:
|
||||||
void dump_print_css(std::ostream & out, double scale) {}
|
void dump_print_css(std::ostream & out, double scale) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// return if a new entry has been created
|
// return id
|
||||||
bool _install(const double * new_value) {
|
long long install(const Matrix & new_value) {
|
||||||
memcpy(value.m, new_value, sizeof(value.m));
|
auto iter = value_map.lower_bound(new_value);
|
||||||
|
if((iter != value_map.end()) && (tm_equal(new_value.m, iter->first.m, 4)))
|
||||||
auto iter = value_map.lower_bound(value);
|
|
||||||
if((iter != value_map.end()) && (tm_equal(value.m, iter->first.m, 4)))
|
|
||||||
{
|
{
|
||||||
id = iter->second;
|
return iter->second;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
id = value_map.size();
|
long long id = value_map.size();
|
||||||
value_map.insert(std::make_pair(value, id));
|
value_map.insert(std::make_pair(new_value, id));
|
||||||
return true;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Imp * imp;
|
Imp * imp;
|
||||||
|
|
||||||
long long id;
|
long long cur_id;
|
||||||
Matrix value;
|
Matrix cur_value;
|
||||||
|
|
||||||
class Matrix_less
|
class Matrix_less
|
||||||
{
|
{
|
||||||
|
@ -177,6 +183,7 @@ protected:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<Matrix, long long, Matrix_less> value_map;
|
std::map<Matrix, long long, Matrix_less> value_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -189,28 +196,31 @@ public:
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void reset(void) {
|
void reset(void) {
|
||||||
is_transparent = true;
|
cur_is_transparent = true;
|
||||||
id = -1;
|
cur_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool install(const GfxRGB & new_value) {
|
bool update(const GfxRGB & new_value) {
|
||||||
if((!is_transparent) && gfxrgb_equal_obj(new_value, value))
|
if((!cur_is_transparent) && gfxrgb_equal_obj(new_value, cur_value))
|
||||||
return false;
|
return false;
|
||||||
_install(new_value);
|
cur_value = new_value;
|
||||||
|
cur_is_transparent = false;
|
||||||
|
cur_id = install(cur_value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool install_transparent (void) {
|
bool update_transparent (void) {
|
||||||
if(is_transparent)
|
if(cur_is_transparent)
|
||||||
return false;
|
return false;
|
||||||
_install_transparent();
|
cur_is_transparent = true;
|
||||||
|
cur_id = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long long get_id (void) const { return id; }
|
long long get_id (void) const { return cur_id; }
|
||||||
const GfxRGB & get_value (void) const { return value; }
|
const GfxRGB & get_value (void) const { return cur_value; }
|
||||||
bool get_is_transparent (void) const { return is_transparent; }
|
bool get_is_transparent (void) const { return cur_is_transparent; }
|
||||||
|
|
||||||
void dump_css(std::ostream & out) {
|
void dump_css(std::ostream & out) {
|
||||||
out << "." << imp->get_css_class_name() << CSS::INVALID_ID << "{";
|
out << "." << imp->get_css_class_name() << CSS::INVALID_ID << "{";
|
||||||
|
@ -228,32 +238,23 @@ public:
|
||||||
void dump_print_css(std::ostream & out, double scale) {}
|
void dump_print_css(std::ostream & out, double scale) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _install(const GfxRGB & new_value) {
|
long long install(const GfxRGB & new_value) {
|
||||||
is_transparent = false;
|
|
||||||
value = new_value;
|
|
||||||
auto iter = value_map.find(new_value);
|
auto iter = value_map.find(new_value);
|
||||||
if(iter != value_map.end())
|
if(iter != value_map.end())
|
||||||
{
|
{
|
||||||
id = iter->second;
|
return iter->second;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
id = value_map.size();
|
long long id = value_map.size();
|
||||||
value_map.insert(std::make_pair(value, id));
|
value_map.insert(std::make_pair(new_value, id));
|
||||||
return true;
|
return id;
|
||||||
}
|
|
||||||
|
|
||||||
bool _install_transparent(void) {
|
|
||||||
is_transparent = true;
|
|
||||||
id = -1;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Imp * imp;
|
Imp * imp;
|
||||||
|
|
||||||
long long id;
|
long long cur_id;
|
||||||
GfxRGB value;
|
GfxRGB cur_value;
|
||||||
bool is_transparent;
|
bool cur_is_transparent;
|
||||||
|
|
||||||
class GfxRGB_hash
|
class GfxRGB_hash
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user