w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

hints.c
Go to the documentation of this file.
1 /* $XConsortium: hints.c,v 1.4 91/10/10 11:18:13 rws Exp $ */
2 /* Copyright International Business Machines, Corp. 1991
3  * All Rights Reserved
4  * Copyright Lexmark International, Inc. 1991
5  * All Rights Reserved
6  *
7  * License to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted,
9  * provided that the above copyright notice appear in all copies and that
10  * both that copyright notice and this permission notice appear in
11  * supporting documentation, and that the name of IBM or Lexmark not be
12  * used in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.
14  *
15  * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
16  * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
17  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
18  * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
19  * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
20  * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
21  * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
22  * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
23  * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
24  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
25  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
26  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27  * THIS SOFTWARE.
28  */
29  /* HINTS CWEB V0006 ******** */
30 /*
31 :h1.HINTS Module - Processing Rasterization Hints
32 
33 &author. Sten F. Andler; continuity by Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com) and Duaine
34 W. Pryor, Jr.
35 
36 
37 :h3.Include Files
38 
39 The included files are:
40 */
41 
42 #include "types.h"
43 #include "objects.h"
44 #include "spaces.h"
45 #include "paths.h"
46 #include "regions.h"
47 #include "hints.h"
48 
49 /*
50 :h3.Functions Provided to the TYPE1IMAGER User
51 
52 None.
53 */
54 
55 /*
56 :h3.Functions Provided to Other Modules
57 
58 This module provides the following entry point to other modules:
59 */
60 
61 
62 /*SHARED LINE(S) ORIGINATED HERE*/
63 
64 /*
65 :h3.Macros Provided to Other Modules
66 
67 None.
68 */
69 
70 /*
71 :h2.InitHints() - Initialize hint data structure
72 */
73 
74 #define MAXLABEL 20
75 static struct {
76  int inuse;
77  int computed;
78  struct fractpoint hint;
80 
81 #define ODD(x) (((int)(x)) & 01)
82 #define FPFLOOR(fp) TOFRACTPEL((fp) >> FRACTBITS)
83 #define FPROUND(fp) FPFLOOR((fp) + FPHALF)
84 
85 void InitHints(void)
86 {
87  int i;
88 
89  for (i = 0; i < MAXLABEL; i++)
90  {
91  oldHint[i].inuse = FALSE;
92  oldHint[i].computed = FALSE;
93  }
94 }
95 
96 /*
97 :h3.CloseHints(hintP) - Reverse hints that are still open
98 */
99 
100 void CloseHints(struct fractpoint *hintP)
101 {
102  int i;
103 
104  for (i = 0; i < MAXLABEL; i++)
105  {
106  if (oldHint[i].inuse)
107  {
108  hintP->x -= oldHint[i].hint.x;
109  hintP->y -= oldHint[i].hint.y;
110 
111  oldHint[i].inuse = FALSE;
112 
113  IfTrace3((HintDebug > 1)," Hint %d was open, hint=(%dl,%dl)\n",
114  i, hintP->x, hintP->y);
115  }
116  }
117 }
118 
119 /*
120 :h3.ComputeHint(hP, currX, currY, hintP) - Compute the value of a hint
121 */
122 
123 static void ComputeHint(struct hintsegment *hP, fractpel currX, fractpel currY,
124  struct fractpoint *hintP)
125 {
126  fractpel currRef = 0, currWidth = 0;
127  int idealWidth;
128  fractpel hintValue = 0;
129  char orientation;
130 
131 /*
132 By construction, width is never zero. Therefore we can use the
133 width value to determine if the hint has been rotated by a
134 multiple of 90 degrees.
135 */
136 
137  if (hP->width.y == 0)
138  {
139  orientation = 'v'; /* vertical */
140  IfTrace0((HintDebug > 0)," vertical hint\n");
141  }
142  else if (hP->width.x == 0)
143  {
144  orientation = 'h'; /* horizontal */
145  IfTrace0((HintDebug > 0)," horizontal hint\n");
146  }
147  else
148  {
149  IfTrace0((HintDebug > 0)," hint not vertical or horizontal\n");
150  hintP->x = hintP->y = 0;
151  return;
152  }
153 
154  /* Compute currRef and currWidth with a unit of 1 pel */
155  if (orientation == 'v') /* vertical */
156  {
157  currRef = hP->ref.x + currX;
158  currWidth = ABS(hP->width.x);
159  }
160  else if (orientation == 'h') /* horizontal */
161  {
162  currRef = hP->ref.y + currY;
163  currWidth = ABS(hP->width.y);
164  }
165  else /* error */
166  {
167  t1_abort("ComputeHint: invalid orientation");
168  }
169 
170  IfTrace4((HintDebug > 1),
171  " currX=%dl, currY=%dl, currRef=%dl, currWidth=%dl\n",
172  currX, currY,
173  currRef, currWidth);
174 
175  if ((hP->hinttype == 'b') /* Bar or stem */
176  || (hP->hinttype == 's')) /* Serif */
177  {
178  idealWidth = NEARESTPEL(currWidth);
179  if (idealWidth == 0) idealWidth = 1;
180  if (ODD(idealWidth)) /* Is ideal width odd? */
181  {
182  /* center "ref" over pel */
183  hintValue = FPFLOOR(currRef) + FPHALF - currRef;
184  }
185  else
186  {
187  /* align "ref" on pel boundary */
188  hintValue = FPROUND(currRef) - currRef;
189  }
190  if (HintDebug > 2) {
191  IfTrace1(TRUE," idealWidth=%d, ", idealWidth);
192  }
193  }
194  else if (hP->hinttype == 'c') /* Curve extrema */
195  {
196  /* align "ref" on pel boundary */
197  hintValue = FPROUND(currRef) - currRef;
198  }
199  else /* error */
200  {
201  t1_abort("ComputeHint: invalid hinttype");
202  }
203 
204  IfTrace1((HintDebug > 1)," hintValue=%dl", hintValue);
205 
206  if (orientation == 'v') /* vertical */
207  {
208  hintP->x = hintValue;
209  hintP->y = 0;
210  }
211  else if (orientation == 'h') /* horizontal */
212  {
213  hintP->x = 0;
214  hintP->y = hintValue;
215  }
216  else /* error */
217  {
218  t1_abort("ComputeHint: invalid orientation");
219  }
220 }
221 
222 /*
223 :h3.ProcessHint(hP, currX, currY, hintP) - Process a rasterization hint
224 */
225 
226 void ProcessHint(struct hintsegment *hP, fractpel currX, fractpel currY,
227  struct fractpoint *hintP)
228 {
229  struct fractpoint thisHint = { 0, 0 };
230 
231  IfTrace4((HintDebug > 1)," ref=(%dl,%dl), width=(%dl,%dl)",
232  hP->ref.x, hP->ref.y,
233  hP->width.x, hP->width.y);
234  IfTrace4((HintDebug > 1),", %c %c %c %c",
235  hP->orientation, hP->hinttype,
236  hP->adjusttype, hP->direction);
237  IfTrace1((HintDebug > 1),", label=%d\n", hP->label);
238 
239  if ((hP->adjusttype == 'm') /* Move */
240  || (hP->adjusttype == 'a')) /* Adjust */
241  {
242  /* Look up hint in oldHint table */
243  if ((hP->label >= 0) && (hP->label < MAXLABEL))
244  {
245  if (oldHint[hP->label].computed)
246  /* Use old hint value if already computed */
247  {
248  thisHint.x = oldHint[hP->label].hint.x;
249  thisHint.y = oldHint[hP->label].hint.y;
250  oldHint[hP->label].inuse = TRUE;
251  }
252  else
253  /* Compute new value for hint and store it for future use */
254  {
255  ComputeHint(hP, currX, currY, &thisHint);
256 
257  oldHint[hP->label].hint.x = thisHint.x;
258  oldHint[hP->label].hint.y = thisHint.y;
259  oldHint[hP->label].inuse = TRUE;
260  oldHint[hP->label].computed = TRUE;
261  }
262  }
263  else /* error */
264  {
265  t1_abort("ProcessHint: invalid label");
266  }
267  }
268  else if (hP->adjusttype == 'r') /* Reverse */
269  {
270  /* Use the inverse of the existing hint value to reverse hint */
271  if ((hP->label >= 0) && (hP->label < MAXLABEL))
272  {
273  if (oldHint[hP->label].inuse)
274  {
275  thisHint.x = -oldHint[hP->label].hint.x;
276  thisHint.y = -oldHint[hP->label].hint.y;
277  oldHint[hP->label].inuse = FALSE;
278  }
279  else /* error */
280  {
281  t1_abort("ProcessHint: label is not in use");
282  }
283  }
284  else /* error */
285  {
286  t1_abort("ProcessHint: invalid label");
287  }
288 
289  }
290  else /* error */
291  {
292  t1_abort("ProcessHint: invalid adjusttype");
293  }
294  IfTrace3((HintDebug > 1)," label=%d, thisHint=(%dl,%dl)\n",
295  hP->label, thisHint.x, thisHint.y);
296 
297  hintP->x += thisHint.x;
298  hintP->y += thisHint.y;
299 
300  IfTrace2((HintDebug > 1)," hint=(%dl,%dl)\n",
301  hintP->x, hintP->y);
302 }
303 
304 /*
305 :h2 id=subpath.Navigation Through Edge Lists
306 
307 For continuity checking purposes, we need to navigate through edge
308 lists by the "subpath" chains and answer questions about edges. The
309 subpath chain links together edges that were part of the same subpath
310 (no intervening move segments) when the interior of the path was
311 calculated. Here we use the term "edge" to mean every edge list
312 that was created in between changes of direction.
313 
314 The subpath chains are singly-linked circular chains. For the convenience
315 of building them, they direction of the list (from edge to edge) is the
316 reverse of the order in which they were built. Within any single edge,
317 the subpath chain goes from top-to-bottom. (There might be a violation
318 of this because of the way the user started the first chain; see
319 :hdref refid=fixsubp..).
320 
321 :h3.ISTOP() and ISBOTTOM() - Flag Bits for Edge Lists at the Top and
322 Bottom of Their SubPaths
323 */
324 
325 #define ISTOP(flag) ((flag)&0x20)
326 #define ISBOTTOM(flag) ((flag)&0x10)
327 /*
328 :h3.ISLEFT() - Flag Bit for Left Edges
329 */
330 
331 #define ISLEFT(flag) ((flag)&0x08)
332 
333 /*
334 :h3.XofY() - Macro to Find X Value at Given Y
335 
336 This macro can only be used if it is known that the Y is within the
337 given edgelist's ymin and ymax.
338 */
339 
340 #define XofY(edge, y) edge->xvalues[y - edge->ymin]
341 
342 /*
343 :h3.findXofY() - Like XofY(), Except not Restricted
344 
345 If the Y is out of bounds of the given edgelist, this macro will
346 call SearchXofY to search the edge's subpath chain for the correct
347 Y range. If the Y value is off the edge, MINPEL is returned.
348 */
349 #define findXofY(edge, y) ((y < edge->ymin || y >= edge->ymax) ? SearchXofY(edge, y) : XofY(edge, y))
350 
351 /*
352 :h4.SearchXofY() - Routine Called by FindXofY() for Difficult Cases
353 
354 The concept of this routine is to follow the subpath chain to find the
355 edge just below (i.e., next in chain) or just above (i.e., immediately
356 before in chain. It is assumed that the Y value is no more than one
357 off of the edge's range; XofY() could be replace by FindXofY() to
358 call ourselves recursively if this were not true.
359 */
360 
362  register struct edgelist *edge, /* represents edge */
363  register pel y) /* 'y' value to find edge for */
364 {
365  register struct edgelist *e; /* loop variable */
366 
367  if (y < edge->ymin) {
368  if (ISTOP(edge->flag))
369  return(MINPEL);
370  for (e = edge->subpath; e->subpath != edge; e = e->subpath) { ; }
371  if (e->ymax == edge->ymin)
372  return(XofY(e, y));
373  }
374  else if (y >= edge->ymax) {
375  if (ISBOTTOM(edge->flag))
376  return(MINPEL);
377  e = edge->subpath;
378  if (e->ymin == edge->ymax)
379  return(XofY(e, y));
380  }
381  else
382  return(XofY(edge, y));
383 
384  t1_abort("bad subpath chain");
385 
386  /*NOTREACHED*/
387  return MINPEL;
388 }
389 /*
390 :h3.ISBREAK() Macro - Tests if an Edge List is at a "Break"
391 
392 The subpath chains are organized top to bottom. When the bottom of
393 a given edge is reached, the subpath chain points to the top of the
394 next edge. We call this a "break" in the chain. The following macro
395 is the simple test for the break condition:
396 */
397 
398 #define ISBREAK(top,bot) (top->ymax != bot->ymin)
399 
400 
401 /*
402 :h3.ImpliedHorizontalLine() - Tests for Horizontal Connectivity
403 
404 This function returns true if two edges are connected horizontally.
405 They are connected horizontally if they are consecutive in the subpath,
406 and either we are at the bottom and the first edge is going down or we
407 are at the top and the first edge is going up.
408 */
409 
410 #define BLACKABOVE -1
411 #define BLACKBELOW +1
412 #define NONE 0
413 
415  register struct edgelist *e1, /* two edges ... */
416  register struct edgelist *e2, /* ... to check */
417  register int y) /* y where they might be connected */
418 {
419  register struct edgelist *e3,*e4;
420 
421  if (ISDOWN(e1->flag) == ISDOWN(e2->flag))
422  return(NONE); /* can't be consecutive unless different directions */
423 /*
424 Now we check for consecutiveness: Can we get from 'e1' to 'e2' with
425 only one intervening break? Can we get from 'e2' to 'e1' with only one
426 intervening break? 'e3' will be as far as we can get after 'e1'; 'e4'
427 will be has far as we can get after 'e2':
428 */
429  for (e3 = e1; !ISBREAK(e3, e3->subpath); e3 = e3->subpath) { ; }
430  for (e3 = e3->subpath; e3 != e2; e3 = e3->subpath)
431  if (ISBREAK(e3, e3->subpath))
432  break;
433 
434  for (e4 = e2; !ISBREAK(e4, e4->subpath); e4 = e4->subpath) { ; }
435  for (e4 = e4->subpath; e4 != e1; e4 = e4->subpath)
436  if (ISBREAK(e4, e4->subpath))
437  break;
438 /*
439 If the edges are mutually consecutive, we must have horizontal lines
440 both top and bottom:
441 */
442  if (e3 == e2 && e4 == e1)
443  return(TRUE);
444 /*
445 If the edges are not consecutive either way, no horizontal lines are
446 possible:
447 */
448  if (e3 != e2 && e4 != e1)
449  return(NONE);
450 /*
451 Now let's swap 'e1' and 'e2' if necessary to enforce the rule that 'e2'
452 follows 'e1'. Remember that subpath chains go in the opposite direction
453 from the way the subpaths were built; this led to the simplest way
454 do build them.
455 */
456  if (e4 != e1) {
457  e2 = e1;
458  e1 = e3; /* remember e3 == e2, this just swaps 'e1' and 'e2' */
459  }
460 /*
461 Now we have everything to return the answer:
462 */
463  if (ISTOP(e1->flag) && y == e1->ymin)
464  return(ISDOWN(e2->flag));
465  else if (ISBOTTOM(e1->flag) && y == e1->ymax)
466  return(!ISDOWN(e2->flag));
467  else
468  t1_abort("ImpliedHorizontalLine: why ask?");
469  /*NOTREACHED*/
470  return 0;
471 }
472 
473 /*
474 :h3 id=fixsubp.FixSubPaths() - Must be Called to Organize Subpath Chains
475 
476 The region-building code in Interior(), in particular splitedge(),
477 maintains the rule that sub-paths are linked top-to-bottom except
478 at breaks. However, it is possible that there may be a "false break"
479 because the user started the subpath in the middle of an edge (and
480 went in the "wrong" direction from there, up instead of down). This
481 routine finds and fixes false breaks.
482 
483 Also, this routine sets the ISTOP and ISBOTTOM flags in the edge lists.
484 */
485 
486 static void FixSubPaths(
487  register struct region *R) /* anchor of region */
488 {
489  register struct edgelist *e; /* fast loop variable */
490  register struct edgelist *edge; /* current edge in region */
491  register struct edgelist *next; /* next in subpath after 'edge' */
492  register struct edgelist *break1; /* first break after 'next' */
493  register struct edgelist *break2 = NULL; /* last break before 'edge' */
494  register struct edgelist *prev; /* previous edge for fixing links */
495  int left = TRUE;
496 
497  for (edge = R->anchor; edge != NULL; edge = edge->link) {
498 
499  if (left)
500  edge->flag |= ISLEFT(ON);
501  left = !left;
502 
503  next = edge->subpath;
504 
505  if (!ISBREAK(edge, next))
506  continue;
507  if (edge->ymax < next->ymin)
508  t1_abort("disjoint subpath?");
509 /*
510 'edge' now contains an edgelist at the bottom of an edge, and 'next'
511 contains the next subsequent edgelist in the subpath, which must be at
512 the top. We refer to this a "break" in the subpath.
513 */
514  next->flag |= ISTOP(ON);
515  edge->flag |= ISBOTTOM(ON);
516 
517  if (ISDOWN(edge->flag) != ISDOWN(next->flag))
518  continue;
519 /*
520 We are now in the unusual case; both edges are going in the same
521 direction so this must be a "false break" due to the way that the user
522 created the path. We'll have to fix it.
523 */
524  for (break1 = next; !ISBREAK(break1, break1->subpath); break1 = break1->subpath) { ; }
525 
526  for (e = break1->subpath; e != edge; e = e->subpath)
527  if (ISBREAK(e, e->subpath))
528  break2 = e;
529 /*
530 Now we've set up 'break1' and 'break2'. I've found the following
531 diagram invaluable. 'break1' is the first break after 'next'. 'break2'
532 is the LAST break before 'edge'.
533 &drawing.
534  next
535  +------+ +---->+------+
536  +--->| >-----+ | | >-----+
537  | | | | | | | |
538  | +-------------+ | +-------------+
539  | | |break1| | | | |
540  | +->| >-------+ +->| >-----+
541  | | | | | |
542  | | | +-------------+
543  | +------+ | | |
544  | +----------------+ | | |
545  | | +------+ | +->| >-----+
546  | +->| >-----+ | | | |
547  | | | | | +-------------+
548  | +-------------+ | | | |
549  | | |edge | | | |break2|
550  | +->| >-----+ | +->| >-----+
551  | | | | | | | |
552  | | | | | | | |
553  | | | | | | | |
554  | +------+ | | +------+ |
555  | | | |
556  +---------------+ +---------------+
557 
558 &edrawing.
559 We want to fix this situation by having 'edge' point to where 'break1'
560 now points, and having 'break1' point to where 'break2' now points.
561 Finally, 'break2' should point to 'next'. Also, we observe that
562 'break1' can't be a bottom, and is also not a top unless it is the same
563 as 'next':
564 */
565  edge->subpath = break1->subpath;
566 
567  break1->subpath = break2->subpath;
568  if (ISBREAK(break1, break1->subpath))
569  t1_abort("unable to fix subpath break?");
570 
571  break2->subpath = next;
572 
573  break1->flag &= ~~ISBOTTOM(ON);
574  if (break1 != next)
575  break1->flag &= ~~ISTOP(ON);
576  }
577 /*
578 This region might contain "ambiguous" edges; edges exactly equal to
579 edge->link. Due to the random dynamics of where they get sorted into
580 the list, they can yield false crossings, where the edges appear
581 to cross. This confuses our continuity logic no end. Since we can
582 swap them without changing the region, we do.
583 */
584  for (edge = R->anchor, prev = NULL; VALIDEDGE(edge); prev = edge, edge = prev->link) {
585 
586  if (! ISAMBIGUOUS(edge->flag))
587  continue;
588 
589  next = edge->subpath;
590 
591  while (ISAMBIGUOUS(next->flag) && next != edge)
592  next = next->subpath;
593 /*
594 We've finally found a non-ambiguous edge; we make sure it is left/right
595 compatible with 'edge':
596 */
597  if ( (ISLEFT(edge->flag) == ISLEFT(next->flag) && ISDOWN(edge->flag) == ISDOWN(next->flag) )
598  || (ISLEFT(edge->flag) != ISLEFT(next->flag) && ISDOWN(edge->flag) != ISDOWN(next->flag) ) )
599  continue;
600 
601 /*
602 Incompatible, we will swap 'edge' and the following edge in the list.
603 You may think that there must be a next edge in this swath. So did I.
604 No! If there is a totally ambiguous inner loop, for example, we could
605 get all the way to the outside without resolving ambiguity.
606 */
607  next = edge->link; /* note new meaning of 'next' */
608  if (next == NULL || edge->ymin != next->ymin)
609  continue;
610  if (prev == NULL)
611  R->anchor = next;
612  else
613  prev->link = next;
614  edge->link = next->link;
615  next->link = edge;
616  edge->flag ^= ISLEFT(ON);
617  edge->flag &= ~~ISAMBIGUOUS(ON);
618  next->flag ^= ISLEFT(ON);
619  next->flag &= ~~ISAMBIGUOUS(ON);
620  edge = next;
621  }
622 }
623 /*
624 :h3.DumpSubPaths()
625 
626 A debug tool.
627 */
628 
629 static struct edgelist *before(struct edgelist *); /* subroutine of DumpSubPaths */
630 
631 static void DumpSubPaths(struct edgelist *anchor)
632 {
633 
634  register struct edgelist *edge,*e,*e2;
635  pel y;
636 
637  for (edge = anchor; VALIDEDGE(edge); edge = edge->link) {
638  if (ISPERMANENT(edge->flag))
639  continue;
640  IfTrace0(TRUE, "BEGIN Subpath\n");
641  for (e2 = edge; !ISPERMANENT(e2->flag);) {
642  if (ISDOWN(e2->flag)) {
643  IfTrace1(TRUE, ". Downgoing edge's top at %p\n", e2);
644  for (e = e2;; e = e->subpath) {
645  IfTrace4(TRUE, ". . [%5d] %5d @ %p[%x]\n",
646  e->ymin, *e->xvalues, e, e->flag);
647  for (y=e->ymin+1; y < e->ymax; y++)
648  IfTrace2(TRUE, ". . [%5d] %5d \"\n", y, e->xvalues[y-e->ymin]);
649  e->flag |= ISPERMANENT(ON);
650  if (ISBREAK(e, e->subpath))
651  break;
652  }
653  }
654  else {
655  IfTrace1(TRUE, ". Upgoing edge's top at %p\n", e2);
656  for (e = e2; !ISBREAK(e, e->subpath); e = e->subpath) { ; }
657  for (;; e=before(e)) {
658  IfTrace4(TRUE, ". . [%5d] %5d @ %p[%x]\n",
659  e->ymax-1, e->xvalues[e->ymax-1-e->ymin], e, e->flag);
660  for (y=e->ymax-2; y >= e->ymin; y--)
661  IfTrace2(TRUE, ". . [%5d] %5d \"\n", y, e->xvalues[y-e->ymin]);
662  e->flag |= ISPERMANENT(ON);
663  if (e == e2)
664  break;
665  }
666  }
667  do {
668  e2 = before(e2);
669  } while (!ISBREAK(before(e2), e2));
670  }
671  }
672 }
673 
674 static struct edgelist *before(struct edgelist *e)
675 {
676  struct edgelist *r;
677  for (r = e->subpath; r->subpath != e; r = r->subpath) { ; }
678  return(r);
679 }
680 
681 /*
682 :h2.Fixing Region Continuity Problems
683 
684 Small regions may become disconnected when their connecting segments are
685 less than a pel wide. This may be correct in some applications, but in
686 many (especially small font characters), it is more pleasing to keep
687 connectivity. ApplyContinuity() (invoked by +CONTINUITY on the
688 Interior() fill rule) fixes connection breaks. The resulting region
689 is geometrically less accurate, but may be more pleasing to the eye.
690 */
691 /*
692 Here are some macros which we will need:
693 */
694 
695 #define IsValidPel(j) (j!=MINPEL)
696 
697 /*
698 :h3.writeXofY() - Stuffs an X Value Into an "edgelist"
699 
700 writeXofY writes an x value into an edge at position 'y'. It must
701 update the edge's xmin and xmax. If there is a possibility that this
702 new x might exceed the region's bounds, updating those are the
703 responsibility of the caller.
704 */
705 
706 static void writeXofY(
707  struct edgelist *e, /* relevant edgelist */
708  int y, /* y value */
709  int x) /* new x value */
710 {
711  if (e->xmin > x) e->xmin = x;
712  if (e->xmax < x) e->xmax = x;
713  e->xvalues[y - e->ymin] = x;
714 }
715 
716 /*-------------------------------------------------------------------------*/
717 /* the following three macros tell us whether we are at a birth point, a */
718 /* death point, or simply in the middle of the character */
719 /*-------------------------------------------------------------------------*/
720 #define WeAreAtTop(e,i) (ISTOP(e->flag) && e->ymin == i)
721 #define WeAreAtBottom(e,i) (ISBOTTOM(e->flag) && e->ymax-1 == i)
722 #define WeAreInMiddle(e,i) \
723  ((!ISTOP(e->flag) && !ISBOTTOM(e->flag))||(i < e->ymax-1 && i > e->ymin))
724 /*
725 The following macro tests if two "edgelist" structures are in the same
726 swath:
727 */
728 #define SAMESWATH(e1,e2) (e1->ymin == e2->ymin)
729 
730 /*
731 :h3.CollapseWhiteRun() - Subroutine of ApplyContinuity()
732 
733 When we have a white run with an implied horizontal line above or
734 below it, we better have black on the other side of this line. This
735 function both tests to see if black is there, and adjusts the end
736 points (collapses) the white run as necessary if it is not. The
737 goal is to collapse the white run as little as possible.
738 */
739 
740 static void CollapseWhiteRun(
741  struct edgelist *anchor, /* anchor of edge list */
742  pel yblack, /* y of (hopefully) black run above or below */
743  struct edgelist *left, /* edgelist at left of WHITE run */
744  struct edgelist *right, /* edgelist at right of WHITE run */
745  pel ywhite) /* y location of white run */
746 {
747  struct edgelist *edge;
748  struct edgelist *swathstart = anchor;
749  register pel x;
750 
751  if (XofY(left, ywhite) >= XofY(right, ywhite))
752  return;
753 /*
754 Find the swath with 'yblack'. If we don't find it, completely collapse
755 the white run and return:
756 */
757  while (VALIDEDGE(swathstart)) {
758  if (yblack < swathstart->ymin) {
759  writeXofY(left, ywhite, XofY(right, ywhite));
760  return;
761  }
762  if (yblack < swathstart->ymax) break;
763  swathstart = swathstart->link->link;
764  }
765  if(!VALIDEDGE(swathstart)) {
766  writeXofY(left, ywhite, XofY(right, ywhite));
767  return;
768  }
769 /*
770 Now we are in the swath that contains 'y', the reference line above
771 or below that we are trying to maintain continuity with. If black
772 in this line begins in the middle of our white run, we must collapse
773 the white run from the left to that point. If black ends in the
774 middle of our white run, we must collapse the white run from the right
775 to that point.
776 */
777  for (edge = swathstart; VALIDEDGE(edge); edge = edge->link) {
778 
779  if (!SAMESWATH(swathstart,edge))
780  break;
781  if( XofY(edge, yblack) > XofY(left, ywhite)) {
782  if (ISLEFT(edge->flag)) {
783  x = XofY(edge, yblack);
784  if (XofY(right, ywhite) < x)
785  x = XofY(right, ywhite);
786  writeXofY(left, ywhite, x);
787  }
788  else {
789  x = XofY(edge, yblack);
790  while (edge->link != NULL && SAMESWATH(edge, edge->link)
791  && x >= XofY(edge->link, yblack) ) {
792  edge = edge->link->link;
793  x = XofY(edge, yblack);
794  }
795  if (x < XofY(right, ywhite))
796  writeXofY(right, ywhite, x);
797  return;
798  }
799  }
800  }
801  writeXofY(left, ywhite, XofY(right, ywhite));
802 }
803 
804 /*
805 :h3.ApplyContinuity() - Fix False Breaks in a Region
806 
807 This is the externally visible routine called from the REGIONS module
808 when the +CONTINUITY flag is on the Interior() fill rule.
809 */
810 
811 void ApplyContinuity(struct region *R)
812 {
813  struct edgelist *left;
814  struct edgelist *right;
815  struct edgelist *edge,*e2;
816  pel rightXabove,rightXbelow,leftXabove,leftXbelow;
817  pel leftX,rightX;
818  int i;
819  int32_t newcenter,abovecenter,belowcenter;
820 
821  FixSubPaths(R);
822  if (RegionDebug >= 3)
823  DumpSubPaths(R->anchor);
824  left = R->anchor;
825 /* loop through and do all of the easy checking. ( no tops or bottoms) */
826  while(VALIDEDGE(left))
827  {
828  right = left->link;
829  for(i=left->ymin;i<left->ymax;++i)
830  {
831  leftX = findXofY(left,i);
832  rightX = findXofY(right,i);
833  leftXbelow = findXofY(left,i+1);
834  rightXbelow = findXofY(right,i+1);
835  if(rightX <= leftX)
836  {
837 /* then, we have a break in a near vertical line */
838  leftXabove = findXofY(left,i-1);
839  rightXabove = findXofY(right,i-1);
840  if( IsValidPel(leftXabove) && IsValidPel(rightXabove) )
841  {
842  abovecenter = leftXabove + rightXabove;
843  }
844  else
845  {
846  abovecenter = leftX + rightX;
847  }
848  if( IsValidPel(leftXbelow) && IsValidPel(rightXbelow) )
849  {
850  belowcenter = leftXbelow + rightXbelow;
851  }
852  else
853  {
854  belowcenter = leftX + rightX;
855  }
856  newcenter = abovecenter + belowcenter;
857  if( newcenter > 4*leftX )
858  {
859  rightX = rightX + 1;
860  }
861  else if( newcenter < 4*leftX)
862  {
863  leftX = leftX - 1;
864  }
865  else
866  {
867  rightX = rightX + 1;
868  }
869  writeXofY(right,i,rightX);
870  writeXofY(left,i,leftX);
871  if(rightX > R->xmax) {R->xmax = rightX;}
872  if(leftX < R->xmin) {R->xmin = leftX;}
873  }
874  if( !WeAreAtBottom(left,i) && (leftXbelow>=rightX))
875  {
876 /* then we have a break in a near horizontal line in the middle */
877  writeXofY(right,i,leftXbelow);
878  }
879  if( !WeAreAtBottom(right,i) && (leftX >=rightXbelow))
880  {
881 /* then we have a break in a near horizontal line in the middle */
882  writeXofY(left,i,rightXbelow);
883  }
884  }
885  left = right->link;
886  }
887 /*
888 There may be "implied horizontal lines" between edges that have
889 implications for continuity. This loop looks for white runs that
890 have implied horizontal lines on the top or bottom, and calls
891 CollapseWhiteRuns to check and fix any continuity problems from
892 them.
893 */
894  for (edge = R->anchor; VALIDEDGE(edge); edge = edge->link) {
895  if ((!ISTOP(edge->flag) && !ISBOTTOM(edge->flag)) || ISLEFT(edge->flag))
896  continue; /* at some future date we may want left edge logic here too */
897  for (e2 = edge->link; VALIDEDGE(e2) && SAMESWATH(edge,e2); e2 = e2->link) {
898  if (ISTOP(e2->flag) && ISTOP(edge->flag)
899  && NONE != ImpliedHorizontalLine(edge,e2,edge->ymin)) {
900  if (ISLEFT(e2->flag))
901  CollapseWhiteRun(R->anchor, edge->ymin-1,
902  edge, e2, edge->ymin);
903  }
904  if (ISBOTTOM(e2->flag) && ISBOTTOM(edge->flag)
905  && NONE != ImpliedHorizontalLine(edge,e2, edge->ymax)) {
906  if (ISLEFT(e2->flag))
907  CollapseWhiteRun(R->anchor, edge->ymax,
908  edge, e2, edge->ymax-1);
909  }
910  }
911  }
912 }
913 
914 
915 
916 
#define next(a)
Definition: aptex-macros.h:924
@ FALSE
Definition: dd.h:101
@ TRUE
Definition: dd.h:102
static FIELD_PTR prev
Definition: genind.c:36
static void FixSubPaths(register struct region *R)
Definition: hints.c:486
#define XofY(edge, y)
Definition: hints.c:340
#define IsValidPel(j)
Definition: hints.c:695
static void writeXofY(struct edgelist *e, int y, int x)
Definition: hints.c:706
#define findXofY(edge, y)
Definition: hints.c:349
#define FPROUND(fp)
Definition: hints.c:83
#define MAXLABEL
Definition: hints.c:74
#define ISTOP(flag)
Definition: hints.c:325
#define ISBOTTOM(flag)
Definition: hints.c:326
#define WeAreAtBottom(e, i)
Definition: hints.c:721
#define NONE
Definition: hints.c:412
int inuse
Definition: hints.c:76
static pel SearchXofY(register struct edgelist *edge, register pel y)
Definition: hints.c:361
static struct edgelist * before(struct edgelist *)
Definition: hints.c:674
struct fractpoint hint
Definition: hints.c:78
int computed
Definition: hints.c:77
static void CollapseWhiteRun(struct edgelist *anchor, pel yblack, struct edgelist *left, struct edgelist *right, pel ywhite)
Definition: hints.c:740
static struct @183 oldHint[20]
#define ODD(x)
Definition: hints.c:81
#define SAMESWATH(e1, e2)
Definition: hints.c:728
static void DumpSubPaths(struct edgelist *anchor)
Definition: hints.c:631
#define ISBREAK(top, bot)
Definition: hints.c:398
#define ISLEFT(flag)
Definition: hints.c:331
static void ComputeHint(struct hintsegment *hP, fractpel currX, fractpel currY, struct fractpoint *hintP)
Definition: hints.c:123
#define FPFLOOR(fp)
Definition: hints.c:82
static int ImpliedHorizontalLine(register struct edgelist *e1, register struct edgelist *e2, register int y)
Definition: hints.c:414
#define ApplyContinuity(R)
Definition: hints.h:41
#define ProcessHint(hP, currX, currY, hintP)
Definition: hints.h:37
#define InitHints
Definition: hints.h:31
#define CloseHints(hintP)
Definition: hints.h:34
#define ABS(a)
Definition: tttypes.h:126
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p scientific i
Definition: afcover.h:80
kerning y
Definition: ttdriver.c:212
@ right
Definition: annotate.c:15
signed int int32_t
Definition: stdint.h:77
float x
Definition: cordic.py:15
void t1_abort(const char *str)
Definition: objects.c:1088
#define IfTrace0(condition, model)
Definition: objects.h:233
#define IfTrace2(condition, model, arg0, arg1)
Definition: objects.h:237
#define IfTrace4(condition, model, arg0, arg1, arg2, arg3)
Definition: objects.h:241
char HintDebug
char RegionDebug
#define ISPERMANENT(flag)
Definition: objects.h:160
#define IfTrace3(condition, model, arg0, arg1, arg2)
Definition: objects.h:239
#define IfTrace1(condition, model, arg0)
Definition: objects.h:235
int r
Definition: ppmqvga.c:68
#define VALIDEDGE(p)
Definition: regions.h:101
#define ISDOWN(f)
Definition: regions.h:190
#define MINPEL
Definition: regions.h:174
#define ISAMBIGUOUS(f)
Definition: regions.h:192
lft_cell * left
Definition: routines.h:73
ShellFileEnvironment e
Definition: sh6.c:388
SHORT pel
Definition: spaces.h:36
#define NEARESTPEL(fp)
Definition: spaces.h:46
int32_t fractpel
Definition: spaces.h:37
#define FPHALF
Definition: spaces.h:45
cairo_list_t link
pel ymin
Definition: regions.h:92
struct edgelist * subpath
Definition: regions.h:90
pel ymax
Definition: regions.h:92
pel xmin
Definition: regions.h:91
XOBJ_COMMON struct edgelist * link
Definition: regions.h:89
fractpel y
Definition: spaces.h:81
fractpel x
Definition: spaces.h:81
char adjusttype
Definition: paths.h:203
char hinttype
Definition: paths.h:202
struct fractpoint ref
Definition: paths.h:199
struct fractpoint width
Definition: paths.h:200
int label
Definition: paths.h:205
char direction
Definition: paths.h:204
char orientation
Definition: paths.h:201
Definition: regions.h:31
@ R
Definition: ubidiimp.h:46
@ ON
Definition: ubidiimp.h:55