From 1d95b73eee696c045840bf3ebb9b78bf07bfc8fd Mon Sep 17 00:00:00 2001 From: Duan Yao Date: Sun, 15 Jun 2014 16:42:34 +0800 Subject: [PATCH] Handle clips during processing of covered text. --- src/CoveredTextHandler.cc | 11 ++++-- src/CoveredTextHandler.h | 3 +- src/DrawingTracer.cc | 68 +++++++++++++++++++++++++++---------- src/DrawingTracer.h | 5 ++- src/HTMLRenderer/draw.cc | 3 +- src/HTMLRenderer/general.cc | 2 +- src/util/math.cc | 28 ++++++++++++--- src/util/math.h | 10 ++++-- 8 files changed, 100 insertions(+), 30 deletions(-) diff --git a/src/CoveredTextHandler.cc b/src/CoveredTextHandler.cc index 8557b57..9f8074a 100644 --- a/src/CoveredTextHandler.cc +++ b/src/CoveredTextHandler.cc @@ -30,11 +30,18 @@ void CoveredTextHandler::reset() void CoveredTextHandler::add_char_bbox(double * bbox) { - for (int i = 0; i < 4; i++) - char_bboxes.push_back(bbox[i]); + char_bboxes.insert(char_bboxes.end(), bbox, bbox + 4); chars_covered.push_back(false); } +void CoveredTextHandler::add_char_bbox_clipped(double * bbox, bool patially) +{ + char_bboxes.insert(char_bboxes.end(), bbox, bbox + 4); + chars_covered.push_back(true); + if (patially) + add_non_char_bbox(bbox, chars_covered.size() - 1); +} + void CoveredTextHandler::add_non_char_bbox(double * bbox, int index) { if (index < 0) diff --git a/src/CoveredTextHandler.h b/src/CoveredTextHandler.h index 34decf6..0531236 100644 --- a/src/CoveredTextHandler.h +++ b/src/CoveredTextHandler.h @@ -32,6 +32,8 @@ public: */ void add_char_bbox(double * bbox); + void add_char_bbox_clipped(double * bbox, bool patially); + /** * Add a drawn non-char graphics' bounding box. * If it intersects any previously drawn char's bbox, the char is marked as covered @@ -51,7 +53,6 @@ public: const std::vector & get_chars_covered() { return chars_covered; } private: - //covered text test std::vector chars_covered; // x00, y00, x01, y01; x10, y10, x11, y11;... std::vector char_bboxes; diff --git a/src/DrawingTracer.cc b/src/DrawingTracer.cc index 15b9f20..7c55f2e 100644 --- a/src/DrawingTracer.cc +++ b/src/DrawingTracer.cc @@ -53,15 +53,15 @@ void DrawingTracer::set_ctm(GfxState *state) matrix.yy = ctm[3]; matrix.x0 = ctm[4]; matrix.y0 = ctm[5]; - cairo_set_matrix (cairo, &matrix); + cairo_set_matrix(cairo, &matrix); } void DrawingTracer::clip(GfxState * state, bool even_odd) { if (!param.process_covered_text) return; - do_path (state, state->getPath()); - cairo_set_fill_rule (cairo, even_odd? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + do_path(state, state->getPath()); + cairo_set_fill_rule(cairo, even_odd? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); cairo_clip (cairo); } @@ -91,13 +91,13 @@ void DrawingTracer::do_path(GfxState * state, GfxPath * path) GfxSubpath *subpath; int i, j; double x, y; - cairo_new_path (cairo); + cairo_new_path(cairo); for (i = 0; i < path->getNumSubpaths(); ++i) { subpath = path->getSubpath(i); if (subpath->getNumPoints() > 0) { x = subpath->getX(0); y = subpath->getY(0); - cairo_move_to (cairo, x, y); + cairo_move_to(cairo, x, y); j = 1; while (j < subpath->getNumPoints()) { if (subpath->getCurve(j)) { @@ -111,7 +111,7 @@ void DrawingTracer::do_path(GfxState * state, GfxPath * path) } else { x = subpath->getX(j); y = subpath->getY(j); - cairo_line_to (cairo, x, y); + cairo_line_to(cairo, x, y); ++j; } } @@ -150,22 +150,56 @@ void DrawingTracer::fill(GfxState * state, bool even_odd) void DrawingTracer::draw_non_char_bbox(GfxState * state, double * bbox) { - double cbox[4], result[4]; + double cbox[4]; cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3); - // TODO intersect - tm_transform_bbox(state->getCTM(), bbox); - if (on_non_char_drawn) - on_non_char_drawn(bbox); + if(bbox_intersect(cbox, bbox, bbox)) + { + tm_transform_bbox(state->getCTM(), bbox); + if (on_non_char_drawn) + on_non_char_drawn(bbox); + } } void DrawingTracer::draw_char_bbox(GfxState * state, double * bbox) { - double cbox[4], result[4]; - cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3); - // TODO intersect - tm_transform_bbox(state->getCTM(), bbox); - if (on_char_drawn) - on_char_drawn(bbox); + // Note: even if 4 corner of the char are all in the clip area, + // it still could be partially clipped. + // TODO better solution? + int pt_in = 0; + if (cairo_in_clip(cairo, bbox[0], bbox[1])) + ++pt_in; + if (cairo_in_clip(cairo, bbox[2], bbox[3])) + ++pt_in; + if (cairo_in_clip(cairo, bbox[2], bbox[1])) + ++pt_in; + if (cairo_in_clip(cairo, bbox[0], bbox[3])) + ++pt_in; + + if (pt_in == 0) + { + if(on_char_clipped) + on_char_clipped(bbox, false); + } + else + { + if (pt_in < 4) + { + double cbox[4]; + cairo_clip_extents(cairo, cbox, cbox + 1, cbox + 2, cbox + 3); + bbox_intersect(cbox, bbox, bbox); + } + tm_transform_bbox(state->getCTM(), bbox); + if (pt_in < 4) + { + if(on_char_clipped) + on_char_clipped(bbox, true); + } + else + { + if (on_char_drawn) + on_char_drawn(bbox); + } + } } void DrawingTracer::draw_image(GfxState *state) diff --git a/src/DrawingTracer.h b/src/DrawingTracer.h index 81fd4b0..032c511 100644 --- a/src/DrawingTracer.h +++ b/src/DrawingTracer.h @@ -25,9 +25,12 @@ public: * The callback to receive drawn event. * bbox in device space. */ + // a non-char graphics is drawn std::function on_non_char_drawn; + // a char is drawn in the clip area std::function on_char_drawn; - std::function on_char_clipped; + // a char is drawn out of/partially in the clip area + std::function on_char_clipped; DrawingTracer(const Param & param); virtual ~DrawingTracer(); diff --git a/src/HTMLRenderer/draw.cc b/src/HTMLRenderer/draw.cc index b87c897..9b3f1bd 100644 --- a/src/HTMLRenderer/draw.cc +++ b/src/HTMLRenderer/draw.cc @@ -32,7 +32,8 @@ using std::ostream; void HTMLRenderer::restoreState(GfxState * state) { - updateAll(state); tracer.restore(); + updateAll(state); + tracer.restore(); } void HTMLRenderer::saveState(GfxState *state) diff --git a/src/HTMLRenderer/general.cc b/src/HTMLRenderer/general.cc index d784f3b..c032e0e 100644 --- a/src/HTMLRenderer/general.cc +++ b/src/HTMLRenderer/general.cc @@ -82,7 +82,7 @@ HTMLRenderer::HTMLRenderer(const Param & param) tracer.on_char_drawn = [this](double * box) { covered_text_handler.add_char_bbox(box); }; tracer.on_char_clipped = - [this](double * box) { covered_text_handler.add_char_bbox(box); }; //TODO + [this](double * box, bool partial) { covered_text_handler.add_char_bbox_clipped(box, partial); }; tracer.on_non_char_drawn = [this](double * box) { covered_text_handler.add_non_char_bbox(box); }; } diff --git a/src/util/math.cc b/src/util/math.cc index fb898c6..1ddabce 100644 --- a/src/util/math.cc +++ b/src/util/math.cc @@ -60,12 +60,30 @@ void tm_transform_bbox(const double * tm, double * bbox) } } -bool bbox_intersect(double * bbox1, double * bbox2) +bool bbox_intersect(const double * bbox1, const double * bbox2, double * result) { - return min(bbox1[0], bbox1[2]) < max(bbox2[0], bbox2[2]) - && max(bbox1[0], bbox1[2]) > min(bbox2[0], bbox2[2]) - && min(bbox1[1], bbox1[3]) < max(bbox2[1], bbox2[3]) - && max(bbox1[1], bbox1[3]) > min(bbox2[1], bbox2[3]); + double x0, y0, x1, y1; + + x0 = max(min(bbox1[0], bbox1[2]), min(bbox2[0], bbox2[2])); + x1 = min(max(bbox1[0], bbox1[2]), max(bbox2[0], bbox2[2])); + + if (x0 >= x1) + return false; + + y0 = max(min(bbox1[1], bbox1[3]), min(bbox2[1], bbox2[3])); + y1 = min(max(bbox1[1], bbox1[3]), max(bbox2[1], bbox2[3])); + + if (y0 >= y1) + return false; + + if (result) + { + result[0] = x0; + result[1] = y0; + result[2] = x1; + result[3] = y1; + } + return true; } } //namespace pdf2htmlEX diff --git a/src/util/math.h b/src/util/math.h index fcdebc4..75997f9 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -39,8 +39,14 @@ static inline double hypot(double x, double y) { return std::sqrt(x*x+y*y); } void tm_transform(const double * tm, double & x, double & y, bool is_delta = false); void tm_multiply(double * tm_left, const double * tm_right); void tm_transform_bbox(const double * tm, double * bbox); - -bool bbox_intersect(double * bbox1, double * bbox2); +/** + * Calculate the intersection of 2 boxes. + * If they are intersecting, store the result to result (if not null) and return true. + * Otherwise return false, and result is not touched. + * Param result can be same as one of bbox1 and bbox2. + * Data in boxes are expected in the order of (x0, y0, x1, y1). + */ +bool bbox_intersect(const double * bbox1, const double * bbox2, double * result = nullptr); } //namespace pdf2htmlEX #endif //MATH_H__