Returns the gutter width of the given TabVector between the given y limits. Also returns x-shift to be added to the vector to clear any intersecting blobs. The shift is deducted from the returned gutter. If ignore_unmergeables is true, then blobs of UnMergeableType are ignored as if they don't exist. (Used for text on image.) max_gutter_width is used as the maximum width worth searching for in cas
| 160 | // max_gutter_width is used as the maximum width worth searching for in case |
| 161 | // there is nothing near the TabVector. |
| 162 | int TabFind::GutterWidth(int bottom_y, int top_y, const TabVector& v, |
| 163 | bool ignore_unmergeables, int max_gutter_width, |
| 164 | int* required_shift) { |
| 165 | bool right_to_left = v.IsLeftTab(); |
| 166 | int bottom_x = v.XAtY(bottom_y); |
| 167 | int top_x = v.XAtY(top_y); |
| 168 | int start_x = right_to_left ? MAX(top_x, bottom_x) : MIN(top_x, bottom_x); |
| 169 | BlobGridSearch sidesearch(this); |
| 170 | sidesearch.StartSideSearch(start_x, bottom_y, top_y); |
| 171 | int min_gap = max_gutter_width; |
| 172 | *required_shift = 0; |
| 173 | BLOBNBOX* blob = NULL; |
| 174 | while ((blob = sidesearch.NextSideSearch(right_to_left)) != NULL) { |
| 175 | const TBOX& box = blob->bounding_box(); |
| 176 | if (box.bottom() >= top_y || box.top() <= bottom_y) |
| 177 | continue; // Doesn't overlap enough. |
| 178 | if (box.height() >= gridsize() * 2 && |
| 179 | box.height() > box.width() * kLineFragmentAspectRatio) { |
| 180 | // Skip likely separator line residue. |
| 181 | continue; |
| 182 | } |
| 183 | if (ignore_unmergeables && BLOBNBOX::UnMergeableType(blob->region_type())) |
| 184 | continue; // Skip non-text if required. |
| 185 | int mid_y = (box.bottom() + box.top()) / 2; |
| 186 | // We use the x at the mid-y so that the required_shift guarantees |
| 187 | // to clear all the blobs on the tab-stop. If we use the min/max |
| 188 | // of x at top/bottom of the blob, then exactness would be required, |
| 189 | // which is not a good thing. |
| 190 | int tab_x = v.XAtY(mid_y); |
| 191 | int gap; |
| 192 | if (right_to_left) { |
| 193 | gap = tab_x - box.right(); |
| 194 | if (gap < 0 && box.left() - tab_x < *required_shift) |
| 195 | *required_shift = box.left() - tab_x; |
| 196 | } else { |
| 197 | gap = box.left() - tab_x; |
| 198 | if (gap < 0 && box.right() - tab_x > *required_shift) |
| 199 | *required_shift = box.right() - tab_x; |
| 200 | } |
| 201 | if (gap > 0 && gap < min_gap) |
| 202 | min_gap = gap; |
| 203 | } |
| 204 | // Result may be negative, in which case, this is a really bad tabstop. |
| 205 | return min_gap - abs(*required_shift); |
| 206 | } |
| 207 | |
| 208 | // Find the gutter width and distance to inner neighbour for the given blob. |
| 209 | void TabFind::GutterWidthAndNeighbourGap(int tab_x, int mean_height, |
no test coverage detected