diff --git a/src/HTMLRenderer/HTMLRenderer.h b/src/HTMLRenderer/HTMLRenderer.h index 64f36be..605fe8d 100644 --- a/src/HTMLRenderer/HTMLRenderer.h +++ b/src/HTMLRenderer/HTMLRenderer.h @@ -164,7 +164,6 @@ class HTMLRenderer : public OutputDev void install_base_font(GfxFont * font, GfxFontLoc * font_loc, FontInfo & info); void install_external_font (GfxFont * font, FontInfo & info); - long long install_transform_matrix(const double * tm); long long install_fill_color(const GfxRGB * rgb); long long install_stroke_color(const GfxRGB * rgb); @@ -179,7 +178,6 @@ class HTMLRenderer : public OutputDev void export_remote_default_font(long long fn_id); void export_local_font(const FontInfo & info, GfxFont * font, const std::string & original_font_name, const std::string & cssfont); - void export_transform_matrix(long long tm_id, const double * tm); void export_fill_color(long long color_id, const GfxRGB * rgb); void export_stroke_color(long long color_id, const GfxRGB * rgb); @@ -277,7 +275,6 @@ class HTMLRenderer : public OutputDev // cur_font_size is as in GfxState, // font_size_manager saves the final font size used in HTML double cur_font_size; - FontSizeManager font_size_manager; // transform matrix long long cur_ttm_id; @@ -292,11 +289,7 @@ class HTMLRenderer : public OutputDev // letter spacing bool letter_space_changed; - LetterSpaceManager letter_space_manager; - - // word spacing bool word_space_changed; - WordSpaceManager word_space_manager; // fill color long long cur_fill_color_id; @@ -309,22 +302,24 @@ class HTMLRenderer : public OutputDev GfxRGB cur_stroke_color; bool cur_has_stroke; bool stroke_color_changed; - - // rise bool rise_changed; - RiseManager rise_manager; - WhitespaceManager whitespace_manager; - HeightManager height_manager; - LeftManager left_manager; + // managers store values actually used in HTML (i.e. scaled) + FontSizeManager font_size_manager; + LetterSpaceManager letter_space_manager; + WordSpaceManager word_space_manager; + RiseManager rise_manager; + WhitespaceManager whitespace_manager; + HeightManager height_manager; + LeftManager left_manager; + TransformMatrixManager transform_matrix_manager; // optimize for web // we try to render the final font size directly // to reduce the effect of ctm as much as possible - // draw_text_tm is cur_text_tm scaled by 1/draw_text_scale, + // the actual tm used is `real tm in PDF` scaled by 1/draw_text_scale, // so everything redenered should be multiplied by draw_text_scale - double draw_text_tm[6]; double draw_text_scale; // the position of next char, in text coords @@ -354,7 +349,6 @@ class HTMLRenderer : public OutputDev //////////////////////////////////////////////////// std::unordered_map font_name_map; - std::map transform_matrix_map; std::unordered_map fill_color_map, stroke_color_map; const Param * param; diff --git a/src/HTMLRenderer/draw.cc b/src/HTMLRenderer/draw.cc index eda5b06..b0fc1f3 100644 --- a/src/HTMLRenderer/draw.cc +++ b/src/HTMLRenderer/draw.cc @@ -372,7 +372,10 @@ void HTMLRenderer::css_draw_rectangle(double x, double y, double w, double h, co } } - f_pages.fs << "
first.m, 4))) - return iter->second; - - long long new_tm_id = transform_matrix_map.size(); - transform_matrix_map.insert(make_pair(m, new_tm_id)); - export_transform_matrix(new_tm_id, tm); - return new_tm_id; -} - long long HTMLRenderer::install_fill_color(const GfxRGB * rgb) { // transparent diff --git a/src/HTMLRenderer/link.cc b/src/HTMLRenderer/link.cc index 510baaa..225f7ac 100644 --- a/src/HTMLRenderer/link.cc +++ b/src/HTMLRenderer/link.cc @@ -193,7 +193,7 @@ void HTMLRenderer::processLink(AnnotLink * al) if(!dest_str.empty()) { - f_pages.fs << ""; } + transform_matrix_manager.install(default_ctm); f_pages.fs << "
(new_line_state, NLS_SPAN); } - if(!(tm_equal(new_draw_text_tm, draw_text_tm, 4))) + if(transform_matrix_manager.install(new_draw_text_tm)) { new_line_state = max(new_line_state, NLS_DIV); - memcpy(draw_text_tm, new_draw_text_tm, sizeof(draw_text_tm)); - cur_ttm_id = install_transform_matrix(draw_text_tm); } } diff --git a/src/util/StateManager.h b/src/util/StateManager.h index e210ae1..f15459a 100644 --- a/src/util/StateManager.h +++ b/src/util/StateManager.h @@ -37,8 +37,7 @@ public: // usually called at the beginning of a page void reset(void) { - value = imp->default_value(); - _install(value); + _install(imp->default_value()); } /* @@ -79,9 +78,8 @@ protected: return false; } - actual_value = new_value; id = value_map.size(); - value_map.insert(std::make_pair(new_value, id)); + actual_value = value_map.insert(std::make_pair(new_value, id)).first->first; return true; } @@ -94,6 +92,88 @@ protected: std::map value_map; }; +// Be careful about the mixed usage of Matrix and const double * +template +class StateManager +{ +public: + StateManager() + : imp(static_cast(this)) + { } + + void reset(void) { + _install(imp->default_value()); + } + + // return if changed + bool install(const double * new_value) { + // For a transform matrix m + // m[4] & m[5] have been taken care of + if(tm_equal(new_value, value.m, 4)) + return false; + _install(new_value); + return true; + } + + long long get_id (void) const { return id; } + const Matrix & get_value (void) const { return value; } + const Matrix & get_actual_value (void) const { return *actual_value; } + + void dump_css(std::ostream & out) { + for(auto iter = value_map.begin(); iter != value_map.end(); ++iter) + { + out << "." << imp->get_css_class_name() << iter->second << "{"; + imp->dump_value(out, iter->first); + out << "}" << std::endl; + } + } + +protected: + // return if a new entry has been created + bool _install(const double * new_value) { + memcpy(value.m, new_value, sizeof(value.m)); + + auto iter = value_map.lower_bound(value); + if((iter != value_map.end()) && (tm_equal(value.m, iter->first.m, 4))) + { + actual_value = &(iter->first); + id = iter->second; + return false; + } + + id = value_map.size(); + actual_value = &(value_map.insert(std::make_pair(value, id)).first->first); + return true; + } + + Imp * imp; + + long long id; + Matrix value; + const Matrix * actual_value; + + class Matrix_less + { + public: + bool operator () (const Matrix & m1, const Matrix & m2) const + { + // Note that we only care about the first 4 elements + for(int i = 0; i < 4; ++i) + { + if(m1.m[i] < m2.m[i] - EPS) + return true; + if(m1.m[i] > m2.m[i] + EPS) + return false; + } + return false; + } + }; + std::map value_map; +}; + +///////////////////////////////////// +// Specific state managers + class FontSizeManager : public StateManager { public: @@ -154,6 +234,39 @@ public: void dump_value(std::ostream & out, double value) { out << "left:" << round(value) << "px;"; } }; +class TransformMatrixManager : public StateManager +{ +public: + static const char * get_css_class_name (void) { return CSS::TRANSFORM_MATRIX_CN; } + const double * default_value(void) { return ID_MATRIX; } + void dump_value(std::ostream & out, const Matrix & matrix) { + // always ignore tm[4] and tm[5] because + // we have already shifted the origin + // TODO: recognize common matices + const auto & m = matrix.m; + if(tm_equal(m, ID_MATRIX, 4)) + { + auto prefixes = {"", "-ms-", "-moz-", "-webkit-", "-o-"}; + for(auto iter = prefixes.begin(); iter != prefixes.end(); ++iter) + out << *iter << "transform:none;"; + } + else + { + auto prefixes = {"", "-ms-", "-moz-", "-webkit-", "-o-"}; + for(auto iter = prefixes.begin(); iter != prefixes.end(); ++iter) + { + // PDF use a different coordinate system from Web + out << *iter << "transform:matrix(" + << round(m[0]) << ',' + << round(-m[1]) << ',' + << round(-m[2]) << ',' + << round(m[3]) << ','; + out << "0,0);"; + } + } + } +}; + } // namespace pdf2htmlEX #endif //STATEMANAGER_H__ diff --git a/src/util/misc.h b/src/util/misc.h index 3500bf7..19ce66e 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -55,23 +55,6 @@ public: } }; -class Matrix_less -{ -public: - bool operator () (const Matrix & m1, const Matrix & m2) const - { - // Note that we only care about the first 4 elements - for(int i = 0; i < 4; ++i) - { - if(m1.m[i] < m2.m[i] - EPS) - return true; - if(m1.m[i] > m2.m[i] + EPS) - return false; - } - return false; - } -}; - } // namespace pdf2htmlEX