2012-08-14 06:35:55 +00:00
|
|
|
|
/*
|
|
|
|
|
* state.cc
|
|
|
|
|
*
|
2013-02-02 19:35:45 +00:00
|
|
|
|
* track current state
|
2012-08-14 06:35:55 +00:00
|
|
|
|
*
|
2013-02-02 19:35:45 +00:00
|
|
|
|
* Copyright (C) 2012,2013 Lu Wang <coolwanglu@gmail.com>
|
2012-08-14 06:35:55 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2012-08-23 21:07:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* TODO
|
2012-08-24 17:40:43 +00:00
|
|
|
|
* optimize lines using nested <span> (reuse classes)
|
2012-08-23 21:07:01 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2012-10-02 18:19:40 +00:00
|
|
|
|
#include <cmath>
|
2012-08-16 10:11:22 +00:00
|
|
|
|
#include <algorithm>
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
|
|
#include "HTMLRenderer.h"
|
2012-12-11 12:48:01 +00:00
|
|
|
|
#include "TextLineBuffer.h"
|
2012-11-29 09:28:05 +00:00
|
|
|
|
#include "util/namespace.h"
|
2012-11-29 10:16:05 +00:00
|
|
|
|
#include "util/math.h"
|
2012-09-12 15:26:14 +00:00
|
|
|
|
|
|
|
|
|
namespace pdf2htmlEX {
|
|
|
|
|
|
2012-08-16 10:11:22 +00:00
|
|
|
|
using std::max;
|
2012-08-31 15:14:05 +00:00
|
|
|
|
using std::abs;
|
2012-08-16 10:11:22 +00:00
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
|
void HTMLRenderer::updateAll(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
all_changed = true;
|
|
|
|
|
updateTextPos(state);
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateRise(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
rise_changed = true;
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateTextPos(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
text_pos_changed = true;
|
|
|
|
|
cur_tx = state->getLineX();
|
|
|
|
|
cur_ty = state->getLineY();
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateTextShift(GfxState * state, double shift)
|
|
|
|
|
{
|
|
|
|
|
text_pos_changed = true;
|
|
|
|
|
cur_tx -= shift * 0.001 * state->getFontSize() * state->getHorizScaling();
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateFont(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
font_changed = true;
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateCTM(GfxState * state, double m11, double m12, double m21, double m22, double m31, double m32)
|
|
|
|
|
{
|
|
|
|
|
ctm_changed = true;
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateTextMat(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
text_mat_changed = true;
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateHorizScaling(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
hori_scale_changed = true;
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateCharSpace(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
letter_space_changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HTMLRenderer::updateWordSpace(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
word_space_changed = true;
|
|
|
|
|
}
|
2013-01-24 12:39:24 +00:00
|
|
|
|
void HTMLRenderer::updateRender(GfxState * state)
|
|
|
|
|
{
|
|
|
|
|
// currently Render is traced for color only
|
|
|
|
|
// might need something like render_changed later
|
2013-01-31 22:21:57 +00:00
|
|
|
|
fill_color_changed = true;
|
|
|
|
|
stroke_color_changed = true;
|
2013-01-24 12:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateFillColorSpace(GfxState * state)
|
|
|
|
|
{
|
2013-01-31 22:21:57 +00:00
|
|
|
|
fill_color_changed = true;
|
2013-01-24 12:39:24 +00:00
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::updateStrokeColorSpace(GfxState * state)
|
|
|
|
|
{
|
2013-01-31 22:21:57 +00:00
|
|
|
|
stroke_color_changed = true;
|
2013-01-24 12:39:24 +00:00
|
|
|
|
}
|
2012-08-15 10:48:11 +00:00
|
|
|
|
void HTMLRenderer::updateFillColor(GfxState * state)
|
|
|
|
|
{
|
2013-01-31 22:21:57 +00:00
|
|
|
|
fill_color_changed = true;
|
2012-08-15 10:48:11 +00:00
|
|
|
|
}
|
2013-01-24 12:39:24 +00:00
|
|
|
|
void HTMLRenderer::updateStrokeColor(GfxState * state)
|
|
|
|
|
{
|
2013-01-31 22:21:57 +00:00
|
|
|
|
stroke_color_changed = true;
|
2013-01-24 12:39:24 +00:00
|
|
|
|
}
|
2013-01-30 15:56:27 +00:00
|
|
|
|
void HTMLRenderer::reset_state()
|
|
|
|
|
{
|
|
|
|
|
draw_text_scale = 1.0;
|
|
|
|
|
|
|
|
|
|
cur_font_info = install_font(nullptr);
|
|
|
|
|
cur_font_size = draw_font_size = 0;
|
|
|
|
|
cur_fs_id = install_font_size(cur_font_size);
|
|
|
|
|
|
|
|
|
|
memcpy(cur_text_tm, ID_MATRIX, sizeof(cur_text_tm));
|
|
|
|
|
memcpy(draw_text_tm, ID_MATRIX, sizeof(draw_text_tm));
|
|
|
|
|
cur_ttm_id = install_transform_matrix(draw_text_tm);
|
|
|
|
|
|
|
|
|
|
cur_letter_space = cur_word_space = 0;
|
|
|
|
|
cur_ls_id = install_letter_space(cur_letter_space);
|
|
|
|
|
cur_ws_id = install_word_space(cur_word_space);
|
|
|
|
|
|
2013-01-31 22:50:21 +00:00
|
|
|
|
cur_fill_color.r = cur_fill_color.g = cur_fill_color.b = 0;
|
2013-02-02 12:32:09 +00:00
|
|
|
|
cur_fill_color_id = install_fill_color(&cur_fill_color);
|
|
|
|
|
cur_has_fill = true;
|
|
|
|
|
|
|
|
|
|
cur_stroke_color.r = cur_stroke_color.g = cur_stroke_color.b = 0;
|
|
|
|
|
cur_stroke_color_id = install_stroke_color(&cur_stroke_color);
|
|
|
|
|
cur_has_stroke = false;
|
2013-01-30 15:56:27 +00:00
|
|
|
|
|
|
|
|
|
cur_rise = 0;
|
|
|
|
|
cur_rise_id = install_rise(cur_rise);
|
|
|
|
|
|
|
|
|
|
cur_tx = cur_ty = 0;
|
|
|
|
|
draw_tx = draw_ty = 0;
|
|
|
|
|
|
|
|
|
|
reset_state_change();
|
|
|
|
|
all_changed = true;
|
|
|
|
|
}
|
|
|
|
|
void HTMLRenderer::reset_state_change()
|
|
|
|
|
{
|
|
|
|
|
all_changed = false;
|
|
|
|
|
|
|
|
|
|
rise_changed = false;
|
|
|
|
|
text_pos_changed = false;
|
|
|
|
|
|
|
|
|
|
font_changed = false;
|
|
|
|
|
ctm_changed = false;
|
|
|
|
|
text_mat_changed = false;
|
|
|
|
|
hori_scale_changed = false;
|
|
|
|
|
|
|
|
|
|
letter_space_changed = false;
|
|
|
|
|
word_space_changed = false;
|
|
|
|
|
|
2013-01-31 22:50:21 +00:00
|
|
|
|
fill_color_changed = false;
|
|
|
|
|
stroke_color_changed = false;
|
2013-01-30 15:56:27 +00:00
|
|
|
|
}
|
2012-08-14 06:35:55 +00:00
|
|
|
|
void HTMLRenderer::check_state_change(GfxState * state)
|
|
|
|
|
{
|
2012-08-15 10:48:11 +00:00
|
|
|
|
// DEPENDENCY WARNING
|
|
|
|
|
// don't adjust the order of state checking
|
|
|
|
|
|
2012-09-09 06:48:10 +00:00
|
|
|
|
new_line_state = NLS_NONE;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
|
bool need_recheck_position = false;
|
|
|
|
|
bool need_rescale_font = false;
|
2012-10-02 06:19:20 +00:00
|
|
|
|
bool draw_text_scale_changed = false;
|
2012-08-15 10:48:11 +00:00
|
|
|
|
|
|
|
|
|
// text position
|
2012-08-16 12:26:09 +00:00
|
|
|
|
// we've been tracking the text position positively in the update*** functions
|
2012-08-15 10:48:11 +00:00
|
|
|
|
if(all_changed || text_pos_changed)
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2012-08-15 13:51:39 +00:00
|
|
|
|
need_recheck_position = true;
|
2012-08-15 10:48:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// font name & size
|
2012-08-14 06:35:55 +00:00
|
|
|
|
if(all_changed || font_changed)
|
|
|
|
|
{
|
2012-09-04 15:33:15 +00:00
|
|
|
|
const FontInfo * new_font_info = install_font(state->getFont());
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
2012-09-04 15:33:15 +00:00
|
|
|
|
if(!(new_font_info->id == cur_font_info->id))
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2013-02-03 09:36:28 +00:00
|
|
|
|
// The width of the type 3 font text, if shown, is likely to be wrong
|
2013-01-19 12:13:31 +00:00
|
|
|
|
// So we will create separate (absolute positioned) blocks for them, such that it won't affect other text
|
2013-02-03 09:36:28 +00:00
|
|
|
|
// TODO: consider the font matrix and estimate the metrics
|
2013-01-19 12:13:31 +00:00
|
|
|
|
if(new_font_info->is_type3 || cur_font_info->is_type3)
|
|
|
|
|
{
|
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_DIV);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
|
|
|
|
}
|
2012-08-27 15:09:01 +00:00
|
|
|
|
cur_font_info = new_font_info;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
|
double new_font_size = state->getFontSize();
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!equal(cur_font_size, new_font_size))
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
|
|
|
|
need_rescale_font = true;
|
2012-08-15 10:48:11 +00:00
|
|
|
|
cur_font_size = new_font_size;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 10:02:18 +00:00
|
|
|
|
// backup the current ctm for need_recheck_position
|
2012-08-19 11:05:14 +00:00
|
|
|
|
double old_ctm[6];
|
2012-10-01 17:59:04 +00:00
|
|
|
|
memcpy(old_ctm, cur_text_tm, sizeof(old_ctm));
|
2012-08-19 10:02:18 +00:00
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
|
// ctm & text ctm & hori scale
|
|
|
|
|
if(all_changed || ctm_changed || text_mat_changed || hori_scale_changed)
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
|
|
|
|
double new_ctm[6];
|
2012-08-15 10:48:11 +00:00
|
|
|
|
|
|
|
|
|
const double * m1 = state->getCTM();
|
|
|
|
|
const double * m2 = state->getTextMat();
|
|
|
|
|
double hori_scale = state->getHorizScaling();
|
|
|
|
|
|
|
|
|
|
new_ctm[0] = (m1[0] * m2[0] + m1[2] * m2[1]) * hori_scale;
|
|
|
|
|
new_ctm[1] = (m1[1] * m2[0] + m1[3] * m2[1]) * hori_scale;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
new_ctm[2] = m1[0] * m2[2] + m1[2] * m2[3];
|
|
|
|
|
new_ctm[3] = m1[1] * m2[2] + m1[3] * m2[3];
|
2012-08-16 06:00:30 +00:00
|
|
|
|
new_ctm[4] = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
|
|
|
|
|
new_ctm[5] = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
|
|
|
|
|
//new_ctm[4] = new_ctm[5] = 0;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!tm_equal(new_ctm, cur_text_tm))
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2012-08-19 10:02:18 +00:00
|
|
|
|
need_recheck_position = true;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
need_rescale_font = true;
|
2012-10-01 17:59:04 +00:00
|
|
|
|
memcpy(cur_text_tm, new_ctm, sizeof(cur_text_tm));
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-02 06:19:20 +00:00
|
|
|
|
// draw_text_tm, draw_text_scale
|
2012-08-15 10:48:11 +00:00
|
|
|
|
// depends: font size & ctm & text_ctm & hori scale
|
2012-08-14 06:35:55 +00:00
|
|
|
|
if(need_rescale_font)
|
|
|
|
|
{
|
2012-10-01 17:59:04 +00:00
|
|
|
|
double new_draw_text_tm[6];
|
|
|
|
|
memcpy(new_draw_text_tm, cur_text_tm, sizeof(new_draw_text_tm));
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
2012-11-29 10:16:05 +00:00
|
|
|
|
double new_draw_text_scale = 1.0/text_scale_factor2 * hypot(new_draw_text_tm[2], new_draw_text_tm[3]);
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
|
|
|
|
double new_draw_font_size = cur_font_size;
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(is_positive(new_draw_text_scale))
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2012-10-02 06:19:20 +00:00
|
|
|
|
new_draw_font_size *= new_draw_text_scale;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
for(int i = 0; i < 4; ++i)
|
2012-10-02 06:19:20 +00:00
|
|
|
|
new_draw_text_tm[i] /= new_draw_text_scale;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2012-10-02 06:19:20 +00:00
|
|
|
|
new_draw_text_scale = 1.0;
|
2012-09-04 04:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-07 12:14:51 +00:00
|
|
|
|
if(!is_positive(new_draw_font_size))
|
2012-12-05 22:10:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Page is flipped and css can't handle it.
|
|
|
|
|
new_draw_font_size = -new_draw_font_size;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; ++i)
|
|
|
|
|
new_draw_text_tm[i] *= -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!(equal(new_draw_text_scale, draw_text_scale)))
|
2012-09-04 04:27:06 +00:00
|
|
|
|
{
|
2012-10-02 06:19:20 +00:00
|
|
|
|
draw_text_scale_changed = true;
|
|
|
|
|
draw_text_scale = new_draw_text_scale;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!(equal(new_draw_font_size, draw_font_size)))
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2012-10-02 18:19:40 +00:00
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
2012-08-14 06:35:55 +00:00
|
|
|
|
draw_font_size = new_draw_font_size;
|
|
|
|
|
cur_fs_id = install_font_size(draw_font_size);
|
|
|
|
|
}
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!(tm_equal(new_draw_text_tm, draw_text_tm, 4)))
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2012-10-02 18:19:40 +00:00
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_DIV);
|
2012-10-01 17:59:04 +00:00
|
|
|
|
memcpy(draw_text_tm, new_draw_text_tm, sizeof(draw_text_tm));
|
|
|
|
|
cur_ttm_id = install_transform_matrix(draw_text_tm);
|
2012-08-15 10:48:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 10:02:18 +00:00
|
|
|
|
// see if we can merge with the current line
|
|
|
|
|
// depends: rise & text position & transformation
|
|
|
|
|
if(need_recheck_position)
|
|
|
|
|
{
|
2012-08-19 20:30:05 +00:00
|
|
|
|
// try to transform the old origin under the new TM
|
|
|
|
|
/*
|
|
|
|
|
* OldTM * (draw_tx, draw_ty, 1)^T = CurTM * (draw_tx + dx, draw_ty + dy, 1)^T
|
|
|
|
|
*
|
|
|
|
|
* OldTM[4] = CurTM[0] * dx + CurTM[2] * dy + CurTM[4]
|
|
|
|
|
* OldTM[5] = CurTM[1] * dx + CurTM[3] * dy + CurTM[5]
|
|
|
|
|
*
|
|
|
|
|
* We just care if we can map the origin y to the same new y
|
|
|
|
|
* So just let dy = cur_y - old_y, and try to solve dx
|
|
|
|
|
*
|
|
|
|
|
* TODO, writing mode, set dx and solve dy
|
|
|
|
|
*/
|
|
|
|
|
|
2012-08-31 15:46:59 +00:00
|
|
|
|
bool merged = false;
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(tm_equal(old_ctm, cur_text_tm, 4))
|
2012-08-19 10:02:18 +00:00
|
|
|
|
{
|
2012-08-31 15:46:59 +00:00
|
|
|
|
double dy = cur_ty - draw_ty;
|
2012-10-01 17:59:04 +00:00
|
|
|
|
double tdx = old_ctm[4] - cur_text_tm[4] - cur_text_tm[2] * dy;
|
|
|
|
|
double tdy = old_ctm[5] - cur_text_tm[5] - cur_text_tm[3] * dy;
|
2012-08-31 15:46:59 +00:00
|
|
|
|
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(equal(cur_text_tm[0] * tdy, cur_text_tm[1] * tdx))
|
2012-08-19 10:02:18 +00:00
|
|
|
|
{
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(is_positive(cur_text_tm[0]))
|
2012-08-19 10:02:18 +00:00
|
|
|
|
{
|
2012-10-01 17:59:04 +00:00
|
|
|
|
draw_tx += tdx / cur_text_tm[0];
|
2012-08-19 21:01:21 +00:00
|
|
|
|
draw_ty += dy;
|
2012-08-31 15:46:59 +00:00
|
|
|
|
merged = true;
|
|
|
|
|
}
|
2012-11-29 10:16:05 +00:00
|
|
|
|
else if (is_positive(cur_text_tm[1]))
|
2012-08-31 15:46:59 +00:00
|
|
|
|
{
|
2012-10-01 17:59:04 +00:00
|
|
|
|
draw_tx += tdy / cur_text_tm[1];
|
2012-08-31 15:46:59 +00:00
|
|
|
|
draw_ty += dy;
|
|
|
|
|
merged = true;
|
2012-08-19 20:30:05 +00:00
|
|
|
|
}
|
2012-08-19 10:02:18 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if((equal(tdx,0)) && (equal(tdy,0)))
|
2012-08-31 15:46:59 +00:00
|
|
|
|
{
|
|
|
|
|
// free
|
|
|
|
|
draw_tx = cur_tx;
|
|
|
|
|
draw_ty += dy;
|
|
|
|
|
merged = true;
|
|
|
|
|
}
|
|
|
|
|
// else fail
|
2012-08-19 10:02:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-31 15:46:59 +00:00
|
|
|
|
//else no solution
|
2012-08-19 10:02:18 +00:00
|
|
|
|
}
|
2012-09-18 08:02:17 +00:00
|
|
|
|
// else force new line
|
2012-08-31 15:46:59 +00:00
|
|
|
|
|
|
|
|
|
if(!merged)
|
2012-08-19 10:02:18 +00:00
|
|
|
|
{
|
2012-10-02 18:19:40 +00:00
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_DIV);
|
2012-08-19 10:02:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
|
// letter space
|
2012-10-02 06:19:20 +00:00
|
|
|
|
// depends: draw_text_scale
|
|
|
|
|
if(all_changed || letter_space_changed || draw_text_scale_changed)
|
2012-08-15 10:48:11 +00:00
|
|
|
|
{
|
|
|
|
|
double new_letter_space = state->getCharSpace();
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!equal(cur_letter_space, new_letter_space))
|
2012-08-15 10:48:11 +00:00
|
|
|
|
{
|
2012-10-02 18:19:40 +00:00
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
2012-08-15 10:48:11 +00:00
|
|
|
|
cur_letter_space = new_letter_space;
|
2012-10-02 06:19:20 +00:00
|
|
|
|
cur_ls_id = install_letter_space(cur_letter_space * draw_text_scale);
|
2012-08-15 10:48:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// word space
|
2012-10-02 06:19:20 +00:00
|
|
|
|
// depends draw_text_scale
|
|
|
|
|
if(all_changed || word_space_changed || draw_text_scale_changed)
|
2012-08-15 10:48:11 +00:00
|
|
|
|
{
|
|
|
|
|
double new_word_space = state->getWordSpace();
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!equal(cur_word_space, new_word_space))
|
2012-08-15 10:48:11 +00:00
|
|
|
|
{
|
2012-10-02 18:19:40 +00:00
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
2012-08-15 10:48:11 +00:00
|
|
|
|
cur_word_space = new_word_space;
|
2012-10-02 06:19:20 +00:00
|
|
|
|
cur_ws_id = install_word_space(cur_word_space * draw_text_scale);
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-15 10:48:11 +00:00
|
|
|
|
// color
|
2013-01-31 22:21:57 +00:00
|
|
|
|
if(all_changed || fill_color_changed || stroke_color_changed)
|
2012-08-15 10:48:11 +00:00
|
|
|
|
{
|
2012-10-12 14:39:58 +00:00
|
|
|
|
/*
|
2013-02-02 12:32:09 +00:00
|
|
|
|
* PDF Spec. Table 106 – Text rendering modes
|
2012-10-12 14:39:58 +00:00
|
|
|
|
*/
|
2013-02-02 12:32:09 +00:00
|
|
|
|
|
|
|
|
|
static const char FILL[8] = { true, false, true, false, true, false, true, false };
|
|
|
|
|
static const char STROKE[8] = { false, true, true, false, false, true, true, false };
|
2013-01-31 22:21:57 +00:00
|
|
|
|
|
2013-02-02 12:32:09 +00:00
|
|
|
|
int idx = state->getRender();
|
|
|
|
|
assert((idx >= 0) && (idx < 8));
|
|
|
|
|
bool is_filled = FILL[idx];
|
|
|
|
|
bool is_stroked = STROKE[idx];
|
2013-01-31 22:21:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fill
|
2013-02-02 12:32:09 +00:00
|
|
|
|
if(is_filled)
|
2012-08-15 10:48:11 +00:00
|
|
|
|
{
|
2013-02-02 12:32:09 +00:00
|
|
|
|
GfxRGB new_color;
|
|
|
|
|
state->getFillRGB(&new_color);
|
2013-01-31 22:21:57 +00:00
|
|
|
|
|
2013-02-02 12:32:09 +00:00
|
|
|
|
if(!cur_has_fill
|
|
|
|
|
|| (!GfxRGB_equal()(new_color, cur_fill_color))
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
|
|
|
|
cur_fill_color = new_color;
|
|
|
|
|
cur_fill_color_id = install_fill_color(&new_color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-01-31 22:21:57 +00:00
|
|
|
|
cur_fill_color_id = install_fill_color(nullptr);
|
|
|
|
|
}
|
2013-02-02 12:32:09 +00:00
|
|
|
|
cur_has_fill = is_filled;
|
2013-01-31 22:21:57 +00:00
|
|
|
|
|
|
|
|
|
// stroke
|
2013-02-02 12:32:09 +00:00
|
|
|
|
if(is_stroked)
|
2013-01-31 22:21:57 +00:00
|
|
|
|
{
|
2013-02-02 12:32:09 +00:00
|
|
|
|
GfxRGB new_color;
|
|
|
|
|
state->getStrokeRGB(&new_color);
|
|
|
|
|
|
|
|
|
|
if(!cur_has_stroke
|
|
|
|
|
|| (!GfxRGB_equal()(new_color, cur_stroke_color))
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
|
|
|
|
cur_stroke_color = new_color;
|
|
|
|
|
cur_stroke_color_id = install_stroke_color(&new_color);
|
|
|
|
|
}
|
2013-01-31 22:21:57 +00:00
|
|
|
|
}
|
2013-02-02 12:32:09 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2013-01-31 22:21:57 +00:00
|
|
|
|
cur_stroke_color_id = install_stroke_color(nullptr);
|
2012-08-15 10:48:11 +00:00
|
|
|
|
}
|
2013-01-31 22:21:57 +00:00
|
|
|
|
cur_has_stroke = is_stroked;
|
2012-08-15 10:48:11 +00:00
|
|
|
|
}
|
2012-08-14 06:35:55 +00:00
|
|
|
|
|
2012-08-24 17:40:43 +00:00
|
|
|
|
// rise
|
2012-10-02 06:19:20 +00:00
|
|
|
|
// depends draw_text_scale
|
|
|
|
|
if(all_changed || rise_changed || draw_text_scale_changed)
|
2012-08-24 17:40:43 +00:00
|
|
|
|
{
|
|
|
|
|
double new_rise = state->getRise();
|
2012-11-29 10:16:05 +00:00
|
|
|
|
if(!equal(cur_rise, new_rise))
|
2012-08-24 17:40:43 +00:00
|
|
|
|
{
|
2012-10-02 18:19:40 +00:00
|
|
|
|
new_line_state = max<NewLineState>(new_line_state, NLS_SPAN);
|
2012-08-24 17:40:43 +00:00
|
|
|
|
cur_rise = new_rise;
|
2012-10-02 06:19:20 +00:00
|
|
|
|
cur_rise_id = install_rise(new_rise * draw_text_scale);
|
2012-08-24 17:40:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-16 12:26:09 +00:00
|
|
|
|
reset_state_change();
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-01 17:59:04 +00:00
|
|
|
|
void HTMLRenderer::prepare_text_line(GfxState * state)
|
2012-08-16 12:26:09 +00:00
|
|
|
|
{
|
2012-09-04 15:33:15 +00:00
|
|
|
|
if(!line_opened)
|
2012-08-16 12:26:09 +00:00
|
|
|
|
{
|
2012-09-09 06:48:10 +00:00
|
|
|
|
new_line_state = NLS_DIV;
|
2012-08-16 12:26:09 +00:00
|
|
|
|
}
|
2012-09-04 15:33:15 +00:00
|
|
|
|
|
2012-09-09 06:48:10 +00:00
|
|
|
|
if(new_line_state == NLS_DIV)
|
2012-08-16 12:26:09 +00:00
|
|
|
|
{
|
2012-10-01 17:59:04 +00:00
|
|
|
|
close_text_line();
|
2012-08-16 12:26:09 +00:00
|
|
|
|
|
2012-12-11 12:48:01 +00:00
|
|
|
|
text_line_buf->reset(state);
|
2012-09-04 15:33:15 +00:00
|
|
|
|
|
|
|
|
|
//resync position
|
|
|
|
|
draw_ty = cur_ty;
|
|
|
|
|
draw_tx = cur_tx;
|
2012-08-24 17:15:15 +00:00
|
|
|
|
}
|
2012-09-04 15:33:15 +00:00
|
|
|
|
else
|
2012-08-24 17:15:15 +00:00
|
|
|
|
{
|
|
|
|
|
// align horizontal position
|
|
|
|
|
// try to merge with the last line if possible
|
2012-10-02 06:19:20 +00:00
|
|
|
|
double target = (cur_tx - draw_tx) * draw_text_scale;
|
2012-08-24 17:15:15 +00:00
|
|
|
|
if(abs(target) < param->h_eps)
|
|
|
|
|
{
|
|
|
|
|
// ignore it
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2012-12-11 12:48:01 +00:00
|
|
|
|
text_line_buf->append_offset(target);
|
2012-10-02 06:19:20 +00:00
|
|
|
|
draw_tx += target / draw_text_scale;
|
2012-08-24 17:15:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-16 10:11:22 +00:00
|
|
|
|
|
2012-09-09 06:48:10 +00:00
|
|
|
|
if(new_line_state != NLS_NONE)
|
2012-08-16 10:11:22 +00:00
|
|
|
|
{
|
2012-12-11 12:48:01 +00:00
|
|
|
|
text_line_buf->append_state();
|
2012-08-16 10:11:22 +00:00
|
|
|
|
}
|
2012-09-04 15:33:15 +00:00
|
|
|
|
|
|
|
|
|
line_opened = true;
|
2012-08-14 06:35:55 +00:00
|
|
|
|
}
|
2012-09-04 15:33:15 +00:00
|
|
|
|
|
2012-10-01 17:59:04 +00:00
|
|
|
|
void HTMLRenderer::close_text_line()
|
2012-08-14 06:35:55 +00:00
|
|
|
|
{
|
2012-09-04 15:33:15 +00:00
|
|
|
|
if(line_opened)
|
|
|
|
|
{
|
|
|
|
|
line_opened = false;
|
2012-12-11 12:48:01 +00:00
|
|
|
|
text_line_buf->flush();
|
2012-09-04 15:33:15 +00:00
|
|
|
|
}
|
2012-08-16 10:11:22 +00:00
|
|
|
|
}
|
2012-09-12 15:26:14 +00:00
|
|
|
|
|
|
|
|
|
} //namespace pdf2htmlEX
|