2012-08-14 06:35:55 +00:00
|
|
|
/*
|
|
|
|
* install.cc
|
|
|
|
*
|
|
|
|
* maintaining all known styles
|
|
|
|
*
|
|
|
|
* by WangLu
|
|
|
|
* 2012.08.14
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iostream>
|
2012-08-30 00:39:49 +00:00
|
|
|
#include <cmath>
|
2012-08-30 17:08:31 +00:00
|
|
|
#include <algorithm>
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
#include <boost/format.hpp>
|
|
|
|
|
|
|
|
#include <CharCodeToUnicode.h>
|
2012-08-23 19:30:37 +00:00
|
|
|
#include <fofi/FoFiTrueType.h>
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
#include "HTMLRenderer.h"
|
2012-08-14 09:13:29 +00:00
|
|
|
#include "namespace.h"
|
2012-08-14 06:35:55 +00:00
|
|
|
|
2012-08-26 15:56:38 +00:00
|
|
|
using std::all_of;
|
2012-08-30 17:08:31 +00:00
|
|
|
using std::max;
|
|
|
|
using std::min;
|
2012-08-26 15:56:38 +00:00
|
|
|
|
2012-08-27 15:09:01 +00:00
|
|
|
FontInfo HTMLRenderer::install_font(GfxFont * font)
|
2012-08-14 06:35:55 +00:00
|
|
|
{
|
|
|
|
assert(sizeof(long long) == 2*sizeof(int));
|
|
|
|
|
|
|
|
long long fn_id = (font == nullptr) ? 0 : *reinterpret_cast<long long*>(font->getID());
|
|
|
|
|
|
|
|
auto iter = font_name_map.find(fn_id);
|
|
|
|
if(iter != font_name_map.end())
|
2012-08-27 15:09:01 +00:00
|
|
|
return iter->second;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
long long new_fn_id = font_name_map.size();
|
|
|
|
|
2012-08-27 15:09:01 +00:00
|
|
|
auto cur_info_iter = font_name_map.insert(make_pair(fn_id, FontInfo({new_fn_id, true}))).first;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
if(font == nullptr)
|
|
|
|
{
|
|
|
|
export_remote_default_font(new_fn_id);
|
2012-08-27 15:09:01 +00:00
|
|
|
return cur_info_iter->second;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
2012-08-30 16:25:05 +00:00
|
|
|
cur_info_iter->second.ascent = font->getAscent();
|
|
|
|
cur_info_iter->second.descent = font->getDescent();
|
|
|
|
|
2012-08-14 06:35:55 +00:00
|
|
|
if(param->debug)
|
|
|
|
{
|
2012-08-14 09:50:16 +00:00
|
|
|
cerr << "Install font: (" << (font->getID()->num) << ' ' << (font->getID()->gen) << ") -> " << format("f%|1$x|")%new_fn_id << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(font->getType() == fontType3) {
|
2012-08-14 09:13:29 +00:00
|
|
|
cerr << "Type 3 fonts are unsupported and will be rendered as Image" << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
export_remote_default_font(new_fn_id);
|
2012-08-27 15:09:01 +00:00
|
|
|
return cur_info_iter->second;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
if(font->getWMode()) {
|
2012-08-14 09:13:29 +00:00
|
|
|
cerr << "Writing mode is unsupported and will be rendered as Image" << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
export_remote_default_font(new_fn_id);
|
2012-08-27 15:09:01 +00:00
|
|
|
return cur_info_iter->second;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto * font_loc = font->locateFont(xref, gTrue);
|
|
|
|
if(font_loc != nullptr)
|
|
|
|
{
|
|
|
|
switch(font_loc -> locType)
|
|
|
|
{
|
|
|
|
case gfxFontLocEmbedded:
|
|
|
|
{
|
2012-08-14 09:13:29 +00:00
|
|
|
string suffix = dump_embedded_font(font, new_fn_id);
|
2012-08-14 06:35:55 +00:00
|
|
|
if(suffix != "")
|
|
|
|
{
|
2012-08-30 15:36:30 +00:00
|
|
|
install_embedded_font(font, suffix, new_fn_id, cur_info_iter->second);
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
export_remote_default_font(new_fn_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case gfxFontLocExternal:
|
|
|
|
install_external_font(font, new_fn_id);
|
|
|
|
break;
|
|
|
|
case gfxFontLocResident:
|
|
|
|
install_base_font(font, font_loc, new_fn_id);
|
|
|
|
break;
|
|
|
|
default:
|
2012-08-14 09:13:29 +00:00
|
|
|
cerr << "TODO: other font loc" << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
export_remote_default_font(new_fn_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
delete font_loc;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
export_remote_default_font(new_fn_id);
|
|
|
|
}
|
|
|
|
|
2012-08-27 15:09:01 +00:00
|
|
|
return cur_info_iter->second;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
2012-08-14 08:23:15 +00:00
|
|
|
// TODO
|
|
|
|
// add a new function and move to text.cc
|
2012-08-30 15:36:30 +00:00
|
|
|
void HTMLRenderer::install_embedded_font(GfxFont * font, const string & suffix, long long fn_id, FontInfo & info)
|
2012-08-14 06:35:55 +00:00
|
|
|
{
|
2012-08-14 09:50:16 +00:00
|
|
|
string fn = (format("f%|1$x|") % fn_id).str();
|
2012-08-14 06:35:55 +00:00
|
|
|
|
2012-08-26 22:51:35 +00:00
|
|
|
path script_path = tmp_dir / (fn + ".pe");
|
2012-08-14 18:46:53 +00:00
|
|
|
ofstream script_fout(script_path, ofstream::binary);
|
2012-08-26 22:51:35 +00:00
|
|
|
add_tmp_file(fn+".pe");
|
2012-08-14 18:46:53 +00:00
|
|
|
|
|
|
|
script_fout << format("Open(%1%, 1)") % (tmp_dir / (fn + suffix)) << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
int * code2GID = nullptr;
|
2012-08-21 19:50:52 +00:00
|
|
|
int code2GID_len = 0;
|
2012-08-26 15:56:38 +00:00
|
|
|
int maxcode = 0;
|
|
|
|
|
2012-08-27 16:06:09 +00:00
|
|
|
Gfx8BitFont * font_8bit = nullptr;
|
|
|
|
|
2012-08-28 11:00:30 +00:00
|
|
|
/*
|
|
|
|
* Step 1
|
|
|
|
* dump the font file directly from the font descriptor and put the glyphs into the correct slots
|
|
|
|
*
|
|
|
|
* for 8bit + nonTrueType
|
|
|
|
* re-encoding the font using a PostScript encoding list (glyph id <-> glpyh name)
|
|
|
|
*
|
|
|
|
* for 8bit + TrueType
|
|
|
|
* sort the glpyhs as the original order, and later will map GID (instead of char code) to Unicode
|
|
|
|
*
|
|
|
|
* for CID + nonTrueType
|
|
|
|
* Flatten the font
|
|
|
|
*
|
|
|
|
* for CID Truetype
|
|
|
|
* same as 8bitTrueType, except for that we have to check 65536 charcodes
|
|
|
|
*/
|
2012-08-26 15:56:38 +00:00
|
|
|
if(!font->isCIDFont())
|
|
|
|
{
|
2012-08-27 16:06:09 +00:00
|
|
|
font_8bit = dynamic_cast<Gfx8BitFont*>(font);
|
2012-08-26 15:56:38 +00:00
|
|
|
maxcode = 0xff;
|
|
|
|
if(suffix == ".ttf")
|
2012-08-14 06:35:55 +00:00
|
|
|
{
|
2012-08-26 22:51:35 +00:00
|
|
|
script_fout << "Reencode(\"original\")" << endl;
|
2012-08-26 15:56:38 +00:00
|
|
|
int buflen;
|
|
|
|
char * buf = nullptr;
|
|
|
|
if((buf = font->readEmbFontFile(xref, &buflen)))
|
2012-08-16 05:24:22 +00:00
|
|
|
{
|
2012-08-26 15:56:38 +00:00
|
|
|
FoFiTrueType *fftt = nullptr;
|
|
|
|
if((fftt = FoFiTrueType::make(buf, buflen)))
|
2012-08-23 19:30:37 +00:00
|
|
|
{
|
2012-08-27 16:06:09 +00:00
|
|
|
code2GID = font_8bit->getCodeToGIDMap(fftt);
|
2012-08-26 15:56:38 +00:00
|
|
|
code2GID_len = 256;
|
|
|
|
delete fftt;
|
2012-08-23 19:30:37 +00:00
|
|
|
}
|
2012-08-26 15:56:38 +00:00
|
|
|
gfree(buf);
|
2012-08-16 05:24:22 +00:00
|
|
|
}
|
2012-08-26 23:10:21 +00:00
|
|
|
}
|
2012-08-14 06:35:55 +00:00
|
|
|
else
|
|
|
|
{
|
2012-08-27 16:06:09 +00:00
|
|
|
// move the slot such that it's consistent with the encoding seen in PDF
|
|
|
|
ofstream out(tmp_dir / (fn + "_.encoding"));
|
|
|
|
add_tmp_file(fn+"_.encoding");
|
|
|
|
|
|
|
|
out << format("/%1% [") % fn << endl;
|
|
|
|
for(int i = 0; i < 256; ++i)
|
|
|
|
{
|
|
|
|
auto cn = font_8bit->getCharName(i);
|
|
|
|
out << "/" << ((cn == nullptr) ? ".notdef" : cn) << endl;
|
|
|
|
}
|
|
|
|
out << "] def" << endl;
|
|
|
|
|
|
|
|
script_fout << format("LoadEncodingFile(%1%)") % (tmp_dir / (fn+"_.encoding")) << endl;
|
|
|
|
script_fout << format("Reencode(\"%1%\")") % fn << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
2012-08-26 15:56:38 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
maxcode = 0xffff;
|
2012-08-26 22:51:35 +00:00
|
|
|
|
2012-08-26 15:56:38 +00:00
|
|
|
if(suffix == ".ttf")
|
|
|
|
{
|
|
|
|
script_fout << "Reencode(\"original\")" << endl;
|
|
|
|
|
|
|
|
GfxCIDFont * _font = dynamic_cast<GfxCIDFont*>(font);
|
2012-08-14 06:35:55 +00:00
|
|
|
|
2012-08-26 15:56:38 +00:00
|
|
|
// code2GID has been stored for embedded CID fonts
|
|
|
|
code2GID = _font->getCIDToGID();
|
|
|
|
code2GID_len = _font->getCIDToGIDLen();
|
|
|
|
}
|
|
|
|
else
|
2012-08-14 06:35:55 +00:00
|
|
|
{
|
2012-08-26 15:56:38 +00:00
|
|
|
script_fout << "CIDFlatten()" << endl;
|
|
|
|
}
|
|
|
|
}
|
2012-08-27 16:06:09 +00:00
|
|
|
|
2012-08-28 11:00:30 +00:00
|
|
|
/*
|
|
|
|
* Step 2
|
|
|
|
* map charcode (or GID for CID truetype)
|
|
|
|
* generate an Consortium encoding file and let fontforge handle it.
|
|
|
|
*
|
|
|
|
* - Always map to Unicode for 8bit TrueType fonts and CID fonts
|
|
|
|
*
|
|
|
|
* - For 8bit nonTruetype fonts:
|
|
|
|
* Try to calculate the correct Unicode value from the glyph names, unless param->always_apply_tounicode is set
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-08-30 15:36:30 +00:00
|
|
|
info.use_tounicode = ((suffix == ".ttf") || (font->isCIDFont()) || (param->always_apply_tounicode));
|
2012-08-27 15:09:01 +00:00
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
auto ctu = font->getToUnicode();
|
2012-08-27 07:56:16 +00:00
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
ofstream map_fout(tmp_dir / (fn + ".encoding"));
|
|
|
|
add_tmp_file(fn+".encoding");
|
2012-08-27 16:06:09 +00:00
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
int cnt = 0;
|
|
|
|
for(int i = 0; i <= maxcode; ++i)
|
|
|
|
{
|
|
|
|
if((suffix != ".ttf") && (font_8bit != nullptr) && (font_8bit->getCharName(i) == nullptr))
|
|
|
|
continue;
|
2012-08-27 16:06:09 +00:00
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
++ cnt;
|
|
|
|
map_fout << format("0x%|1$X|") % ((code2GID && (i < code2GID_len))? code2GID[i] : i);
|
2012-08-27 16:06:09 +00:00
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
Unicode u, *pu=&u;
|
2012-08-27 16:06:09 +00:00
|
|
|
|
2012-08-30 15:36:30 +00:00
|
|
|
if(info.use_tounicode)
|
2012-08-27 16:14:11 +00:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
if(ctu)
|
|
|
|
n = ctu->mapToUnicode(i, &pu);
|
|
|
|
u = check_unicode(pu, n, i, font);
|
2012-08-27 15:09:01 +00:00
|
|
|
}
|
2012-08-27 16:14:11 +00:00
|
|
|
else
|
2012-08-27 15:09:01 +00:00
|
|
|
{
|
2012-08-27 16:14:11 +00:00
|
|
|
u = unicode_from_font(i, font);
|
2012-08-27 15:09:01 +00:00
|
|
|
}
|
2012-08-27 07:56:16 +00:00
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
map_fout << format(" 0x%|1$X|") % u;
|
|
|
|
map_fout << format(" # 0x%|1$X|") % i;
|
|
|
|
|
|
|
|
map_fout << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
2012-08-27 16:14:11 +00:00
|
|
|
if(cnt > 0)
|
|
|
|
{
|
|
|
|
script_fout << format("LoadEncodingFile(%1%, \"%2%\")") % (tmp_dir / (fn+".encoding")) % fn << endl;
|
|
|
|
script_fout << format("Reencode(\"%1%\", 1)") % fn << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ctu)
|
|
|
|
ctu->decRefCnt();
|
|
|
|
|
2012-08-31 02:10:06 +00:00
|
|
|
auto dest = ((param->single_html ? tmp_dir : dest_dir) / (fn+(param->font_suffix)));
|
2012-08-15 04:27:41 +00:00
|
|
|
if(param->single_html)
|
2012-08-31 02:10:06 +00:00
|
|
|
add_tmp_file(fn+(param->font_suffix));
|
2012-08-14 18:46:53 +00:00
|
|
|
|
2012-08-30 15:36:30 +00:00
|
|
|
script_fout << format("Generate(%1%)") % dest << endl;
|
2012-08-30 16:25:05 +00:00
|
|
|
script_fout << "Close()" << endl;
|
2012-08-30 15:36:30 +00:00
|
|
|
script_fout << format("Open(%1%, 1)") % dest << endl;
|
|
|
|
|
|
|
|
for(const string & s1 : {"Win", "Typo", "HHead"})
|
|
|
|
{
|
|
|
|
for(const string & s2 : {"Ascent", "Descent"})
|
|
|
|
{
|
|
|
|
script_fout << "Print(GetOS2Value(\"" << s1 << s2 << "\"))" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-31 02:10:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Firefox & Chrome interprets the values in different ways
|
|
|
|
* Trying to unify them
|
|
|
|
*/
|
|
|
|
script_fout << "a=GetOS2Value(\"TypoAscent\")" << endl;
|
|
|
|
script_fout << "d=GetOS2Value(\"TypoDescent\")" << endl;
|
|
|
|
script_fout << "SetOS2Value(\"TypoAscent\", 0)" << endl;
|
|
|
|
script_fout << "SetOS2Value(\"TypoDescent\", -a-d)" << endl;
|
|
|
|
script_fout << format("Generate(%1%)") % dest << endl;
|
|
|
|
|
2012-08-30 15:36:30 +00:00
|
|
|
if(system((boost::format("fontforge -script %1% 1>%2% 2>%3%") % script_path % (tmp_dir / (fn+".info")) % (tmp_dir / NULL_FILENAME)).str().c_str()) != 0)
|
2012-08-16 14:36:52 +00:00
|
|
|
cerr << "Warning: fontforge failed." << endl;
|
|
|
|
|
2012-08-30 15:36:30 +00:00
|
|
|
add_tmp_file(fn+".info");
|
2012-08-20 20:50:07 +00:00
|
|
|
add_tmp_file(NULL_FILENAME);
|
2012-08-14 06:35:55 +00:00
|
|
|
|
2012-08-30 15:36:30 +00:00
|
|
|
// read metric
|
|
|
|
int WinAsc, WinDes, TypoAsc, TypoDes, HHeadAsc, HHeadDes;
|
|
|
|
if(ifstream(tmp_dir / (fn+".info")) >> WinAsc >> WinDes >> TypoAsc >> TypoDes >> HHeadAsc >> HHeadDes)
|
|
|
|
{
|
2012-08-30 16:25:05 +00:00
|
|
|
int em = TypoAsc - TypoDes;
|
|
|
|
if(em != 0)
|
|
|
|
{
|
2012-08-30 17:08:31 +00:00
|
|
|
/*
|
|
|
|
int a = max(WinAsc, max(TypoAsc, HHeadAsc));
|
|
|
|
int d = min(-WinDes, min(TypoDes, HHeadDes));
|
|
|
|
*/
|
|
|
|
int a = WinAsc;
|
|
|
|
int d = -WinDes;
|
|
|
|
|
|
|
|
info.ascent = ((double)a) / em;
|
|
|
|
info.descent = ((double)d) / em;
|
2012-08-30 16:25:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info.ascent = 0;
|
|
|
|
info.descent = 0;
|
|
|
|
}
|
2012-08-30 15:36:30 +00:00
|
|
|
}
|
2012-08-30 16:25:05 +00:00
|
|
|
|
|
|
|
if(param->debug)
|
2012-08-30 15:36:30 +00:00
|
|
|
{
|
2012-08-30 16:25:05 +00:00
|
|
|
cerr << "Ascent: " << info.ascent << " Descent: " << info.descent << endl;
|
2012-08-30 15:36:30 +00:00
|
|
|
}
|
|
|
|
|
2012-08-31 02:10:06 +00:00
|
|
|
export_remote_font(info, param->font_suffix, param->font_format, font);
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLRenderer::install_base_font(GfxFont * font, GfxFontLoc * font_loc, long long fn_id)
|
|
|
|
{
|
2012-08-14 09:13:29 +00:00
|
|
|
string psname(font_loc->path->getCString());
|
2012-08-14 06:35:55 +00:00
|
|
|
string basename = psname.substr(0, psname.find('-'));
|
|
|
|
string cssfont;
|
|
|
|
auto iter = BASE_14_FONT_CSS_FONT_MAP.find(basename);
|
|
|
|
if(iter == BASE_14_FONT_CSS_FONT_MAP.end())
|
|
|
|
{
|
2012-08-14 09:13:29 +00:00
|
|
|
cerr << "PS Font: " << basename << " not found in the base 14 font map" << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
cssfont = "";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cssfont = iter->second;
|
|
|
|
|
|
|
|
export_local_font(fn_id, font, psname, cssfont);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLRenderer::install_external_font( GfxFont * font, long long fn_id)
|
|
|
|
{
|
2012-08-14 09:13:29 +00:00
|
|
|
string fontname(font->getName()->getCString());
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
// resolve bad encodings in GB
|
|
|
|
auto iter = GB_ENCODED_FONT_NAME_MAP.find(fontname);
|
|
|
|
if(iter != GB_ENCODED_FONT_NAME_MAP.end())
|
|
|
|
{
|
|
|
|
fontname = iter->second;
|
2012-08-14 09:13:29 +00:00
|
|
|
cerr << "Warning: workaround for font names in bad encodings." << endl;
|
2012-08-14 06:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export_local_font(fn_id, font, fontname, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
long long HTMLRenderer::install_font_size(double font_size)
|
|
|
|
{
|
|
|
|
auto iter = font_size_map.lower_bound(font_size - EPS);
|
|
|
|
if((iter != font_size_map.end()) && (_equal(iter->first, font_size)))
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
long long new_fs_id = font_size_map.size();
|
2012-08-14 09:13:29 +00:00
|
|
|
font_size_map.insert(make_pair(font_size, new_fs_id));
|
2012-08-14 06:35:55 +00:00
|
|
|
export_font_size(new_fs_id, font_size);
|
|
|
|
return new_fs_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
long long HTMLRenderer::install_transform_matrix(const double * tm)
|
|
|
|
{
|
|
|
|
TM m(tm);
|
|
|
|
auto iter = transform_matrix_map.lower_bound(m);
|
|
|
|
if((iter != transform_matrix_map.end()) && (m == (iter->first)))
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
long long new_tm_id = transform_matrix_map.size();
|
2012-08-14 09:13:29 +00:00
|
|
|
transform_matrix_map.insert(make_pair(m, new_tm_id));
|
2012-08-14 06:35:55 +00:00
|
|
|
export_transform_matrix(new_tm_id, tm);
|
|
|
|
return new_tm_id;
|
|
|
|
}
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
long long HTMLRenderer::install_letter_space(double letter_space)
|
|
|
|
{
|
|
|
|
auto iter = letter_space_map.lower_bound(letter_space - EPS);
|
|
|
|
if((iter != letter_space_map.end()) && (_equal(iter->first, letter_space)))
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
long long new_ls_id = letter_space_map.size();
|
|
|
|
letter_space_map.insert(make_pair(letter_space, new_ls_id));
|
|
|
|
export_letter_space(new_ls_id, letter_space);
|
|
|
|
return new_ls_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
long long HTMLRenderer::install_word_space(double word_space)
|
|
|
|
{
|
|
|
|
auto iter = word_space_map.lower_bound(word_space - EPS);
|
|
|
|
if((iter != word_space_map.end()) && (_equal(iter->first, word_space)))
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
long long new_ws_id = word_space_map.size();
|
|
|
|
word_space_map.insert(make_pair(word_space, new_ws_id));
|
|
|
|
export_word_space(new_ws_id, word_space);
|
|
|
|
return new_ws_id;
|
|
|
|
}
|
|
|
|
|
2012-08-14 06:35:55 +00:00
|
|
|
long long HTMLRenderer::install_color(const GfxRGB * rgb)
|
|
|
|
{
|
2012-08-14 09:13:29 +00:00
|
|
|
const GfxRGB & c = *rgb;
|
2012-08-14 06:35:55 +00:00
|
|
|
auto iter = color_map.lower_bound(c);
|
|
|
|
if((iter != color_map.end()) && (c == (iter->first)))
|
|
|
|
return iter->second;
|
|
|
|
|
|
|
|
long long new_color_id = color_map.size();
|
2012-08-14 09:13:29 +00:00
|
|
|
color_map.insert(make_pair(c, new_color_id));
|
2012-08-14 06:35:55 +00:00
|
|
|
export_color(new_color_id, rgb);
|
|
|
|
return new_color_id;
|
|
|
|
}
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
long long HTMLRenderer::install_whitespace(double ws_width, double & actual_width)
|
|
|
|
{
|
|
|
|
// ws_width is already mulitpled by draw_scale
|
|
|
|
auto iter = whitespace_map.lower_bound(ws_width - param->h_eps);
|
|
|
|
if((iter != whitespace_map.end()) && (abs(iter->first - ws_width) < param->h_eps))
|
|
|
|
{
|
|
|
|
actual_width = iter->first;
|
|
|
|
return iter->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
actual_width = ws_width;
|
|
|
|
long long new_ws_id = whitespace_map.size();
|
|
|
|
whitespace_map.insert(make_pair(ws_width, new_ws_id));
|
|
|
|
export_whitespace(new_ws_id, ws_width);
|
|
|
|
return new_ws_id;
|
|
|
|
}
|
|
|
|
|
2012-08-24 17:40:43 +00:00
|
|
|
long long HTMLRenderer::install_rise(double rise)
|
|
|
|
{
|
|
|
|
auto iter = rise_map.lower_bound(rise - param->v_eps);
|
|
|
|
if((iter != rise_map.end()) && (abs(iter->first - rise) < param->v_eps))
|
|
|
|
{
|
|
|
|
return iter->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
long long new_rise_id = rise_map.size();
|
|
|
|
rise_map.insert(make_pair(rise, new_rise_id));
|
|
|
|
export_rise(new_rise_id, rise);
|
|
|
|
return new_rise_id;
|
|
|
|
}
|