1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/auxtext.c,v 1.17 2011/05/16 16:21:56 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_AUXTEXT_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "auxtext.e"
26 #include "choice.e"
27 #include "color.e"
28 #include "cursor.e"
29 #include "cutpaste.e"
30 #include "dialog.e"
31 #include "drawing.e"
32 #include "file.e"
33 #include "font.e"
34 #include "miniline.e"
35 #include "msg.e"
36 #include "obj.e"
37 #include "pattern.e"
38 #include "prtgif.e"
39 #include "ps.e"
40 #include "raster.e"
41 #include "rect.e"
42 #include "setup.e"
43 #include "select.e"
44 #include "strtbl.e"
45 #include "text.e"
46 #include "util.e"
47 #include "xbitmap.e"
48 #include "xpixmap.e"
49 
50 GC	rotateGC=NULL;
51 Pixmap	textBackingBitmap=None, textBackingBgBitmap=None;
52 Pixmap	textBackingPixmap=None;
53 int	textBackingBitmapW=INVALID;
54 int	textBackingBitmapH=INVALID;
55 int	doubleQuoteDoubleQuote=FALSE;
56 int	groupedTextEditable=FALSE;
57 
58 struct SelRec *outerSel=NULL, *innerSel=NULL;
59 
GetStrSizeInfo(pDynStr,w,lbearing,rextra)60 void GetStrSizeInfo(pDynStr, w, lbearing, rextra)
61    struct DynStrRec *pDynStr;
62    int *w, *lbearing, *rextra;
63 {
64    XCharStruct xcs;
65 
66    MyTextExtents(canvasFontPtr, pDynStr->s, pDynStr->sz-1, &xcs);
67    if (w != NULL) *w = xcs.width;
68    if (lbearing != NULL) *lbearing = (xcs.lbearing >= 0 ? 0 : xcs.lbearing);
69    if (rextra != NULL) *rextra = xcs.rbearing-xcs.width;
70 }
71 
GetNumberOfMiniLines(minilines)72 int GetNumberOfMiniLines(minilines)
73    MiniLinesInfo *minilines;
74 {
75    int count=0;
76    MiniLineInfo *pMiniLine=minilines->first;
77 
78    for ( ; pMiniLine != NULL; pMiniLine=pMiniLine->next, count++) {
79    }
80    return count;
81 }
82 
IsHex(ch,pn_val)83 int IsHex(ch, pn_val)
84    char ch;
85    int *pn_val;
86 {
87    if (ch >= '0' && ch <= '9') {
88       *pn_val = ((int)(ch - '0'));
89       return TRUE;
90    }
91    if (ch >= 'a' && ch <= 'f') {
92       *pn_val = 10+((int)(ch - 'a'));
93       return TRUE;
94    }
95    if (ch >= 'A' && ch <= 'F') {
96       *pn_val = 10+((int)(ch - 'F'));
97       return TRUE;
98    }
99    return FALSE;
100 }
101 
InputOctalString(pszBuf,pnBufSize)102 int InputOctalString(pszBuf, pnBufSize)
103    char *pszBuf;
104    int *pnBufSize;
105 {
106    int i=0, nBufSizeIn=(*pnBufSize), nError=FALSE;
107    int nPrevIsOctal=FALSE, nByte1OfOctal=TRUE;
108    char *psz=NULL, szSpec[MAXSTRING];
109 
110    *pnBufSize = 0;
111    *pszBuf = '\0';
112    *szSpec = '\0';
113    if (canvasFontDoubleByte) {
114       sprintf(gszMsgBox, TgLoadString(STID_INPUT_OCTAL_STR), "\\244\\244");
115    } else {
116       sprintf(gszMsgBox, TgLoadString(STID_INPUT_STR));
117    }
118    Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
119    UtilTrimBlanks(szSpec);
120    if (*szSpec == '\0') return FALSE;
121 
122    if (szSpec[0] == '0' && szSpec[1] == 'x') {
123       for (i=0, psz=(&szSpec[2]); !nError && i < nBufSizeIn-1 && *psz != '\0';
124             i++, psz=(&psz[2])) {
125          int hi_nibble=0, lo_nibble=0;
126 
127          if (IsHex(psz[0], &hi_nibble) && IsHex(psz[1], &lo_nibble)) {
128             int hval=(((hi_nibble&0x0ff)<<4)+(lo_nibble&0x0ff));
129 
130             pszBuf[i] = hval;
131 
132             if (canvasFontDoubleByte && canvasFontDoubleByteModBytes) {
133                if ((pszBuf[i] & 0x80) == 0) {
134                   pszBuf[i] |= 0x80;
135                }
136             }
137          } else {
138             nError = TRUE;
139          }
140       }
141    } else {
142       for (i=0, psz=szSpec; !nError && i < nBufSizeIn-1 && *psz != '\0';
143             i++, psz++) {
144          int nThisIsOctal=FALSE;
145 
146          if (*psz == '\\') {
147             if (psz[1] == '\0') {
148                pszBuf[i] = '\\';
149             } else if (psz[1] == '\\') {
150                pszBuf[i] = '\\';
151                psz++;
152             } else if (psz[1] == 'r') {
153                pszBuf[i] = '\r';
154                psz++;
155             } else if (psz[1] == 'n') {
156                pszBuf[i] = '\n';
157                psz++;
158             } else if (psz[1] >= '0' && psz[1] <= '7') {
159                char *psz1=NULL, saved_ch='\0';
160                int oval=0;
161 
162                *psz = '0';
163                for (psz1=(&psz[2]); *psz1 >= '0' && *psz1 <= '7'; psz1++) ;
164                saved_ch = (*psz1);
165                *psz1 = '\0';
166                if (sscanf(psz, "%o", &oval) != 1) {
167                   nError = TRUE;
168                } else {
169                   pszBuf[i] = (char)(oval & 0xff);
170 
171                   nThisIsOctal = TRUE;
172                   if (canvasFontDoubleByte && canvasFontDoubleByteModBytes) {
173                      if (nPrevIsOctal) {
174                         nByte1OfOctal = !nByte1OfOctal;
175                      } else {
176                         nByte1OfOctal = TRUE;
177                      }
178                      if ((pszBuf[i] & 0x80) == 0) {
179                         pszBuf[i] |= 0x80;
180                      }
181                   }
182                }
183                *psz1 = saved_ch;
184                *psz = '\\';
185                if (!nError) {
186                   psz = psz1;
187                   psz--;
188                }
189             } else {
190                i--;
191                psz++;
192             }
193          } else {
194             pszBuf[i] = *psz;
195          }
196          nPrevIsOctal = nThisIsOctal;
197       }
198    }
199    if (canvasFontDoubleByte && ((i & 0x1) != 0)) {
200       nError = TRUE;
201    }
202    if (nError) {
203       *pszBuf = '\0';
204       sprintf(gszMsgBox, TgLoadCachedString(CSTID_MALFORMED_INPUT_STR), szSpec);
205       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
206       return FALSE;
207    }
208    pszBuf[i] = '\0';
209    *pnBufSize = i;
210    return TRUE;
211 }
212 
CharIsCntrlINS(key_ev,key_sym)213 int CharIsCntrlINS(key_ev, key_sym)
214    XKeyEvent *key_ev;
215    KeySym key_sym;
216 {
217    if (key_ev != NULL && ((key_ev->state & ControlMask) != 0) &&
218          ((key_ev->state & ShiftMask) == 0) &&
219          (key_sym == XK_Insert || key_sym == XK_KP_Insert)) {
220       return TRUE;
221    }
222    return FALSE;
223 }
224 
CharIsShiftINS(key_ev,key_sym)225 int CharIsShiftINS(key_ev, key_sym)
226    XKeyEvent *key_ev;
227    KeySym key_sym;
228 {
229    if (key_ev != NULL && ((key_ev->state & ControlMask) == 0) &&
230          ((key_ev->state & ShiftMask) != 0) &&
231          (key_sym == XK_Insert || key_sym == XK_KP_Insert)) {
232       return TRUE;
233    }
234    return FALSE;
235 }
236 
CharIsCntrlShiftINS(key_ev,key_sym)237 int CharIsCntrlShiftINS(key_ev, key_sym)
238    XKeyEvent *key_ev;
239    KeySym key_sym;
240 {
241    if (key_ev != NULL && ((key_ev->state & ControlMask) != 0) &&
242          ((key_ev->state & ShiftMask) != 0) &&
243          (key_sym == XK_Insert || key_sym == XK_KP_Insert)) {
244       return TRUE;
245    }
246    return FALSE;
247 }
248 
249 /*
250  * int has_ch=XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
251  *
252  * TranslateKeys(buf, &key_sym);
253  *
254  * if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
255  * } else if (CharIsCRorLF(key_ev, buf, key_sym, &has_ch)) {
256  * } else if (CharIsBSorDEL(key_ev, buf, key_sym, &has_ch, FALSE)) {
257  * } else if (CharIsTAB(key_ev, buf, key_sym, &has_ch)) {
258  * }
259  */
CharIsESC(key_ev,psz_buf,key_sym,pn_has_ch)260 int CharIsESC(key_ev, psz_buf, key_sym, pn_has_ch)
261    XKeyEvent *key_ev;
262    char *psz_buf;
263    KeySym key_sym;
264    int *pn_has_ch;
265 {
266    if (key_sym == XK_Escape) return TRUE;
267    if (key_ev != NULL && (key_ev->state & ControlMask) &&
268          key_sym == XK_bracketleft) {
269       return TRUE;
270    }
271    if (pn_has_ch != NULL) {
272       return ((*pn_has_ch) && *psz_buf == '\033');
273    }
274    return (*psz_buf == '\033');
275 }
276 
CharIsCRorLF(key_ev,psz_buf,key_sym,pn_has_ch)277 int CharIsCRorLF(key_ev, psz_buf, key_sym, pn_has_ch)
278    XKeyEvent *key_ev;
279    char *psz_buf;
280    KeySym key_sym;
281    int *pn_has_ch;
282 {
283    if (key_sym==XK_Return || key_sym==XK_KP_Enter || key_sym==XK_Linefeed) {
284       return TRUE;
285    }
286    if (key_ev != NULL && (key_ev->state & ControlMask) &&
287          (key_sym == XK_m || key_sym == XK_j)) {
288       return TRUE;
289    }
290    if (pn_has_ch != NULL) {
291       return ((*pn_has_ch) && (*psz_buf == '\r' || *psz_buf == '\n'));
292    }
293    return (*psz_buf == '\r' || *psz_buf == '\n');
294 }
295 
CharIsDEL(key_ev,psz_buf,key_sym,pn_has_ch)296 int CharIsDEL(key_ev, psz_buf, key_sym, pn_has_ch)
297    XKeyEvent *key_ev;
298    char *psz_buf;
299    KeySym key_sym;
300    int *pn_has_ch;
301 {
302    if (key_sym==XK_Delete || key_sym==XK_KP_Delete) {
303       return TRUE;
304    }
305    if (pn_has_ch != NULL) {
306       return ((*pn_has_ch) && (*psz_buf == '\177'));
307    }
308    return (*psz_buf == '\177');
309 }
310 
CharIsBS(key_ev,psz_buf,key_sym,pn_has_ch,left_is_BS)311 int CharIsBS(key_ev, psz_buf, key_sym, pn_has_ch, left_is_BS)
312    XKeyEvent *key_ev;
313    char *psz_buf;
314    KeySym key_sym;
315    int *pn_has_ch, left_is_BS;
316 {
317    if ((left_is_BS && (key_sym==XK_Left || key_sym==XK_KP_Left)) ||
318          key_sym==XK_BackSpace) {
319       return TRUE;
320    }
321    if (key_ev != NULL && (key_ev->state & ControlMask) && (key_sym == XK_h)) {
322       return TRUE;
323    }
324    if (pn_has_ch != NULL) {
325       return ((*pn_has_ch) && (*psz_buf == '\b'));
326    }
327    return (*psz_buf == '\b');
328 }
329 
CharIsBSorDEL(key_ev,psz_buf,key_sym,pn_has_ch,left_is_BS)330 int CharIsBSorDEL(key_ev, psz_buf, key_sym, pn_has_ch, left_is_BS)
331    XKeyEvent *key_ev;
332    char *psz_buf;
333    KeySym key_sym;
334    int *pn_has_ch, left_is_BS;
335 {
336    if ((left_is_BS && (key_sym==XK_Left || key_sym==XK_KP_Left)) ||
337          key_sym==XK_BackSpace || key_sym==XK_Delete || key_sym==XK_KP_Delete) {
338       return TRUE;
339    }
340    if (key_ev != NULL && (key_ev->state & ControlMask) && (key_sym == XK_h)) {
341       return TRUE;
342    }
343    if (pn_has_ch != NULL) {
344       return ((*pn_has_ch) && (*psz_buf == '\b' || *psz_buf == '\177'));
345    }
346    return (*psz_buf == '\b' || *psz_buf == '\177');
347 }
348 
CharIsTAB(key_ev,psz_buf,key_sym,pn_has_ch)349 int CharIsTAB(key_ev, psz_buf, key_sym, pn_has_ch)
350    XKeyEvent *key_ev;
351    char *psz_buf;
352    KeySym key_sym;
353    int *pn_has_ch;
354 {
355    if (key_sym==XK_Tab || key_sym==XK_KP_Tab) {
356       return TRUE;
357    }
358    if (key_ev != NULL && (key_ev->state & ControlMask) && (key_sym == XK_i)) {
359       return TRUE;
360    }
361    if (pn_has_ch != NULL) {
362       return ((*pn_has_ch) && (*psz_buf == '\t'));
363    }
364    return (*psz_buf == '\t');
365 }
366 
CharIsHome(key_ev,psz_buf,key_sym,pn_has_ch)367 int CharIsHome(key_ev, psz_buf, key_sym, pn_has_ch)
368    XKeyEvent *key_ev;
369    char *psz_buf;
370    KeySym key_sym;
371    int *pn_has_ch;
372 {
373    return (key_sym==XK_Home || key_sym==XK_KP_Home);
374 }
375 
CharIsEnd(key_ev,psz_buf,key_sym,pn_has_ch)376 int CharIsEnd(key_ev, psz_buf, key_sym, pn_has_ch)
377    XKeyEvent *key_ev;
378    char *psz_buf;
379    KeySym key_sym;
380    int *pn_has_ch;
381 {
382    return (key_sym==XK_End || key_sym==XK_KP_End);
383 }
384 
CharIsCntrlSpace(key_ev,psz_buf,key_sym,pn_has_ch)385 int CharIsCntrlSpace(key_ev, psz_buf, key_sym, pn_has_ch)
386    XKeyEvent *key_ev;
387    char *psz_buf;
388    KeySym key_sym;
389    int *pn_has_ch;
390 {
391    int state=key_ev->state;
392 
393    if (((state & ControlMask) == ControlMask) && ((state & METAMASK) == 0)) {
394       if (key_sym == XK_space || (psz_buf[0] == ' ' && psz_buf[1] == '\0')) {
395          return TRUE;
396       } else if (key_sym == XK_backslash || (psz_buf[0] == '\\' &&
397             psz_buf[1] == '\0')) {
398          return TRUE;
399       }
400    }
401    return FALSE;
402 }
403 
TranslateKeys(s,key_sym)404 void TranslateKeys(s, key_sym)
405    char *s;
406    KeySym *key_sym;
407 {
408    switch (*key_sym) {
409    case XK_KP_Space:     *key_sym=XK_space;    s[0]=' ';  s[1]='\0'; break;
410    case XK_KP_Tab:       *key_sym=XK_Tab;      s[0]='\t'; s[1]='\0'; break;
411    case XK_KP_Enter:     *key_sym=XK_Return;   s[0]='\r'; s[1]='\0'; break;
412    case XK_KP_Equal:     *key_sym=XK_equal;    s[0]='=';  s[1]='\0'; break;
413    case XK_KP_Multiply:  *key_sym=XK_multiply; s[0]='*';  s[1]='\0'; break;
414    case XK_KP_Add:       *key_sym=XK_plus;     s[0]='+';  s[1]='\0'; break;
415    case XK_KP_Separator: *key_sym=XK_comma;    s[0]=',';  s[1]='\0'; break;
416    case XK_KP_Subtract:  *key_sym=XK_minus;    s[0]='-';  s[1]='\0'; break;
417    case XK_KP_Decimal:   *key_sym=XK_period;   s[0]='.';  s[1]='\0'; break;
418    case XK_KP_Divide:    *key_sym=XK_slash;    s[0]='/';  s[1]='\0'; break;
419 
420    case XK_KP_0: *key_sym=XK_0; s[0]='0'; s[1]='\0'; break;
421    case XK_KP_1: *key_sym=XK_1; s[0]='1'; s[1]='\0'; break;
422    case XK_KP_2: *key_sym=XK_2; s[0]='2'; s[1]='\0'; break;
423    case XK_KP_3: *key_sym=XK_3; s[0]='3'; s[1]='\0'; break;
424    case XK_KP_4: *key_sym=XK_4; s[0]='4'; s[1]='\0'; break;
425    case XK_KP_5: *key_sym=XK_5; s[0]='5'; s[1]='\0'; break;
426    case XK_KP_6: *key_sym=XK_6; s[0]='6'; s[1]='\0'; break;
427    case XK_KP_7: *key_sym=XK_7; s[0]='7'; s[1]='\0'; break;
428    case XK_KP_8: *key_sym=XK_8; s[0]='8'; s[1]='\0'; break;
429    case XK_KP_9: *key_sym=XK_9; s[0]='9'; s[1]='\0'; break;
430    }
431 }
432 
433 static
GetTransformedTextBBoxAbsVs(ObjPtr,LBearing,RightExtra,Vs)434 void GetTransformedTextBBoxAbsVs(ObjPtr, LBearing, RightExtra, Vs)
435    struct ObjRec *ObjPtr;
436    int LBearing, RightExtra;
437    IntPoint *Vs; /* array of 5 points */
438 {
439    int x, y;
440    struct BBRec bbox;
441 
442    bbox.ltx = ObjPtr->orig_obbox.ltx - ObjPtr->x + LBearing;
443    bbox.lty = ObjPtr->orig_obbox.lty - ObjPtr->y;
444    bbox.rbx = ObjPtr->orig_obbox.rbx - ObjPtr->x + RightExtra;
445    bbox.rby = ObjPtr->orig_obbox.rby - ObjPtr->y;
446    TransformOffsetBBoxThroughCTM(&bbox, ObjPtr->ctm, Vs);
447    x = Vs[0].x + ObjPtr->x; y = Vs[0].y + ObjPtr->y;
448    Vs[0].x = Vs[4].x = x; Vs[0].y = Vs[4].y = y;
449    x = Vs[1].x + ObjPtr->x; y = Vs[1].y + ObjPtr->y;
450    Vs[1].x = x; Vs[1].y = y;
451    x = Vs[2].x + ObjPtr->x; y = Vs[2].y + ObjPtr->y;
452    Vs[2].x = x; Vs[2].y = y;
453    x = Vs[3].x + ObjPtr->x; y = Vs[3].y + ObjPtr->y;
454    Vs[3].x = x; Vs[3].y = y;
455 }
456 
SetTextOBBox(ObjPtr,Just,W,H,LBearing,RightExtra,Rotate)457 void SetTextOBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate)
458    struct ObjRec *ObjPtr;
459    int Just, W, H, LBearing, RightExtra, Rotate;
460 {  /* In this procedure, it is assumed that the x and y field */
461    /*       of the text object has the correct information.*/
462    /* The rotation is clockwise */
463    register int mw2, pw2;
464 
465    if (ObjPtr->ctm == NULL) {
466       switch (Just) {
467       case JUST_L:
468          switch (Rotate) {
469          case ROTATE0:
470             ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+W;
471             ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+H;
472             break;
473          case ROTATE90:
474             ObjPtr->obbox.ltx = ObjPtr->x-H; ObjPtr->obbox.rbx = ObjPtr->x;
475             ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+W;
476             break;
477          case ROTATE180:
478             ObjPtr->obbox.ltx = ObjPtr->x-W; ObjPtr->obbox.rbx = ObjPtr->x;
479             ObjPtr->obbox.lty = ObjPtr->y-H; ObjPtr->obbox.rby = ObjPtr->y;
480             break;
481          case ROTATE270:
482             ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+H;
483             ObjPtr->obbox.lty = ObjPtr->y-W; ObjPtr->obbox.rby = ObjPtr->y;
484             break;
485          }
486          break;
487       case JUST_C:
488          mw2 = W/2;
489          pw2 = W-W/2;
490          switch (Rotate) {
491          case ROTATE0:
492             ObjPtr->obbox.ltx = ObjPtr->x-mw2;
493             ObjPtr->obbox.rbx = ObjPtr->x+pw2;
494             ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+H;
495             break;
496          case ROTATE90:
497             ObjPtr->obbox.ltx = ObjPtr->x-H;
498             ObjPtr->obbox.rbx = ObjPtr->x;
499             ObjPtr->obbox.lty = ObjPtr->y-mw2;
500             ObjPtr->obbox.rby = ObjPtr->y+pw2;
501             break;
502          case ROTATE180:
503             ObjPtr->obbox.ltx = ObjPtr->x-pw2;
504             ObjPtr->obbox.rbx = ObjPtr->x+mw2;
505             ObjPtr->obbox.lty = ObjPtr->y-H;
506             ObjPtr->obbox.rby = ObjPtr->y;
507             break;
508          case ROTATE270:
509             ObjPtr->obbox.ltx = ObjPtr->x;
510             ObjPtr->obbox.rbx = ObjPtr->x+H;
511             ObjPtr->obbox.lty = ObjPtr->y-pw2;
512             ObjPtr->obbox.rby = ObjPtr->y+mw2;
513             break;
514          }
515          break;
516       case JUST_R:
517          switch (Rotate) {
518          case ROTATE0:
519             ObjPtr->obbox.ltx = ObjPtr->x-W; ObjPtr->obbox.rbx = ObjPtr->x;
520             ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+H;
521             break;
522          case ROTATE90:
523             ObjPtr->obbox.ltx = ObjPtr->x-H; ObjPtr->obbox.rbx = ObjPtr->x;
524             ObjPtr->obbox.lty = ObjPtr->y-W; ObjPtr->obbox.rby = ObjPtr->y;
525             break;
526          case ROTATE180:
527             ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+W;
528             ObjPtr->obbox.lty = ObjPtr->y-H; ObjPtr->obbox.rby = ObjPtr->y;
529             break;
530          case ROTATE270:
531             ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+H;
532             ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+W;
533             break;
534          }
535          break;
536       }
537    } else {
538       IntPoint abs_obj_obbox_vs[5];
539 
540       GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
541       ObjPtr->obbox.ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
542             min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
543       ObjPtr->obbox.rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
544             max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
545       ObjPtr->obbox.lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
546             min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
547       ObjPtr->obbox.rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
548             max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
549    }
550 }
551 
SetTextBBox(ObjPtr,Just,W,H,LBearing,RightExtra,Rotate)552 void SetTextBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate)
553    struct ObjRec *ObjPtr;
554    int Just, W, H, LBearing, RightExtra, Rotate;
555    /* In this procedure, it is assumed that the x and y field */
556    /*       of the text object has the correct information.*/
557    /* The rotation is clockwise */
558 {
559    SetTextOBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate);
560 
561    if (ObjPtr->ctm == NULL) {
562       switch (Rotate) {
563       case ROTATE0:
564          ObjPtr->bbox.ltx = ObjPtr->obbox.ltx + LBearing;
565          ObjPtr->bbox.rbx = ObjPtr->obbox.rbx + RightExtra;
566          ObjPtr->bbox.lty = ObjPtr->obbox.lty;
567          ObjPtr->bbox.rby = ObjPtr->obbox.rby;
568          break;
569       case ROTATE90:
570          ObjPtr->bbox.ltx = ObjPtr->obbox.ltx;
571          ObjPtr->bbox.rbx = ObjPtr->obbox.rbx;
572          ObjPtr->bbox.lty = ObjPtr->obbox.lty + LBearing;
573          ObjPtr->bbox.rby = ObjPtr->obbox.rby + RightExtra;
574          break;
575       case ROTATE180:
576          ObjPtr->bbox.ltx = ObjPtr->obbox.ltx - RightExtra;
577          ObjPtr->bbox.rbx = ObjPtr->obbox.rbx - LBearing;
578          ObjPtr->bbox.lty = ObjPtr->obbox.lty;
579          ObjPtr->bbox.rby = ObjPtr->obbox.rby;
580          break;
581       case ROTATE270:
582          ObjPtr->bbox.ltx = ObjPtr->obbox.ltx;
583          ObjPtr->bbox.rbx = ObjPtr->obbox.rbx;
584          ObjPtr->bbox.lty = ObjPtr->obbox.lty - RightExtra;
585          ObjPtr->bbox.rby = ObjPtr->obbox.rby - LBearing;
586          break;
587       }
588    } else {
589       IntPoint abs_obj_bbox_vs[5];
590 
591       GetTransformedTextBBoxAbsVs(ObjPtr, LBearing, RightExtra,
592             abs_obj_bbox_vs);
593       ObjPtr->bbox.ltx = min(min(abs_obj_bbox_vs[0].x,abs_obj_bbox_vs[1].x),
594             min(abs_obj_bbox_vs[2].x,abs_obj_bbox_vs[3].x));
595       ObjPtr->bbox.rbx = max(max(abs_obj_bbox_vs[0].x,abs_obj_bbox_vs[1].x),
596             max(abs_obj_bbox_vs[2].x,abs_obj_bbox_vs[3].x));
597       ObjPtr->bbox.lty = min(min(abs_obj_bbox_vs[0].y,abs_obj_bbox_vs[1].y),
598             min(abs_obj_bbox_vs[2].y,abs_obj_bbox_vs[3].y));
599       ObjPtr->bbox.rby = max(max(abs_obj_bbox_vs[0].y,abs_obj_bbox_vs[1].y),
600             max(abs_obj_bbox_vs[2].y,abs_obj_bbox_vs[3].y));
601    }
602    ObjPtr->bbox.ltx--;
603    ObjPtr->bbox.rbx++;
604    ObjPtr->bbox.lty--;
605    ObjPtr->bbox.rby++;
606 }
607 
SetTextOrigBBoxes(ObjPtr,Just,W,H,LBearing,RightExtra,Rotate)608 void SetTextOrigBBoxes(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate)
609    struct ObjRec *ObjPtr;
610    int Just, W, H, LBearing, RightExtra, Rotate;
611    /* In this procedure, it is assumed that the x and y field */
612    /*       of the text object has the correct information.*/
613    /* The rotation is clockwise */
614 {
615    struct BBRec obbox, bbox;
616    struct XfrmMtrxRec *ctm;
617 
618    if (ObjPtr->ctm == NULL) return;
619    memcpy(&obbox, &ObjPtr->obbox, sizeof(struct BBRec));
620    memcpy(&bbox, &ObjPtr->bbox, sizeof(struct BBRec));
621    ctm = ObjPtr->ctm;
622    ObjPtr->ctm = NULL;
623 
624    SetTextBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate);
625 
626    memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec));
627    memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox, sizeof(struct BBRec));
628    ObjPtr->ctm = ctm;
629 }
630 
UpdTextBBox(ObjPtr)631 int UpdTextBBox(ObjPtr)
632    struct ObjRec *ObjPtr;
633    /*
634     * This function should be called every time any part of a text object is
635     *       changed.
636     * Therefore, it should never be called if PRTGIF.
637     * Returns FALSE if the text object is changed.
638     */
639 {
640    struct TextRec *text_ptr=ObjPtr->detail.t;
641    int read_only=FALSE;
642 #ifdef _TGIF_DBG /* debug, do not translate */
643    int saved_baseline_y=text_ptr->baseline_y;
644 
645 #endif /* _TGIF_DBG */
646 
647    if (mainDisplay == NULL) return FALSE;
648 
649 #ifdef _TGIF_DBG /* debug, do not translate */
650    if (PRTGIF && !cmdLineOpenDisplay) {
651       fprintf(stderr, "UpdTextBBox() called in PRTGIF!\n");
652    }
653 #endif /* _TGIF_DBG */
654    if (text_ptr->read_only) {
655       return TRUE;
656    }
657    PushCurFont();
658 
659    ObjFontInfoToCurFontInfo(text_ptr);
660    allowFontFaceSubstitution = FALSE;
661    read_only = (!RecalcTextMetrics(text_ptr, ObjPtr->x, text_ptr->baseline_y));
662    allowFontFaceSubstitution = TRUE;
663 
664 #ifdef _TGIF_DBG /* debug, do not translate */
665    if (text_ptr->baseline_y != saved_baseline_y) {
666       TgAssert(FALSE,
667             "Text_ptr->baseline_y changed in UpdTextBBox()", "Restored");
668       text_ptr->baseline_y = saved_baseline_y;
669    }
670 #endif /* _TGIF_DBG */
671 
672    if (read_only) {
673       PopCurFont();
674       return FALSE;
675    }
676    ObjPtr->y = text_ptr->baseline_y - text_ptr->minilines.first->asc;
677 
678    SetTextOrigBBoxes(ObjPtr, textJust, text_ptr->w, text_ptr->h,
679          text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
680    SetTextBBox(ObjPtr, textJust, text_ptr->w, text_ptr->h,
681          text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
682 
683    PopCurFont();
684    return (!read_only);
685 }
686 
PixelOnOff(image,col_start,row_start,scale)687 int PixelOnOff(image, col_start, row_start, scale)
688    XImage *image;
689    int col_start, row_start, scale;
690 {
691    register int m, n;
692    int on_count=0, off_count=0;
693 
694    if (scale == 2) {
695       for (m = 0; m < 2; m++) {
696          for (n = 0; n < 2; n++) {
697             switch (XGetPixel(image,col_start+n,row_start+m)) {
698             case 0: if (++off_count > 2) return 0; break;
699             case 1: if (++on_count >= 2) return 1; break;
700             }
701          }
702       }
703    } else if (scale > 2) {
704       int half_scale=scale>>1;
705 
706       for (m = 0; m < 2; m++) {
707          for (n = 0; n < 2; n++) {
708             switch (PixelOnOff(image, col_start+n*half_scale,
709                   row_start+m*half_scale, half_scale)) {
710             case 0: if (++off_count > 2) return 0; break;
711             case 1: if (++on_count >= 2) return 1; break;
712             }
713          }
714       }
715    } else {
716       return 1;
717    }
718    return 0;
719 }
720 
721 static
PaintBackingPixmap(text_ptr,bbox_w,bbox_h,min_lbearing,max_rextra,baseline_y)722 int PaintBackingPixmap(text_ptr, bbox_w, bbox_h, min_lbearing, max_rextra,
723       baseline_y)
724    struct TextRec *text_ptr;
725    int bbox_w, bbox_h, min_lbearing, max_rextra, baseline_y;
726    /*
727     * bbox_w includes left bearing and right extra.
728     */
729 {
730    MiniLinesInfo *minilines=(&text_ptr->minilines);
731    int x=0, w=minilines->w, saved_pen=penPat, saved_trans_pat=transPat;
732 
733    if (bbox_w > textBackingBitmapW || bbox_h > textBackingBitmapH) {
734       int tmp_w, tmp_h;
735 
736       if (textBackingBitmap != None) {
737          XFreePixmap(mainDisplay, textBackingBitmap);
738       }
739       if (textBackingBgBitmap != None) {
740          XFreePixmap(mainDisplay, textBackingBgBitmap);
741       }
742       if (textBackingPixmap != None) {
743          XFreePixmap(mainDisplay, textBackingPixmap);
744       }
745       tmp_w = max(bbox_w,textBackingBitmapW);
746       tmp_h = max(bbox_h,textBackingBitmapH);
747       textBackingBitmap = XCreatePixmap(mainDisplay, mainWindow,
748             tmp_w, tmp_h, 1);
749       textBackingBgBitmap = XCreatePixmap(mainDisplay, mainWindow,
750             tmp_w, tmp_h, 1);
751       textBackingPixmap = XCreatePixmap(mainDisplay, mainWindow,
752             tmp_w, tmp_h, mainDepth);
753       if (textBackingBitmap == None || textBackingBgBitmap == None ||
754             textBackingPixmap == None) {
755          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
756          return FailAllocPixmapMessage(tmp_w, tmp_h);
757       }
758       textBackingBitmapW = tmp_w;
759       textBackingBitmapH = tmp_h;
760    }
761    switch (textJust) {
762    case JUST_L: x = (-min_lbearing); break;
763    case JUST_C:
764       x = ((bbox_w+min_lbearing-max_rextra-w)>>1)-min_lbearing+(w>>1);
765       break;
766    case JUST_R: x = bbox_w-max_rextra; break;
767    }
768    XFillRectangle(mainDisplay, textBackingPixmap, xpmGC, 0, 0, bbox_w, bbox_h);
769    XSetForeground(mainDisplay, rotateGC, 0);
770    XFillRectangle(mainDisplay, textBackingBitmap, rotateGC, 0, 0, bbox_w,
771          bbox_h);
772    XFillRectangle(mainDisplay, textBackingBgBitmap, rotateGC, 0, 0, bbox_w,
773          bbox_h);
774    XSetForeground(mainDisplay, rotateGC, 1);
775 
776    ResetDirtyBBoxInfo();
777    transPat = FALSE;
778    penPat = SOLIDPAT;
779    PaintMiniLines(mainDisplay, textBackingBgBitmap, rotateGC, 1,
780          x, baseline_y, minilines, FALSE, TRUE);
781 
782    penPat = text_ptr->pen;
783    PaintMiniLines(mainDisplay, textBackingBitmap, rotateGC, 1,
784          x, baseline_y, minilines, FALSE, TRUE);
785    PaintMiniLines(mainDisplay, textBackingPixmap, xpmGC, mainDepth,
786          x, baseline_y, minilines, FALSE, FALSE);
787 
788    penPat = saved_pen;
789    transPat = saved_trans_pat;
790 
791    return TRUE;
792 }
793 
794 #ifdef NOT_DEFINED
795 #ifdef _TGIF_DBG /* debug, do not translate */
796 static
DebugCachedTextBitmapImage(image,before,w,h,min_lbearing,max_rextra)797 void DebugCachedTextBitmapImage(image, before, w, h, min_lbearing, max_rextra)
798    XImage *image;
799    int before, w, h, min_lbearing, max_rextra;
800 {
801    int i=0;
802 
803    if (before) fprintf(stderr, "\n");
804    fprintf(stderr, "           w = %1d\n", w);
805    fprintf(stderr, "           h = %1d\n", h);
806    if (before) {
807       fprintf(stderr, "min_lbearing = %1d\n", min_lbearing);
808       fprintf(stderr, "  max_rextra = %1d\n", max_rextra);
809    }
810    for (i=0; i < h; i++) {
811       int j=0;
812 
813       for (j=0; j < w; j++) {
814          int data=XGetPixel(image,j,i);
815 
816          fprintf(stderr, "%c%s", (data==1 ? 'X' : ' '), (j+1 == w ? "\n" : ""));
817       }
818    }
819 }
820 #endif /* _TGIF_DBG */
821 #endif /* NOT_DEFINED */
822 
MakeCachedTextBitmap(ObjPtr)823 void MakeCachedTextBitmap(ObjPtr)
824    struct ObjRec *ObjPtr;
825 {
826    int r=0, c=0, bbox_w=0, bbox_h=0, num_cols=0, num_rows=0;
827    int watch_cursor=FALSE, do_msg=FALSE, min_lbearing=0, max_rextra=0;
828    int flat=FALSE, skinny=FALSE, start_row=0, start_col=0, ok=FALSE;
829    struct MtrxRec mtrx;
830    Pixmap dest_bitmap=None, dest_bg_bitmap=None, dest_pixmap=None;
831    XImage *src_image=NULL, *src_bitmap_image=NULL, *src_bitmap_bg_image=NULL;
832    XImage *dest_image=NULL, *dest_bitmap_image=NULL, *dest_bitmap_bg_image=NULL;
833    struct TextRec *text_ptr=ObjPtr->detail.t;
834 
835    if (ObjPtr->ctm == NULL && text_ptr->cached_bitmap != None &&
836          text_ptr->cached_zoomed == zoomedIn &&
837          text_ptr->cached_zoom == zoomScale) {
838       return;
839    }
840    if (ObjPtr->obbox.ltx==ObjPtr->obbox.rbx ||
841          ObjPtr->obbox.lty==ObjPtr->obbox.rby) {
842       return;
843    }
844    InvalidateTextCache(text_ptr);
845 
846    if (PRTGIF) {
847       RecalcTextMetrics(text_ptr, ObjPtr->x, text_ptr->baseline_y);
848    }
849    if (curChoice == DRAWTEXT && textCursorShown && ObjPtr == curTextObj) {
850       if (RestoreEditTextSize(ObjPtr, TRUE)) {
851          UpdTextBBox(ObjPtr);
852       }
853    }
854    if (text_ptr->read_only) {
855       min_lbearing = text_ptr->min_lbearing;
856       max_rextra = text_ptr->max_rextra;
857       bbox_w = text_ptr->orig_w;
858       bbox_h = text_ptr->orig_h;
859    } else {
860       min_lbearing = text_ptr->min_lbearing;
861       max_rextra = text_ptr->max_rextra;
862       bbox_w = text_ptr->w - min_lbearing + max_rextra;
863       bbox_h = text_ptr->h;
864    }
865    ok = PaintBackingPixmap(text_ptr, bbox_w, bbox_h, min_lbearing,
866          max_rextra, text_ptr->minilines.first->asc);
867    if (curChoice == DRAWTEXT && textCursorShown && ObjPtr == curTextObj) {
868       if (RestoreEditTextSize(ObjPtr, FALSE)) {
869          UpdTextBBox(ObjPtr);
870       }
871    }
872    if (!ok) {
873       return;
874    }
875    watch_cursor = watchCursorOnMainWindow;
876    if (!watch_cursor && !RedrawDuringScrolling()) {
877       SetWatchCursor(drawWindow);
878       SetWatchCursor(mainWindow);
879    } else {
880       CheckInterrupt(TRUE);
881    }
882    src_image = XGetImage(mainDisplay, textBackingPixmap, 0, 0, bbox_w, bbox_h,
883          AllPlanes, ZPixmap);
884    src_bitmap_image = XGetImage(mainDisplay, textBackingBitmap, 0, 0,
885          bbox_w, bbox_h, 1, ZPixmap);
886    src_bitmap_bg_image = XGetImage(mainDisplay, textBackingBgBitmap, 0, 0,
887          bbox_w, bbox_h, 1, ZPixmap);
888 
889    if (ObjPtr->ctm == NULL) {
890       if (text_ptr->read_only) {
891          num_cols = ObjPtr->bbox.rbx - ObjPtr->bbox.ltx - 2;
892          num_rows = ObjPtr->bbox.rby - ObjPtr->bbox.lty - 2;
893       } else {
894          num_cols = bbox_w; num_rows = bbox_h;
895       }
896       if (zoomedIn || zoomScale == 0) {
897          num_cols <<= zoomScale;
898          num_rows <<= zoomScale;
899       } else {
900          num_cols >>= zoomScale;
901          num_rows >>= zoomScale;
902       }
903    } else {
904       num_cols = ZOOMED_SIZE(ObjPtr->bbox.rbx - ObjPtr->bbox.ltx - 2);
905       num_rows = ZOOMED_SIZE(ObjPtr->bbox.rby - ObjPtr->bbox.lty - 2);
906    }
907    if (num_cols == 0) {
908       skinny = TRUE;
909       num_cols = 1;
910    }
911    if (num_rows == 0) {
912       flat = TRUE;
913       num_rows = 1;
914    }
915    do_msg = (((num_rows*num_cols)>=0x4000) && !RedrawDuringScrolling());
916    if (do_msg) {
917       SaveStatusStrings();
918       SetStringStatus(TgLoadCachedString(CSTID_CACHING_TEXT_BMP));
919       XSync(mainDisplay, False);
920    }
921    dest_bitmap = XCreatePixmap(mainDisplay,mainWindow,num_cols,num_rows,1);
922    dest_bg_bitmap = XCreatePixmap(mainDisplay,mainWindow,num_cols,num_rows,1);
923    XSetForeground(mainDisplay, rotateGC, 0);
924    XFillRectangle(mainDisplay,dest_bitmap,rotateGC,0,0,num_cols,num_rows);
925    XFillRectangle(mainDisplay,dest_bg_bitmap,rotateGC,0,0,num_cols,num_rows);
926    dest_pixmap = XCreatePixmap(mainDisplay, mainWindow, num_cols, num_rows,
927          mainDepth);
928    XFillRectangle(mainDisplay, dest_pixmap, xpmGC, 0, 0, num_cols, num_rows);
929 
930    dest_image = XGetImage(mainDisplay, dest_pixmap, 0, 0, num_cols,
931          num_rows, AllPlanes, ZPixmap);
932    dest_bitmap_image = XGetImage(mainDisplay, dest_bitmap, 0, 0, num_cols,
933          num_rows, 1, ZPixmap);
934    dest_bitmap_bg_image = XGetImage(mainDisplay, dest_bg_bitmap, 0, 0, num_cols,
935          num_rows, 1, ZPixmap);
936 
937    if (!flat && !skinny) {
938 #ifdef NOT_DEFINED
939 #ifdef _TGIF_DBG
940       DebugCachedTextBitmapImage(src_bitmap_image, TRUE, bbox_w, bbox_h,
941             min_lbearing, max_rextra);
942 #endif /* _TGIF_DBG */
943 #endif /* NOT_DEFINED */
944       if (ObjPtr->ctm == NULL) {
945          mtrx.image_w = (float)bbox_w;
946          mtrx.image_h = (float)bbox_h;
947          mtrx.w = (float)num_cols;
948          mtrx.h = (float)num_rows;
949          mtrx.rotate = ROTATE0;
950          mtrx.flip = NO_FLIP;
951 
952          CalcTransform(&mtrx);
953 
954          start_col = (mtrx.transformed_w >= 0.0) ? 0 : (-num_cols)+1;
955          start_row = (mtrx.transformed_h >= 0.0) ? 0 : (-num_rows)+1;
956 
957          for (r=0; r < num_rows; r++) {
958             double part_x, part_y;
959 
960             if (do_msg && ((r & 0xf) == 0)) {
961                int percent=(r*10000/num_rows)/100;
962 
963                sprintf(gszMsgBox, TgLoadCachedString(CSTID_PROGRESS_PERCENT),
964                      percent);
965                SetStringStatus(gszMsgBox);
966                XSync(mainDisplay, False);
967             }
968             part_x = ((double)(r+start_row)+0.5)*(mtrx.rev_m[1][0]);
969             part_y = ((double)(r+start_row)+0.5)*(mtrx.rev_m[1][1]);
970             for (c=0; c < num_cols; c++) {
971                double x, y;
972 
973                x = part_x+((double)(c+start_col)+0.5)*(mtrx.rev_m[0][0]);
974                y = part_y+((double)(c+start_col)+0.5)*(mtrx.rev_m[0][1]);
975                if (x >= ((double)0) && x < ((double)bbox_w) &&
976                      y >= ((double)0) && y < ((double)bbox_h)) {
977                   int new_x=(int)x, new_y=(int)y;
978 
979                   if (new_x < 0) new_x = 0;
980                   if (new_x >= bbox_w) new_x = bbox_w-1;
981                   if (new_y < 0) new_y = 0;
982                   if (new_y >= bbox_h) new_y = bbox_h-1;
983                   if (XGetPixel(src_bitmap_image, new_x, new_y) == 1) {
984                      int dest_pixel=XGetPixel(src_image, new_x, new_y);
985 
986                      XPutPixel(dest_bitmap_image, c, r, 1);
987                      XPutPixel(dest_image, c, r, dest_pixel);
988                   }
989                   if (XGetPixel(src_bitmap_bg_image, new_x, new_y) == 1) {
990                      XPutPixel(dest_bitmap_bg_image, c, r, 1);
991                   }
992                }
993             }
994          }
995       } else {
996          int abs_offset_x=ObjPtr->bbox.ltx+1-ObjPtr->x;
997          int abs_offset_y=ObjPtr->bbox.lty+1-ObjPtr->y;
998          int abs_adj_x=ObjPtr->x-ObjPtr->orig_obbox.ltx;
999          int abs_adj_y=ObjPtr->y-ObjPtr->orig_obbox.lty;
1000 
1001          for (r=0; r < num_rows; r++) {
1002             int y=abs_offset_y+ABS_SIZE(r);
1003             double dy=((double)y)+0.5;
1004 
1005             if (do_msg && ((r & 0xf) == 0)) {
1006                int percent=(r*10000/num_rows)/100;
1007 
1008                sprintf(gszMsgBox, TgLoadCachedString(CSTID_PROGRESS_PERCENT),
1009                      percent);
1010                SetStringStatus(gszMsgBox);
1011                XSync(mainDisplay, False);
1012             }
1013             for (c=0; c < num_cols; c++) {
1014                int x=abs_offset_x+ABS_SIZE(c);
1015                double dx=((double)x)+0.5;
1016                double new_dx=((double)0), new_dy=((double)0);
1017 
1018                ReverseTransformDoublePointThroughCTM(dx, dy, ObjPtr->ctm,
1019                      &new_dx, &new_dy);
1020                new_dx += (double)abs_adj_x;
1021                new_dy += (double)abs_adj_y;
1022                if (new_dx >= ((double)0) && new_dx < ((double)bbox_w) &&
1023                      new_dy >= ((double)0) && new_dy < ((double)bbox_h)) {
1024                   int new_x=(int)new_dx, new_y=(int)new_dy;
1025 
1026                   if (new_x < 0) new_x = 0;
1027                   if (new_x >= bbox_w) new_x = bbox_w-1;
1028                   if (new_y < 0) new_y = 0;
1029                   if (new_y >= bbox_h) new_y = bbox_h-1;
1030                   if (XGetPixel(src_bitmap_image, new_x, new_y) == 1) {
1031                      int dest_pixel=XGetPixel(src_image, new_x, new_y);
1032 
1033                      XPutPixel(dest_bitmap_image, c, r, 1);
1034                      XPutPixel(dest_image, c, r, dest_pixel);
1035                   }
1036                   if (XGetPixel(src_bitmap_bg_image, new_x, new_y) == 1) {
1037                      XPutPixel(dest_bitmap_bg_image, c, r, 1);
1038                   }
1039                }
1040             }
1041          }
1042          memcpy(&text_ptr->cached_ctm,ObjPtr->ctm,sizeof(struct XfrmMtrxRec));
1043       }
1044 #ifdef NOT_DEFINED
1045 #ifdef _TGIF_DBG
1046       DebugCachedTextBitmapImage(dest_bitmap_image, FALSE, num_cols, num_rows,
1047             0, 0);
1048 #endif /* _TGIF_DBG */
1049 #endif /* NOT_DEFINED */
1050    }
1051    if (do_msg) {
1052       SetStringStatus(TgLoadCachedString(CSTID_FINISHED_CACHEING_TEXT_BMP));
1053       XSync(mainDisplay, False);
1054    }
1055    XPutImage(mainDisplay, dest_bitmap, rotateGC, dest_bitmap_image, 0, 0, 0, 0,
1056          num_cols, num_rows);
1057    XPutImage(mainDisplay, dest_bg_bitmap, rotateGC, dest_bitmap_bg_image, 0, 0,
1058          0, 0, num_cols, num_rows);
1059    XPutImage(mainDisplay, dest_pixmap, xpmGC, dest_image, 0, 0, 0, 0,
1060          num_cols, num_rows);
1061    if (do_msg) RestoreStatusStrings();
1062 
1063    text_ptr->cached_bitmap = dest_bitmap;
1064    text_ptr->cached_bg_bitmap = dest_bg_bitmap;
1065    text_ptr->cached_pixmap = dest_pixmap;
1066    text_ptr->cached_zoomed = zoomedIn;
1067    text_ptr->cached_zoom = zoomScale;
1068    XDestroyImage(src_image);
1069    XDestroyImage(src_bitmap_image);
1070    XDestroyImage(src_bitmap_bg_image);
1071    XDestroyImage(dest_image);
1072    XDestroyImage(dest_bitmap_image);
1073    XDestroyImage(dest_bitmap_bg_image);
1074 
1075    if (!watch_cursor && !RedrawDuringScrolling()) {
1076       SetDefaultCursor(mainWindow);
1077       ShowCursor();
1078    } else {
1079       CheckInterrupt(TRUE);
1080    }
1081 }
1082 
CleanOuterInnerSel()1083 void CleanOuterInnerSel()
1084 {
1085    register struct SelRec *sel_ptr, *next_sel;
1086 
1087    if (outerSel != NULL) {
1088       for (sel_ptr=outerSel; sel_ptr != NULL; sel_ptr=next_sel) {
1089          next_sel = sel_ptr->next;
1090          free(sel_ptr);
1091       }
1092       outerSel = innerSel = NULL;
1093    }
1094 }
1095 
UpdateOuterInnerSel(obj_ptr)1096 void UpdateOuterInnerSel(obj_ptr)
1097    struct ObjRec *obj_ptr;
1098    /* outerSel is at the top of the chain and innerSel is at the bottom */
1099 {
1100    AddObjIntoSel(obj_ptr, NULL, outerSel, &outerSel, &innerSel);
1101 }
1102 
1103 /*
1104  * Need to check for pins.
1105  */
1106 
1107 static
SubFindTextObj(ObjPtr,XOff,YOff,obj_to_be_found)1108 struct ObjRec *SubFindTextObj(ObjPtr, XOff, YOff, obj_to_be_found)
1109    struct ObjRec *ObjPtr, *obj_to_be_found;
1110    int XOff, YOff;
1111 {
1112    register struct ObjRec *obj_ptr;
1113    register struct AttrRec *attr_ptr;
1114    struct ObjRec *found_text_obj;
1115 
1116    for (obj_ptr=ObjPtr->detail.r->first; obj_ptr!=NULL; obj_ptr=obj_ptr->next) {
1117       if (ObjPtr->type == OBJ_PIN && obj_ptr != GetPinObj(ObjPtr)) {
1118          continue;
1119       }
1120       obj_ptr->tmp_parent = ObjPtr;
1121       if (obj_to_be_found == NULL) {
1122          if (obj_ptr->type == OBJ_TEXT &&
1123                XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1124                YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1125                XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1126                YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1127             return obj_ptr;
1128          } else {
1129             attr_ptr = obj_ptr->fattr;
1130             for (; attr_ptr != NULL;  attr_ptr=attr_ptr->next) {
1131                if (XOff>=OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1132                      YOff>=OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1133                      XOff<=OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1134                      YOff<=OFFSET_Y(attr_ptr->obj->bbox.rby)+3 &&
1135                      attr_ptr->shown == TRUE) {
1136                   return attr_ptr->obj;
1137                }
1138             }
1139             switch (obj_ptr->type) {
1140             case OBJ_GROUP:
1141             case OBJ_ICON:
1142             case OBJ_SYM:
1143             case OBJ_PIN: break;
1144             default: continue;
1145             }
1146             if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1147                   YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1148                   XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1149                   YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1150                if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1151                      obj_to_be_found)) != NULL) {
1152                   UpdateOuterInnerSel(obj_ptr);
1153                   return found_text_obj;
1154                }
1155             }
1156          }
1157       } else {
1158          if (obj_ptr == obj_to_be_found) {
1159             return obj_ptr;
1160          } else {
1161             attr_ptr = obj_ptr->fattr;
1162             for (; attr_ptr != NULL;  attr_ptr=attr_ptr->next) {
1163                if (attr_ptr->obj == obj_to_be_found) {
1164                   return attr_ptr->obj;
1165                }
1166             }
1167             switch (obj_ptr->type) {
1168             case OBJ_GROUP:
1169             case OBJ_ICON:
1170             case OBJ_SYM:
1171             case OBJ_PIN: break;
1172             default: continue;
1173             }
1174             if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1175                   obj_to_be_found)) != NULL) {
1176                UpdateOuterInnerSel(obj_ptr);
1177                return found_text_obj;
1178             }
1179          }
1180       }
1181    }
1182    return NULL;
1183 }
1184 
FindTextObj(XOff,YOff,obj_to_be_found)1185 struct ObjRec *FindTextObj(XOff, YOff, obj_to_be_found)
1186    int XOff, YOff;
1187    struct ObjRec *obj_to_be_found;
1188    /* XOff and YOff are screen offsets */
1189 {
1190    register struct ObjRec *obj_ptr;
1191    register struct AttrRec *attr_ptr;
1192    struct ObjRec *found_text_obj;
1193 
1194    CleanOuterInnerSel();
1195 
1196    for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
1197       obj_ptr->tmp_parent = NULL;
1198       if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1199          continue;
1200       }
1201       if (obj_to_be_found == NULL) {
1202          if (obj_ptr->type == OBJ_TEXT &&
1203                XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1204                YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1205                XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1206                YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1207             return obj_ptr;
1208          } else {
1209             attr_ptr = obj_ptr->fattr;
1210             for (; attr_ptr != NULL;  attr_ptr=attr_ptr->next) {
1211                if (XOff>=OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1212                      YOff>=OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1213                      XOff<=OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1214                      YOff<=OFFSET_Y(attr_ptr->obj->bbox.rby)+3 &&
1215                      attr_ptr->shown == TRUE) {
1216                   return attr_ptr->obj;
1217                }
1218             }
1219             if (!groupedTextEditable) continue;
1220 
1221             switch (obj_ptr->type) {
1222             case OBJ_GROUP:
1223             case OBJ_ICON:
1224             case OBJ_SYM:
1225             case OBJ_PIN: break;
1226             default: continue;
1227             }
1228             if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1229                   YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1230                   XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1231                   YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1232                if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1233                } else if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1234                      obj_to_be_found)) != NULL) {
1235                   UpdateOuterInnerSel(obj_ptr);
1236                   return found_text_obj;
1237                }
1238             }
1239          }
1240       } else {
1241          if (obj_ptr == obj_to_be_found) {
1242             return obj_ptr;
1243          } else {
1244             attr_ptr = obj_ptr->fattr;
1245             for (; attr_ptr != NULL;  attr_ptr=attr_ptr->next) {
1246                if (attr_ptr->obj == obj_to_be_found) {
1247                   return attr_ptr->obj;
1248                }
1249             }
1250             if (!groupedTextEditable) continue;
1251 
1252             switch (obj_ptr->type) {
1253             case OBJ_GROUP:
1254             case OBJ_ICON:
1255             case OBJ_SYM:
1256             case OBJ_PIN: break;
1257             default: continue;
1258             }
1259             if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1260             } else if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1261                   obj_to_be_found)) != NULL) {
1262                UpdateOuterInnerSel(obj_ptr);
1263                return found_text_obj;
1264             }
1265          }
1266       }
1267    }
1268    return NULL;
1269 }
1270 
UnlinkCurTextFromInnerSel()1271 void UnlinkCurTextFromInnerSel()
1272 {
1273    register struct GroupRec *group_obj=innerSel->obj->detail.r;
1274 
1275    if (group_obj->first == group_obj->last) {
1276       if (outerSel != innerSel || innerSel->obj->fattr != NULL) {
1277 #ifdef _TGIF_DBG /* debug, do not translate */
1278          sprintf(gszMsgBox, "%s %s.  %s!  %s %s.",
1279                "Error!   The text object within a composite object which you",
1280                "have just erased caused all ancestors to be deleted",
1281                "You may see ghost images now",
1282                "Please undo and try ungroup the ancestor object first",
1283                "before erasing the text");
1284          if (PRTGIF) {
1285             fprintf(stderr, "%s\n", gszMsgBox);
1286          } else {
1287             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1288          }
1289 #endif /* _TGIF_DBG */
1290       }
1291       DelObj(outerSel->obj);
1292       CleanOuterInnerSel();
1293       curTextObj = NULL;
1294       return;
1295    } else if (curTextObj == group_obj->first) {
1296       curTextObj->next->prev = NULL;
1297       group_obj->first = curTextObj->next;
1298    } else if (curTextObj == group_obj->last) {
1299       curTextObj->prev->next = NULL;
1300       group_obj->last = curTextObj->prev;
1301    } else {
1302       curTextObj->prev->next = curTextObj->next;
1303       curTextObj->next->prev = curTextObj->prev;
1304    }
1305    curTextObj->prev = curTextObj->next = NULL;
1306 }
1307 
AdjAncestorsBBox()1308 void AdjAncestorsBBox()
1309 {
1310    register struct SelRec *sel_ptr;
1311 
1312    for (sel_ptr=innerSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1313       AdjObjBBox(sel_ptr->obj);
1314    }
1315 }
1316 
1317 static
DumpTextPath(FP,ObjPtr)1318 void DumpTextPath(FP, ObjPtr)
1319    FILE *FP;
1320    struct ObjRec *ObjPtr;
1321 {
1322    struct TextRec *text_ptr=ObjPtr->detail.t;
1323    MiniLinesInfo *minilines=(&text_ptr->minilines);
1324    int x=ObjPtr->x, y=ObjPtr->y, trans_pat=ObjPtr->trans_pat;
1325 
1326    fprintf(FP, "   %s\n", gPsCmd[PS_GSAVE]);
1327    fprintf(FP, "      1 %s\n", gPsCmd[PS_SETLINEWIDTH]);
1328    if (ObjPtr->ctm != NULL) {
1329       float m[6];
1330 
1331       m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
1332       m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
1333       m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
1334       m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
1335       fprintf(FP, "      %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
1336             gPsCmd[PS_TRANSLATE]);
1337       fprintf(FP, "      [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
1338             m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
1339             ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
1340       x = y = 0;
1341    }
1342    switch (penPat) {
1343    case SOLIDPAT: break;
1344    case BACKPAT:
1345       if (!trans_pat) {
1346          fprintf(FP, "      1 %s\n", gPsCmd[PS_SETGRAY]);
1347       }
1348       break;
1349    default:
1350       if (!colorDump && useGray) {
1351          GrayCheck(penPat);
1352          fprintf(FP, "      %s %s\n", GrayStr(penPat), gPsCmd[PS_SETGRAY]);
1353       }
1354       break;
1355    }
1356    fprintf(FP, "      %1d %1d %s\n", x, y+minilines->first->asc,
1357          gPsCmd[PS_MOVETO]);
1358    if (preDumpSetup) PSUseMiniLines();
1359    DumpMiniLines(minilines, x, y+minilines->first->asc, FP, &ObjPtr->obbox,
1360          TRUE, 6);
1361 
1362 #ifdef _TGIF_DBG
1363    CleanUpIndentStrings();
1364 #endif /* _TGIF_DBG */
1365 
1366    fprintf(FP, "   %s\n", gPsCmd[PS_GRESTORE]);
1367 }
1368 
1369 static
DumpSimpleTextBBoxPath(FP,just,x,lty,rby,indent)1370 void DumpSimpleTextBBoxPath(FP, just, x, lty, rby, indent)
1371    FILE *FP;
1372    int just, x, lty, rby, indent;
1373 {
1374    int i=0;
1375 
1376    if (psUseShortHand) {
1377       for (i=0; i < indent; i++) fprintf(FP, " ");
1378       fprintf(FP, "%s %1d %1d %s ",
1379             gPsCmd[PS_NEWPATH],
1380             x, lty, gPsCmd[PS_MOVETO]);
1381       switch (just) {
1382       case JUST_L: break;
1383       case JUST_C:
1384          fprintf(FP, "tgifstrw 2 %s %s 0 %s ",
1385                gPsCmd[PS_DIV], gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1386          break;
1387       case JUST_R:
1388          fprintf(FP, "tgifstrw %s 0 %s ", gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1389          break;
1390       }
1391       fprintf(FP, "tgifstrw 0 %s 0 %1d %s tgifstrw neg 0 %s %s ",
1392             gPsCmd[PS_RLINETO], rby-lty, gPsCmd[PS_RLINETO],
1393             gPsCmd[PS_RLINETO], gPsCmd[PS_CLOSEPATH]);
1394    } else {
1395       for (i=0; i < indent; i++) fprintf(FP, " ");
1396       fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
1397       for (i=0; i < indent; i++) fprintf(FP, " ");
1398 
1399       fprintf(FP, "   %1d %1d %s ", x, lty, gPsCmd[PS_MOVETO]);
1400       switch (just) {
1401       case JUST_L: break;
1402       case JUST_C:
1403          fprintf(FP, "tgifstrw 2 %s %s 0 %s\n",
1404                gPsCmd[PS_DIV], gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1405          for (i=0; i < indent+3; i++) fprintf(FP, " ");
1406          break;
1407       case JUST_R:
1408          fprintf(FP, "tgifstrw %s 0 %s\n", gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1409          for (i=0; i < indent+3; i++) fprintf(FP, " ");
1410          break;
1411       }
1412       fprintf(FP, "tgifstrw 0 %s ", gPsCmd[PS_RLINETO]);
1413       fprintf(FP, "0 %1d %s ", rby-lty, gPsCmd[PS_RLINETO]);
1414       fprintf(FP, "tgifstrw neg 0 %s\n", gPsCmd[PS_RLINETO]);
1415       for (i=0; i < indent; i++) fprintf(FP, " ");
1416       fprintf(FP, "%s ", gPsCmd[PS_CLOSEPATH]);
1417    }
1418 }
1419 
1420 static
DumpTextFill(FP,ObjPtr)1421 void DumpTextFill(FP, ObjPtr)
1422    FILE *FP;
1423    struct ObjRec *ObjPtr;
1424 {
1425    struct TextRec *text_ptr=ObjPtr->detail.t;
1426    int fill=text_ptr->fill, trans_pat=ObjPtr->trans_pat, ltx, lty, rbx, rby;
1427    int color_index=ObjPtr->color;
1428    int simple_text=SimpleTextObj(text_ptr);
1429 
1430    if (simple_text) {
1431       fprintf(FP, "   /tgifstrw 0 def\n");
1432       DumpSimpleTextPath(FP, ObjPtr);
1433    }
1434    DumpRGBColorLine(FP, color_index, 0, TRUE);
1435 
1436    if (ObjPtr->ctm == NULL) {
1437       ltx = ObjPtr->bbox.ltx;
1438       lty = ObjPtr->bbox.lty;
1439       rbx = ObjPtr->bbox.rbx-1;
1440       rby = ObjPtr->bbox.rby-1;
1441    } else {
1442       ltx = ObjPtr->detail.t->orig_bbox.ltx;
1443       lty = ObjPtr->detail.t->orig_bbox.lty;
1444       rbx = ObjPtr->detail.t->orig_bbox.rbx-1;
1445       rby = ObjPtr->detail.t->orig_bbox.rby-1;
1446    }
1447    if (ObjPtr->ctm != NULL) {
1448       float m[6];
1449 
1450       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
1451       m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
1452       m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
1453       m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
1454       m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
1455       fprintf(FP, "   %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
1456             gPsCmd[PS_TRANSLATE]);
1457       fprintf(FP, "   [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
1458             m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
1459             ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
1460       fprintf(FP, "   %1d %s %1d %s %s\n",
1461             ObjPtr->x, gPsCmd[PS_NEG], ObjPtr->y, gPsCmd[PS_NEG],
1462             gPsCmd[PS_TRANSLATE]);
1463    }
1464    switch (fill) {
1465    case NONEPAT: break;
1466    case SOLIDPAT:
1467       if (simple_text) {
1468          DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1469                ObjPtr->x, lty, rby, 0);
1470       } else {
1471          DumpRectPath(FP, ltx, lty, rbx, rby, 0, FALSE);
1472       }
1473       fprintf(FP, "%s\n", gPsCmd[PS_FILL]);
1474       break;
1475    case BACKPAT:
1476       if (!trans_pat) {
1477          if (simple_text) {
1478             DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1479                   ObjPtr->x, lty, rby, 0);
1480          } else {
1481             DumpRectPath(FP, ltx, lty, rbx, rby, 0, FALSE);
1482          }
1483          fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
1484          DumpRGBColorLine(FP, color_index, 0, TRUE);
1485       }
1486       break;
1487    default:
1488       /* patterned */
1489       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
1490       if (colorDump || !useGray) {
1491          if (!trans_pat) {
1492             if (simple_text) {
1493                DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1494                      ObjPtr->x, lty, rby, 3);
1495             } else {
1496                DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
1497             }
1498             fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
1499             DumpRGBColorLine(FP, color_index, 3, TRUE);
1500          }
1501       } else {
1502          GrayCheck(fill);
1503          fprintf(FP, "      %s %s\n", GrayStr(fill), gPsCmd[PS_SETGRAY]);
1504       }
1505       if (colorDump || !useGray) {
1506          if (preDumpSetup) PSUseColorPattern();
1507          if (simple_text) {
1508             DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1509                   ObjPtr->x, lty, rby, 3);
1510          } else {
1511             DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
1512          }
1513          fprintf(FP, "%s %s\n", gPsCmd[PS_EOCLIP], gPsCmd[PS_NEWPATH]);
1514          DumpPatFill(FP, fill, ObjPtr->bbox, 3, TRUE);
1515       } else {
1516          if (simple_text) {
1517             DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1518                   ObjPtr->x, lty, rby, 3);
1519          } else {
1520             DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
1521          }
1522          fprintf(FP, "%s\n", gPsCmd[PS_FILL]);
1523       }
1524       fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
1525       break;
1526    }
1527    if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
1528 }
1529 
DumpTextObj(FP,ObjPtr)1530 void DumpTextObj(FP, ObjPtr)
1531    FILE *FP;
1532    register struct ObjRec *ObjPtr;
1533 {
1534    struct TextRec *text_ptr=ObjPtr->detail.t;
1535    MiniLinesInfo *minilines=(&text_ptr->minilines);
1536    int pen=text_ptr->pen, fill=text_ptr->fill, trans_pat=ObjPtr->trans_pat;
1537    int underline_y_offset=text_ptr->underline_y_offset;
1538    int overline_y_offset=text_ptr->overline_y_offset;
1539 
1540    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
1541          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
1542       return;
1543    }
1544    if (ObjPtr->ctm != NULL && (ObjPtr->obbox.ltx == ObjPtr->obbox.rbx ||
1545          ObjPtr->obbox.lty == ObjPtr->obbox.rby)) {
1546       /* zero width or height text */
1547       return;
1548    }
1549    fprintf(FP, "%% TEXT\n");
1550    fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
1551 
1552    if (!PRTGIF) SaveCurFont();
1553 
1554    ObjFontInfoToCurFontInfo(text_ptr);
1555 
1556    penPat = pen;
1557    transPat = trans_pat;
1558    objFill = fill;
1559    curUnderlineYOffset = underline_y_offset;
1560    curOverlineYOffset = overline_y_offset;
1561 
1562    if (PRTGIF || text_ptr->read_only) {
1563       canvasFontAsc = minilines->first->asc;
1564       canvasFontDes = minilines->first->des;
1565       textCursorH = canvasFontAsc + canvasFontDes;
1566    }
1567    /* fill the bounding rectangle */
1568    DumpTextFill(FP, ObjPtr);
1569 
1570    if (penPat == NONEPAT) {
1571       fprintf(FP, "\n");
1572       if (!PRTGIF) RestoreCurFont();
1573       return;
1574    }
1575    if ((colorDump || !useGray) && penPat>BACKPAT && curFont==FONT_COU) {
1576       if (PRTGIF) {
1577          fprintf(stderr, "%s\n",
1578                TgLoadString(STID_WARN_PRINT_COURIER_IN_COLOR));
1579          fprintf(stderr, "%s\n",
1580                TgLoadString(STID_MAY_CAUSE_ERROR_IN_PRINTOUT));
1581       } else {
1582          TwoLineMsg(TgLoadString(STID_WARN_PRINT_COURIER_IN_COLOR),
1583                TgLoadString(STID_MAY_CAUSE_ERROR_IN_PRINTOUT));
1584       }
1585    }
1586    if ((colorDump || !useGray) && penPat > BACKPAT && !trans_pat) {
1587       int tmp_pen = penPat;
1588 
1589       penPat = BACKPAT;
1590       DumpTextPath(FP, ObjPtr);
1591       penPat = tmp_pen;
1592    }
1593    if (!(penPat == BACKPAT && trans_pat)) {
1594       DumpTextPath(FP, ObjPtr);
1595    }
1596    fprintf(FP, "\n");
1597    if (!PRTGIF) RestoreCurFont();
1598 }
1599 
1600 static
NeedToCacheStrSeg(pStrSeg)1601 int NeedToCacheStrSeg(pStrSeg)
1602    StrSegInfo *pStrSeg;
1603 {
1604    return (pStrSeg->double_byte && pStrSeg->double_byte_vertical);
1605 }
1606 
1607 static
NeedToCacheStrBlock(pStrBlock)1608 int NeedToCacheStrBlock(pStrBlock)
1609    StrBlockInfo *pStrBlock;
1610 {
1611    switch (pStrBlock->type) {
1612    case SB_SIMPLE: return NeedToCacheStrSeg(pStrBlock->seg);
1613    case SB_CHAR_SPACE: return FALSE;
1614 
1615    case SB_SUPSUB_LEFT:
1616    case SB_SUPSUB_CENTER:
1617    case SB_SUPSUB_RIGHT:
1618       if (pStrBlock->sup != NULL && NeedToCacheMiniLines(pStrBlock->sup)) {
1619          return TRUE;
1620       }
1621       if (pStrBlock->sub != NULL && NeedToCacheMiniLines(pStrBlock->sub)) {
1622          return TRUE;
1623       }
1624       if (pStrBlock->type == SB_SUPSUB_CENTER) {
1625          return NeedToCacheStrSeg(pStrBlock->seg);
1626       }
1627       break;
1628    }
1629    return FALSE;
1630 }
1631 
1632 static
NeedToCacheMiniLine(pMiniLine)1633 int NeedToCacheMiniLine(pMiniLine)
1634    MiniLineInfo *pMiniLine;
1635 {
1636    StrBlockInfo *pStrBlock=NULL;
1637 
1638    for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
1639          pStrBlock=pStrBlock->next) {
1640       if (NeedToCacheStrBlock(pStrBlock)) {
1641          return TRUE;
1642       }
1643    }
1644    return FALSE;
1645 }
1646 
NeedToCacheMiniLines(minilines)1647 int NeedToCacheMiniLines(minilines)
1648    MiniLinesInfo *minilines;
1649 {
1650    MiniLineInfo *pMiniLine=NULL;
1651 
1652    for (pMiniLine=minilines->first; pMiniLine != NULL;
1653          pMiniLine=pMiniLine->next) {
1654       if (NeedToCacheMiniLine(pMiniLine)) {
1655          return TRUE;
1656       }
1657    }
1658    return FALSE;
1659 }
1660 
NeedsToCacheTextObj(ObjPtr)1661 int NeedsToCacheTextObj(ObjPtr)
1662    struct ObjRec *ObjPtr;
1663 {
1664    struct TextRec *text_ptr=ObjPtr->detail.t;
1665 
1666    if (ObjPtr->ctm != NULL || zoomScale != 0 || text_ptr->read_only) {
1667       return TRUE;
1668    }
1669    return NeedToCacheMiniLines(&text_ptr->minilines);
1670 }
1671 
SaveString(FP,S)1672 void SaveString(FP, S)
1673    FILE *FP;
1674    register char *S;
1675 {
1676    for ( ; *S != '\0'; S++) {
1677       if (*S == '\\') {
1678          if (fprintf(FP, "%s", "\\\\") == EOF) writeFileFailed = TRUE;
1679       } else if (*S == '"') {
1680          if (doubleQuoteDoubleQuote) {
1681             if (fprintf(FP, "%s", "\"\"") == EOF) writeFileFailed = TRUE;
1682          } else {
1683             if (fprintf(FP, "%s", "\\\"") == EOF) writeFileFailed = TRUE;
1684          }
1685       } else if ((*S) & 0x80) {
1686          if (fprintf(FP, "\\%o", (*S)&0xff) == EOF) writeFileFailed = TRUE;
1687       } else {
1688          if (fputc(*S, FP) == EOF) writeFileFailed = TRUE;
1689       }
1690    }
1691 }
1692 
SaveDoubleByteString(FP,S)1693 void SaveDoubleByteString(FP, S)
1694    FILE *FP;
1695    register char *S;
1696 {
1697    for ( ; *S != '\0'; S++) {
1698       if ((*S)&0x80) {
1699          if (fprintf(FP, "\\%03o\\%03o", S[0]&0xff, S[1]&0xff) == EOF) {
1700             writeFileFailed = TRUE;
1701          }
1702          S++;
1703          if (*S == '\0') break;
1704       } else if (*S == '\\') {
1705          if (fprintf(FP, "%s", "\\\\") == EOF) writeFileFailed = TRUE;
1706       } else if (*S == '"') {
1707          if (doubleQuoteDoubleQuote) {
1708             if (fprintf(FP, "%s", "\"\"") == EOF) writeFileFailed = TRUE;
1709          } else {
1710             if (fprintf(FP, "%s", "\\\"") == EOF) writeFileFailed = TRUE;
1711          }
1712       } else {
1713          if (fputc(*S, FP) == EOF) writeFileFailed = TRUE;
1714       }
1715    }
1716 }
1717 
1718 static
SaveStrSeg(FP,pStrSeg)1719 void SaveStrSeg(FP, pStrSeg)
1720    FILE *FP;
1721    StrSegInfo *pStrSeg;
1722    /*
1723     * str_seg()
1724     */
1725 {
1726    char font_str[MAXSTRING];
1727    int overunder=((pStrSeg->overline_on<<1)+pStrSeg->underline_on);
1728 
1729    GetPSFontStr(pStrSeg->font, pStrSeg->style, font_str);
1730          /* font_str starts with the '/' character */
1731 
1732    if (fprintf(FP, "str_seg('%s',", colorMenuItems[pStrSeg->color]) == EOF) {
1733       writeFileFailed = TRUE;
1734    }
1735    /*
1736     * When the new file format (version 38) is implemented, make sure to
1737     * save the DontReencode related information (dontreencode) in the file!
1738     */
1739    if (fprintf(FP,
1740          "'%s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,",
1741          &font_str[1], pStrSeg->style, pStrSeg->sz_unit,
1742          pStrSeg->w, pStrSeg->asc, pStrSeg->des, pStrSeg->min_lbearing,
1743          pStrSeg->max_rextra, overunder,
1744          pStrSeg->double_byte, pStrSeg->double_byte_mod_bytes,
1745          pStrSeg->double_byte_vertical, pStrSeg->direction) == EOF) {
1746       writeFileFailed = TRUE;
1747    }
1748    if (fprintf(FP, "\n\t\"") == EOF) writeFileFailed = TRUE;
1749    if (pStrSeg->double_byte) {
1750       SaveDoubleByteString(FP, pStrSeg->dyn_str.s);
1751    } else {
1752       SaveString(FP, pStrSeg->dyn_str.s);
1753    }
1754    if (fprintf(FP, "\")") == EOF) writeFileFailed = TRUE;
1755 }
1756 
1757 static
SaveAStrBlock(FP,pStrBlock)1758 void SaveAStrBlock(FP, pStrBlock)
1759    FILE *FP;
1760    StrBlockInfo *pStrBlock;
1761    /*
1762     * str_block()
1763     */
1764 {
1765    int has_sup=FALSE, has_sub=FALSE;
1766    int something_saved=FALSE;
1767 
1768    switch (pStrBlock->type) {
1769    case SB_SUPSUB_LEFT:
1770    case SB_SUPSUB_CENTER:
1771    case SB_SUPSUB_RIGHT:
1772       if (pStrBlock->sup != NULL) has_sup = TRUE;
1773       if (pStrBlock->sub != NULL) has_sub = TRUE;
1774       break;
1775    }
1776    if (fprintf(FP, "str_block(%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d",
1777          pStrBlock->type, pStrBlock->w, pStrBlock->asc, pStrBlock->des,
1778          pStrBlock->min_lbearing, pStrBlock->max_rextra,
1779          pStrBlock->special_char_w, has_sup, has_sub) == EOF) {
1780       writeFileFailed = TRUE;
1781    }
1782    switch (pStrBlock->type) {
1783    case SB_SIMPLE:
1784       if (fprintf(FP, ",[\n") == EOF) writeFileFailed = TRUE;
1785       SaveStrSeg(FP, pStrBlock->seg);
1786       if (fprintf(FP, "]") == EOF) writeFileFailed = TRUE;
1787       break;
1788    case SB_CHAR_SPACE:
1789       break;
1790 
1791    case SB_SUPSUB_LEFT:
1792    case SB_SUPSUB_CENTER:
1793    case SB_SUPSUB_RIGHT:
1794       if (fprintf(FP, ",[\n") == EOF) writeFileFailed = TRUE;
1795 
1796       if (pStrBlock->sup != NULL) {
1797          SaveMiniLines(FP, pStrBlock->sup);
1798          something_saved = TRUE;
1799       }
1800       if (pStrBlock->sub != NULL) {
1801          if (something_saved) {
1802             if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
1803          }
1804          SaveMiniLines(FP, pStrBlock->sub);
1805          something_saved = TRUE;
1806       }
1807       if (pStrBlock->type == SB_SUPSUB_CENTER) {
1808          if (something_saved) {
1809             if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
1810          }
1811          /* pStrBlock->seg better not be NULL or it will crash */
1812          SaveStrSeg(FP, pStrBlock->seg);
1813          something_saved = TRUE;
1814       }
1815       if (something_saved) {
1816          if (fprintf(FP, "\n]") == EOF) writeFileFailed = TRUE;
1817       } else {
1818          if (fprintf(FP, "]") == EOF) writeFileFailed = TRUE;
1819       }
1820       break;
1821    }
1822    if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
1823 }
1824 
1825 static
SaveStrBlocks(FP,pFirstStrBlock)1826 void SaveStrBlocks(FP, pFirstStrBlock)
1827    FILE *FP;
1828    StrBlockInfo *pFirstStrBlock;
1829    /*
1830     * ... [
1831     * str_block(),
1832     * str_block(),
1833     * ...
1834     * str_block()
1835     * ]
1836     */
1837 {
1838    StrBlockInfo *pStrBlock;
1839 
1840    if (fprintf(FP, "[\n") == EOF) writeFileFailed = TRUE;
1841 
1842    for (pStrBlock=pFirstStrBlock; pStrBlock != NULL;
1843          pStrBlock=pStrBlock->next) {
1844       SaveAStrBlock(FP, pStrBlock);
1845       if (pStrBlock->next != NULL) {
1846          if (fprintf(FP, ",\n") == EOF) {
1847             writeFileFailed = TRUE;
1848          }
1849       }
1850    }
1851    if (pFirstStrBlock == NULL) {
1852       if (fprintf(FP, "]") == EOF) writeFileFailed = TRUE;
1853    } else {
1854       if (fprintf(FP, "\n]") == EOF) writeFileFailed = TRUE;
1855    }
1856 }
1857 
1858 static
SaveAMiniLine(FP,pMiniLine)1859 void SaveAMiniLine(FP, pMiniLine)
1860    FILE *FP;
1861    MiniLineInfo *pMiniLine;
1862    /*
1863     * mini_line(w,asc,des,min_lbearing,max_rextra,v_gap)
1864     */
1865 {
1866    if (pMiniLine == pMiniLine->owner_minilines->first &&
1867          pMiniLine->v_gap != 0) {
1868       TgAssert(FALSE, "First mini_line has non-zero v_gap in SaveAMiniLine()",
1869             "It's set to 0");
1870       pMiniLine->v_gap = 0;
1871    }
1872    if (fprintf(FP, "mini_line(%1d,%1d,%1d,%1d,%1d,%1d,",
1873          pMiniLine->w, pMiniLine->asc, pMiniLine->des, pMiniLine->min_lbearing,
1874          pMiniLine->max_rextra, pMiniLine->v_gap) == EOF) {
1875       writeFileFailed = TRUE;
1876    }
1877    SaveStrBlocks(FP, pMiniLine->first_block);
1878 
1879    if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
1880 }
1881 
SaveMiniLines(FP,minilines)1882 void SaveMiniLines(FP, minilines)
1883    FILE *FP;
1884    MiniLinesInfo *minilines;
1885    /*
1886     * ... [
1887     * minilines(w,h,min_lbearing,max_rextra,just,v_space,baseline_offset,[
1888     * mini_line(),
1889     * mini_line(),
1890     * ...
1891     * mini_line()
1892     * ])
1893     * ]
1894     */
1895 {
1896    MiniLineInfo *pMiniLine=NULL;
1897 
1898    if (fprintf(FP, "minilines(%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n",
1899          minilines->w, minilines->h, minilines->min_lbearing,
1900          minilines->max_rextra, minilines->just, minilines->v_space,
1901          minilines->baseline_offset) == EOF) {
1902       writeFileFailed = TRUE;
1903    }
1904    for (pMiniLine=minilines->first; pMiniLine != NULL;
1905          pMiniLine=pMiniLine->next) {
1906       SaveAMiniLine(FP, pMiniLine);
1907       if (pMiniLine->next != NULL) {
1908          if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
1909       }
1910    }
1911    if (fprintf(FP, "\n])") == EOF) writeFileFailed = TRUE;
1912 }
1913 
CombineOverUnderYOffsets(underline_y_offset,overline_y_offset,pn_combined)1914 void CombineOverUnderYOffsets(underline_y_offset, overline_y_offset,
1915       pn_combined)
1916    int underline_y_offset, overline_y_offset, *pn_combined;
1917 {
1918    underline_y_offset = (underline_y_offset & 0x0ffff);
1919    overline_y_offset = (overline_y_offset & 0x0ffff);
1920    *pn_combined = ((overline_y_offset << 16) | underline_y_offset);
1921 }
1922 
UncombineOverUnderYOffsets(combined,pn_underline_y_offset,pn_overline_y_offset)1923 void UncombineOverUnderYOffsets(combined, pn_underline_y_offset,
1924       pn_overline_y_offset)
1925    int combined, *pn_underline_y_offset, *pn_overline_y_offset;
1926 {
1927    int underline_y_offset=(combined & 0x0ffff);
1928    int overline_y_offset=((combined >> 16) & 0x0ffff);
1929 
1930    if ((underline_y_offset & 0x08000) == 0x08000) {
1931       underline_y_offset = (0x010000 - abs(underline_y_offset));
1932       underline_y_offset = -underline_y_offset;
1933    }
1934    if ((overline_y_offset & 0x08000) == 0x08000) {
1935       overline_y_offset = (0x010000 - abs(overline_y_offset));
1936       overline_y_offset = -overline_y_offset;
1937    }
1938    *pn_underline_y_offset = underline_y_offset;
1939    *pn_overline_y_offset = overline_y_offset;
1940 }
1941 
SaveTextObj(FP,ObjPtr)1942 void SaveTextObj(FP, ObjPtr)
1943    FILE *FP;
1944    struct ObjRec *ObjPtr;
1945 {
1946    struct TextRec *text_ptr=ObjPtr->detail.t;
1947    int compressed=FALSE, combined_y_offset=0;
1948 
1949    CombineOverUnderYOffsets(text_ptr->underline_y_offset,
1950          text_ptr->overline_y_offset, &combined_y_offset);
1951    if (fprintf(FP, "text('%s',", colorMenuItems[ObjPtr->color]) == EOF) {
1952       writeFileFailed = TRUE;
1953    }
1954    if (fprintf(FP,
1955          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,",
1956          ObjPtr->x, ObjPtr->y, text_ptr->lines, text_ptr->minilines.just,
1957          text_ptr->pen, ObjPtr->obbox.rbx-ObjPtr->obbox.ltx,
1958          ObjPtr->obbox.rby-ObjPtr->obbox.lty, ObjPtr->id,
1959          text_ptr->minilines.first->first_block->asc,
1960          text_ptr->minilines.first->first_block->des) == EOF) {
1961       writeFileFailed = TRUE;
1962    }
1963    if (fprintf(FP,
1964          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,\"\",",
1965          text_ptr->fill, text_ptr->minilines.v_space, ObjPtr->rotation,
1966          ObjPtr->locked, combined_y_offset, text_ptr->w,
1967          text_ptr->h, text_ptr->min_lbearing, text_ptr->max_rextra) == EOF) {
1968       writeFileFailed = TRUE;
1969    }
1970    if (fprintf(FP,
1971          "%1d,%1d,%1d,%1d,%1d,'',",
1972          compressed, ObjPtr->ctm!=NULL, ObjPtr->invisible,
1973          ObjPtr->trans_pat, text_ptr->baseline_y) == EOF) {
1974       writeFileFailed = TRUE;
1975    }
1976    if (ObjPtr->ctm != NULL && fprintf(FP,
1977          "[\n\t%1d,%1d,%1d,%1d,%1d,%1d,%g,%g,%g,%g,%1d,%1d,%1d,%1d,%1d,%1d],",
1978          ObjPtr->x, ObjPtr->y,
1979          ObjPtr->orig_obbox.ltx, ObjPtr->orig_obbox.lty,
1980          ObjPtr->orig_obbox.rbx, ObjPtr->orig_obbox.rby,
1981          ObjPtr->ctm->m[CTM_SX], ObjPtr->ctm->m[CTM_SIN],
1982          ObjPtr->ctm->m[CTM_MSIN], ObjPtr->ctm->m[CTM_SY],
1983          ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY],
1984          text_ptr->orig_bbox.ltx, text_ptr->orig_bbox.lty,
1985          text_ptr->orig_bbox.rbx, text_ptr->orig_bbox.rby) == EOF) {
1986       writeFileFailed = TRUE;
1987    }
1988    if (serializingFile) SaveCreatorID(FP, ObjPtr, "\t");
1989    if (fprintf(FP, "[\n") == EOF) writeFileFailed = TRUE;
1990    if (text_ptr->minilines.baseline_offset != 0) {
1991       TgAssert(FALSE,
1992             "Minilines of text object has bad baseline_offset in SaveTextObj()",
1993             "It's set to 0");
1994       text_ptr->minilines.baseline_offset = 0;
1995    }
1996    SaveMiniLines(FP, &text_ptr->minilines);
1997    if (fprintf(FP, "])") == EOF) writeFileFailed = TRUE;
1998 }
1999 
SaveHexString(FP,buf)2000 void SaveHexString(FP, buf)
2001    FILE *FP;
2002    char *buf;
2003 {
2004    for ( ; *buf != '\0'; buf++) {
2005       int ival=0;
2006 
2007       ival = ((((unsigned int)(*buf)) >> 4) & 0x0f);
2008       if (ival >= 10) {
2009          fprintf(FP, "%c", (char)(((int)'a')+(ival-10)));
2010       } else {
2011          fprintf(FP, "%c", (char)(((int)'0')+ival));
2012       }
2013       ival = (((unsigned int)(*buf)) & 0x0f);
2014       if (ival >= 10) {
2015          fprintf(FP, "%c", (char)(((int)'a')+(ival-10)));
2016       } else {
2017          fprintf(FP, "%c", (char)(((int)'0')+ival));
2018       }
2019    }
2020 }
2021 
ReadString(Str)2022 char *ReadString(Str)
2023    char *Str;
2024 {
2025    register char *s=NULL;
2026 
2027    if (Str == NULL) return NULL;
2028 
2029    for (s=Str; *s != '\0'; s++) {
2030       if (*s == '"') {
2031          if (s[1] == '"') {
2032             UtilStrCpy(s, s+1);
2033          } else {
2034             break;
2035          }
2036       } else if (*s == '\\') {
2037          if (s[1] >= '0' && s[1] <= '3') {
2038             if (s[2] >= '0' && s[2] <= '7' && s[3] >= '0' && s[3] <= '7') {
2039                *s = (char)(((s[1]-'0')<<6)+((s[2]-'0')<<3)+(s[3]-'0'));
2040                UtilStrCpy(s+1, s+4);
2041             } else {
2042                sprintf(gszMsgBox,
2043                      TgLoadString(STID_BAD_OCTAL_STRING_ENCOUNTERED),
2044                      s[1], s[2], s[3]);
2045                if (PRTGIF) {
2046                   fprintf(stderr, "%s\n", gszMsgBox);
2047                } else {
2048                   Msg(gszMsgBox);
2049                }
2050                UtilStrCpy(s, s+1);
2051             }
2052          } else {
2053             UtilStrCpy(s, s+1);
2054          }
2055       }
2056    }
2057    if (*s == '"') s++;
2058    return s;
2059 }
2060 
CreateStrSegFromString(buf,pOwnerStrBlock)2061 StrSegInfo *CreateStrSegFromString(buf, pOwnerStrBlock)
2062    char *buf;
2063    StrBlockInfo *pOwnerStrBlock;
2064 {
2065    StrSegInfo *pStrSeg=NewStrSeg();
2066 
2067    DynStrSet(&pStrSeg->dyn_str, buf);
2068 
2069    pStrSeg->color = colorIndex;
2070    pStrSeg->font = curFont;
2071    pStrSeg->style = curStyle;
2072    pStrSeg->sz_unit = GetCurSzUnit();
2073    if (mainDisplay != NULL) {
2074       strcpy(pStrSeg->color_str, colorMenuItems[colorIndex]);
2075    }
2076    pStrSeg->double_byte = canvasFontDoubleByte;
2077    pStrSeg->double_byte_mod_bytes = canvasFontDoubleByteModBytes;
2078    pStrSeg->double_byte_vertical = canvasFontDoubleByteVertical;
2079    pStrSeg->direction = canvasFontDirection;
2080    pStrSeg->dontreencode = canvasFontDontReencode;
2081    pStrSeg->underline_on = curUnderlineOn;
2082    pStrSeg->overline_on = curOverlineOn;
2083 
2084    pStrSeg->asc = canvasFontAsc;
2085    pStrSeg->des = canvasFontDes;
2086    if (mainDisplay != NULL) {
2087       pStrSeg->w = MyTextWidth(canvasFontPtr, pStrSeg->dyn_str.s,
2088             pStrSeg->dyn_str.sz-1);
2089    }
2090    pStrSeg->owner = pOwnerStrBlock;
2091 
2092    return pStrSeg;
2093 }
2094 
CreateStrBlockFromString(buf,pOwnerMiniLine)2095 StrBlockInfo *CreateStrBlockFromString(buf, pOwnerMiniLine)
2096    char *buf;
2097    MiniLineInfo *pOwnerMiniLine;
2098 {
2099    StrBlockInfo *pStrBlock=NewStrBlock();
2100 
2101    pStrBlock->seg = CreateStrSegFromString(buf, pStrBlock);
2102    pStrBlock->type = SB_SIMPLE;
2103    pStrBlock->owner_mini_line = pOwnerMiniLine;
2104 
2105    return pStrBlock;
2106 }
2107 
CreateMiniLineFromString(buf,ppFirstMiniLine,ppLastMiniLine)2108 MiniLineInfo *CreateMiniLineFromString(buf, ppFirstMiniLine, ppLastMiniLine)
2109    char *buf;
2110    MiniLineInfo **ppFirstMiniLine, **ppLastMiniLine;
2111 {
2112    MiniLineInfo *pMiniLine=NewMiniLine();
2113 
2114    if (canvasFontDoubleByte) {
2115       struct StrRec *pStr=NULL, *pStr1=NULL;
2116 
2117       pStr = SegmentDoubleByteString(buf);
2118       for (pStr1=pStr; pStr1 != NULL; pStr1=pStr1->next) {
2119          int str_seg_double_byte=TRUE;
2120          StrBlockInfo *pStrBlock=CreateStrBlockFromString(pStr1->dyn_str.s,
2121                pMiniLine);
2122 
2123          if (*pStr1->dyn_str.s != '\0') {
2124             str_seg_double_byte = ((*pStr1->dyn_str.s) & 0x80);
2125          }
2126          pStrBlock->prev = pMiniLine->last_block;
2127          if (pMiniLine->first_block == NULL) {
2128             pMiniLine->first_block = pStrBlock;
2129          } else {
2130             pMiniLine->last_block->next = pStrBlock;
2131          }
2132          pMiniLine->last_block = pStrBlock;
2133 
2134          if (str_seg_double_byte == FALSE) {
2135             pStrBlock->seg->font = defaultSingleByteFont;
2136             pStrBlock->seg->double_byte = FALSE;
2137             pStrBlock->seg->double_byte_mod_bytes = FALSE;
2138             pStrBlock->seg->double_byte_vertical = FALSE;
2139          }
2140       }
2141       FreeStrList(pStr);
2142    } else {
2143       StrBlockInfo *pStrBlock=CreateStrBlockFromString(buf, pMiniLine);
2144 
2145       pMiniLine->first_block = pMiniLine->last_block = pStrBlock;
2146    }
2147    if (ppFirstMiniLine != NULL && ppLastMiniLine != NULL) {
2148       pMiniLine->prev = (*ppLastMiniLine);
2149       pMiniLine->next = NULL;;
2150       if ((*ppLastMiniLine) == NULL) {
2151          (*ppFirstMiniLine) = pMiniLine;
2152       } else {
2153          (*ppLastMiniLine)->next = pMiniLine;
2154       }
2155       (*ppLastMiniLine) = pMiniLine;
2156    }
2157    return pMiniLine;
2158 }
2159 
FormTextObjectFromFile(FP,AbsX,AbsBaselineY)2160 struct ObjRec *FormTextObjectFromFile(FP, AbsX, AbsBaselineY)
2161    FILE *FP;
2162    int AbsX, AbsBaselineY;
2163 {
2164    MiniLineInfo *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
2165    struct ObjRec *obj_ptr=NULL;
2166    struct TextRec *text_ptr=NULL;
2167    int num_lines=0;
2168 
2169    obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
2170    if (obj_ptr == NULL) FailAllocMessage();
2171    memset(obj_ptr, 0, sizeof(struct ObjRec));
2172 
2173    text_ptr = (struct TextRec *)malloc(sizeof(struct TextRec));
2174    if (text_ptr == NULL) FailAllocMessage();
2175    memset(text_ptr, 0, sizeof(struct TextRec));
2176 
2177    if (FP != NULL) {
2178       char *buf=NULL;
2179 
2180       while ((buf=UtilGetALine(FP)) != NULL) {
2181          MiniLineInfo *pMiniLine=CreateMiniLineFromString(buf,
2182                &pFirstMiniLine, &pLastMiniLine);
2183 
2184          if (pMiniLine != NULL) {
2185             num_lines++;
2186          }
2187          free(buf);
2188       }
2189    }
2190    if (num_lines == 0) {
2191       CreateMiniLineFromString("", &pFirstMiniLine, &pLastMiniLine);
2192 
2193       num_lines++;
2194    }
2195    text_ptr->lines = num_lines;
2196    text_ptr->minilines.first = pFirstMiniLine;
2197    text_ptr->minilines.last = pLastMiniLine;
2198    text_ptr->baseline_y = AbsBaselineY;
2199 
2200    CopyCurInfoIntoTextPtr(obj_ptr, text_ptr);
2201 
2202    obj_ptr->x = AbsX;
2203    obj_ptr->y = AbsBaselineY-text_ptr->minilines.first->asc;
2204    obj_ptr->type = OBJ_TEXT;
2205    obj_ptr->color = colorIndex;
2206    if (mainDisplay != NULL) {
2207       UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
2208             colorMenuItems[colorIndex]);
2209    }
2210    obj_ptr->id = objId++;;
2211    obj_ptr->dirty = FALSE;
2212    obj_ptr->rotation = 0;
2213    obj_ptr->detail.t = text_ptr;
2214    obj_ptr->fattr = obj_ptr->lattr = NULL;
2215    obj_ptr->ctm = NULL;
2216 
2217    RecalcTextMetrics(text_ptr, AbsX, AbsBaselineY);
2218 
2219    SetTextBBox(obj_ptr, textJust, text_ptr->w, text_ptr->h,
2220          text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
2221    AdjObjBBox(obj_ptr);
2222    return obj_ptr;
2223 }
2224 
2225 static
PaintLeftText(Str,Just,LtX,LtY)2226 int PaintLeftText(Str, Just, LtX, LtY)
2227    char *Str;
2228    int Just, LtX, LtY;
2229    /* LtX and LtY are UNSCALED screen offset */
2230 {
2231    register int amount;
2232 
2233    if (zoomScale != 0) {
2234       LtX = ZOOMED_SIZE(LtX);
2235       LtY = ZOOMED_SIZE(LtY);
2236       amount = MyTextWidth(canvasFontPtr, Str, strlen(Str));
2237       BlurText(drawWindow, drawGC, LtX, LtY,
2238             (zoomedIn ? ((amount<<zoomScale)+1) : (amount>>zoomScale)+1),
2239             (zoomedIn ? (textCursorH<<zoomScale)+1 :
2240                         (textCursorH>>zoomScale)+1));
2241       return amount;
2242    }
2243 
2244    LtY += canvasFontAsc;
2245    amount = MyTextWidth(canvasFontPtr, Str, strlen(Str));
2246    MyDrawString(mainDisplay, drawWindow, drawGC, mainDepth, LtX, LtY,
2247             Str, strlen(Str));
2248 
2249    return amount; /* return the length of the painted string */
2250 }
2251 
RepaintFirstStr(ObjPtr,Str)2252 void RepaintFirstStr(ObjPtr, Str)
2253    struct ObjRec *ObjPtr;
2254    char *Str;
2255    /* Replace (graphically) the FIRST string of the text in ObjPtr by Str */
2256 {
2257    struct TextRec *text_ptr=ObjPtr->detail.t;
2258    char *s=GetTextPtrFirstStrSeg(text_ptr)->dyn_str.s, *s1=Str;
2259    char tmp_str[MAXSTRING+1], *c_ptr;
2260    int len;
2261    struct BBRec bbox;
2262    XGCValues values;
2263 
2264    bbox.ltx = ObjPtr->obbox.ltx; bbox.lty = ObjPtr->obbox.lty;
2265    bbox.rbx = ObjPtr->obbox.rbx; bbox.rby = ObjPtr->obbox.rby;
2266 
2267    c_ptr = tmp_str;
2268    for ( ; *s != '\0' && *s1 != '\0' && *s1 == *s; *c_ptr++ = *s++, s1++) ;
2269 
2270    if (*s == *s1) return; /* no updates */
2271    text_ptr->attr->owner->dirty = TRUE;
2272    *c_ptr = '\0';
2273 
2274    PushCurFont();
2275    ObjFontInfoToCurFontInfo(text_ptr);
2276    SetCanvasFont();
2277 
2278    if (*s != '\0') {
2279       values.foreground = GetDrawingBgPixel(INVALID, INVALID);
2280       values.function = GXcopy;
2281       values.fill_style = FillSolid;
2282       XChangeGC(mainDisplay, drawGC,
2283             GCForeground | GCFunction | GCFillStyle, &values);
2284 
2285       len = MyTextWidth(canvasFontPtr, tmp_str, strlen(tmp_str));
2286       XFillRectangle(mainDisplay, drawWindow, drawGC, OFFSET_X(bbox.ltx+len),
2287             OFFSET_Y(bbox.lty),
2288             (zoomedIn ? ((bbox.rbx-bbox.ltx-len)<<zoomScale)+1 :
2289                         ((bbox.rbx-bbox.ltx-len)>>zoomScale)+1),
2290             (zoomedIn ? (textCursorH<<zoomScale)+1 :
2291                         (textCursorH>>zoomScale)+1));
2292 
2293       values.foreground = colorPixels[ObjPtr->color];
2294       XChangeGC(mainDisplay, drawGC, GCForeground, &values);
2295    } else {
2296       values.foreground = colorPixels[ObjPtr->color];
2297       values.function = GXcopy;
2298       values.fill_style = FillSolid;
2299       XChangeGC(mainDisplay, drawGC,
2300             GCForeground | GCFunction | GCFillStyle, &values);
2301    }
2302 
2303    ObjPtr->bbox.rbx = ObjPtr->obbox.rbx = bbox.ltx + PaintLeftText(Str,
2304          textJust, bbox.ltx-drawOrigX, bbox.lty-drawOrigY);
2305 
2306    PopCurFont();
2307 }
2308