/************************************************************/ /* Windows Write, Copyright 1985-1992 Microsoft Corporation */ /************************************************************/ /* disp.c -- MW display routines */ #define NOKEYSTATE #define NOSYSCOMMANDS #define NOSHOWWINDOW //#define NOATOM #define NOCLIPBOARD #define NOGDICAPMASKS #define NOCTLMGR #define NOWINSTYLES //#define NOVIRTUALKEYCODES #define NOSYSMETRICS #define NOMENUS #define NOSOUND #define NOCOMM #define NOOPENFILE #define NOWH #define NOWINOFFSETS #define NOMETAFILE #define NOMB #define NODRAWTEXT #include #define NOUAC #include "mw.h" #include "debug.h" #include "cmddefs.h" #include "dispdefs.h" #include "wwdefs.h" #define NOKCCODES /* Removes all kc code defines */ #include "ch.h" #include "docdefs.h" #include "fmtdefs.h" #include "propdefs.h" #include "macro.h" #include "printdef.h" #include "fontdefs.h" #if defined(OLE) #include "obj.h" #endif #ifdef DBCS #include "dbcs.h" #endif #ifdef CASHMERE /* No VisiMode in WinMemo */ extern int vfVisiMode; #endif /* CASHMERE */ extern int vcchBlted; extern int vidxpInsertCache; extern int vdlIns; extern int vfInsLast; extern struct PAP vpapAbs; extern struct SEP vsepAbs; extern int rgval[]; extern struct DOD (**hpdocdod)[]; extern typeCP cpMacCur; extern int vfSelHidden; extern struct WWD rgwwd[]; extern int wwCur, wwMac; extern struct FLI vfli; extern struct SEL selCur; extern struct WWD *pwwdCur; extern int docCur; extern struct CHP (**vhgchpFormat)[]; extern int vichpFormat; extern typeCP cpMinCur; extern typeCP cpMinDocument; extern int vfInsertOn; extern int vfTextBltValid; extern typeCP vcpFirstParaCache; extern typeCP vcpLimParaCache; extern unsigned vpgn; extern struct SEP vsepAbs; extern CHAR stBuf[]; extern typeCP CpEdge(); extern typeCP CpMacText(); extern int vdocPageCache; extern int vfPictSel; extern int vfAwfulNoise; extern int vfSkipNextBlink; extern int dypMax; extern HDC vhMDC; extern HWND vhWndPageInfo; extern struct FMI vfmiScreen; extern int docScrap; extern long rgbBkgrnd; extern long ropErase; extern BOOL vfMonochrome; extern int dxpbmMDC; extern int dypbmMDC; extern HBITMAP hbmNull; extern int vfOutOfMemory; extern int vfSeeSel; extern int vfInsEnd; /* Is insert point at end-of-line? */ extern int vipgd; extern typeCP vcpMinPageCache; extern typeCP vcpMacPageCache; /* actual position of the cursor line */ extern int vxpCursLine; extern int vypCursLine; extern int vdypCursLine; extern int vfScrollInval; /* means scroll did not take and UpdateWw must be repeated */ extern BOOL vfDead; extern HRGN vhrgnClip; /* G L O B A L S int dlsMac = 0;*/ #ifdef DBCS int donteat = 0; /* propagate not to eat message */ #endif /* D I S P L A Y F L I */ /* Display formatted line in window ww at line dl */ DisplayFli(ww, dl, fDontDisplay) int ww; int dl; int fDontDisplay; /* True if we set up dl info but don't display */ { #ifdef KOREA // jinwoo: 92, 9, 28 /* process Subscript separatedly from descent */ #ifdef NODESC extern int isSubs; #endif #endif typeCP dcp; typeCP dcpMac; struct WWD *pwwd = &rgwwd[ww]; HDC hDC = pwwd->hDC; int xp; /* Current xp to write text */ int yp; /* Current yp to write text */ int xpMin = pwwd->xpMin; /* Minimum xp in window */ int xpMac = pwwd->xpMac; /* Maximum xp in window */ int ypLine; /* Screen yp for current line */ int dxp; /* Width of current run */ int dyp; /* Line height */ int dxpExtra; /* Width of pad for each space */ typeCP cpMin; typeCP cpMac; int xpSel; /* xp of the start of the selection */ int dxpSel = 0; /* Width of the selection. */ CHAR chMark = '\0'; /* style character */ struct CHP *pchp; BOOL fTabsKludge = (vfli.ichLastTab >= 0); BOOL fInsertOn = FALSE; int cBreakRun; /* break characters in run (no relation to Dick or Jane) */ #ifdef SMFONT RECT rcOpaque; #endif /* SMFONT */ #ifdef DDISP CommSzNumNum(" DisplayFli: dl/fDontDisplay ", dl, fDontDisplay); #endif Assert(ww >= 0 && ww < wwMax); #ifdef SMFONT Assert(!fDontDisplay || vfli.fGraphics) #endif /* SMFONT */ Scribble(5,'D'); /* Fill up EDL and set some useful locals */ { register struct EDL *pedl = &(**pwwd->hdndl)[dl]; if (dl == vdlIns) { /* Overwriting chars blted during fast insert; reset blt count */ vcchBlted = 0; vidxpInsertCache = -1; } pedl->xpLeft = vfli.xpLeft; pedl->xpMac = vfli.xpReal; cpMin = pedl->cpMin = vfli.cpMin; pedl->dcpMac = (cpMac = vfli.cpMac) - cpMin; dyp = pedl->dyp = vfli.dypLine; pedl->ichCpMin = vfli.ichCpMin; pedl->dcpDepend = (cpMin == cpMac) ? 0xff : vfli.dcpDepend; pedl->fValid = TRUE; pedl->fGraphics = vfli.fGraphics; pedl->fSplat = vfli.fSplat; /* The position of current line equals the position of the previous line + height of this line. */ #ifdef SMFONT pedl->yp = rcOpaque.bottom = dyp + (ypLine = rcOpaque.top = (dl == 0 ? pwwd->ypMin : (pedl - 1)->yp)); #else /* not SMFONT */ pedl->yp = dyp + (ypLine = (dl == 0 ? pwwd->ypMin : (pedl - 1)->yp)); #endif /* SMFONT */ if (pedl->fIchCpIncr = (vfli.ichCpMac != 0)) { /* Look at final text column */ ++cpMac; /* Since this is true, we can compress pedl->ichCpMac to 1 bit. */ Assert(vfli.ichCpMac == pedl->ichCpMin + 1); } } if (vfli.doc == docNil) { /* This is the space beyond the end mark. */ PatBlt(hDC, 0, ypLine, xpMac, dyp, ropErase); goto Finished; } /* Is there a character in the "style bar"? */ if (cpMin != cpMac) { #ifdef CASHMERE /* This line is not completely empty (not after the end mark); check for painting marks on the style bar. */ if (cpMin == vcpFirstParaCache && vpapAbs.rhc != 0) { /* This is a running-head. */ chMark = chStatRH; } else if ((**hpdocdod)[vfli.doc].hpgtb != 0) #else /* not CASHMERE */ if (vpapAbs.rhc == 0 && (**hpdocdod)[vfli.doc].hpgtb != 0) #endif /* CASHMERE */ { if (vdocPageCache != vfli.doc || cpMac > vcpMacPageCache || cpMac <= vcpMinPageCache) { CachePage(vfli.doc, cpMac - 1); } /* We are now guaranteed that cpMac is within the cached page. */ if (cpMin <= vcpMinPageCache && (!vfli.fGraphics || vfli.ichCpMin == 0)) { /* This is the first line of new page; show page mark. */ chMark = chStatPage; } } } #ifdef SMFONT #ifdef DDISP /* black out this line to test how efficiently/correctly we overwrite pixels from previously-resident lines of text */ PatBlt(hDC, 0, ypLine, xpMac, dyp, BLACKNESS); { long int i; for (i=0; i < 500000; i++) ; } #endif /* Calculate dcpMac now, so we might be able to know how much to erase. */ dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal; /* Erase any character that might be in the style bar. */ dxp = xpSelBar + 1; if (!vfli.fGraphics) { dxp = xpMac; // clear the whole line } PatBlt(hDC, 0, ypLine, dxp, dyp, ropErase); /* If this is graphics then go draw any characters in the style bar. */ if (vfli.fGraphics) { goto DrawMark; } /* If there are no "real" characters on this line then we can skip alot of this. */ if (dcpMac == 0) { goto EndLine2; } #else /* not SMFONT */ if (vfli.fGraphics || fDontDisplay) { /* Erase any character that might be in the style bar. */ PatBlt(hDC, 0, ypLine, xpSelBar, dyp, ropErase); goto DrawMark; } #endif /* SMFONT */ ValidateMemoryDC(); if (vhMDC == NULL) { Error: /* Notify the user that an error has occured and simply erase this line. */ WinFailure(); PatBlt(hDC, xpSelBar, ypLine, xpMac - xpSelBar, dyp, ropErase); goto Finished; } #ifndef SMFONT /* Create a new bitmap for the memory DC if the current bitmap is not big enough. */ if (xpMac > dxpbmMDC || dyp > dypbmMDC) { HBITMAP hbm; /* If there is an old bitmap, then delete it. */ if (dxpbmMDC != 0 || dypbmMDC != 0) { DeleteObject(SelectObject(vhMDC, hbmNull)); } /* Create the new bitmap and select it in. */ if ((hbm = CreateBitmap(dxpbmMDC = xpMac, dypbmMDC = dyp, 1, 1, (LPSTR)NULL)) == NULL) { /* There should be a graceful way to recover if the bitmap is ever NULL (e.g we don't have enough memory for it). */ dxpbmMDC = dypbmMDC = 0; goto Error; } SelectObject(vhMDC, hbm); } /* Erase the are of the bitmap we are going to use. */ PatBlt(vhMDC, xpSelBar, 0, xpMac, dyp, vfMonochrome ? ropErase : WHITENESS); #endif /* not SMFONT */ /* Initialize some of the variables we'll need. */ pchp = &(**vhgchpFormat)[0]; #ifdef SMFONT xp = rcOpaque.left = rcOpaque.right = vfli.xpLeft + xpSelBar - xpMin + 1; #else /* not SMFONT */ dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal; xp = vfli.xpLeft + xpSelBar - xpMin + 1; #endif /* SMFONT */ dxpExtra = fTabsKludge ? 0 : vfli.dxpExtra; #ifdef SMFONT /* If we are horizontally scrolled, then set the clip area to the area outside of the selection bar. */ if (xpMin != 0) { IntersectClipRect(hDC, xpSelBar, rcOpaque.top, xpMac, rcOpaque.bottom); } #endif /* SMFONT */ for (dcp = 0; dcp < dcpMac; pchp++) { /* For all runs do: */ int ichFirst; /* First character in the current run */ int cchRun; /* Number of characters in the current run */ dcp = ichFirst = pchp->ichRun; dcp += pchp->cchRun; if (dcp > dcpMac) { dcp = dcpMac; } cchRun = dcp - ichFirst; /* Compute dxp = sum of width of characters in current run (formerly DxaFromIcpDcp). */ { register int *pdxp; register int cchT = cchRun; PCH pch = vfli.rgch + ichFirst; dxp = cBreakRun = 0; pdxp = &vfli.rgdxp[ichFirst]; while (cchT-- > 0) { dxp += *pdxp++; if (*pch++ == chSpace) ++cBreakRun; } #ifdef DDISP CommSzNum(" dxp=",dxp); #endif } if (dxp > 0) { int cchDone; PCH pch = &vfli.rgch[ichFirst]; #ifdef KOREA //920525 KDLEE; jinwoo: 92, 9, 28 #ifdef NODESC TEXTMETRIC tm; #endif #endif //KOREA LoadFont(vfli.doc, pchp, mdFontScreen); #ifdef KOREA //KDLEE 920525; jinwoo: 92, 9, 28 #ifdef NODESC GetTextMetrics (vhMDC, (LPTEXTMETRIC)&tm); if (tm.tmCharSet==HANGEUL_CHARSET) yp = dyp - (vfli.dypBase/3) -((pchp->hpsPos != 0 ? (pchp->hpsPos < hpsNegMin ? ypSubSuper : -ypSubSuper) : 0)) - vfmiScreen.dypBaseline - (isSubs ? ypSubSuper : 0); else yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos < hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) - vfmiScreen.dypBaseline - (isSubs ? ypSubSuper : 0); #else /* NODESC */ yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos < hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) - vfmiScreen.dypBaseline; #endif /* NODESC */ #else /* KOREA */ yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos < hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) - vfmiScreen.dypBaseline; #endif // KOREA jinwoo: 92, 9, 28 /* Note: tabs and other special characters are guaranteed to come at the start of a run. */ SetTextJustification(vhMDC, dxpExtra * cBreakRun, cBreakRun); #ifdef SMFONT SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun); #endif /* SMFONT */ cchDone = 0; while (cchDone < cchRun) { int cch; /* Does the wide-space zone begin in this run? */ if (vfli.fAdjSpace && (vfli.ichFirstWide < ichFirst + cchRun) && (ichFirst + cchDone <= vfli.ichFirstWide)) { int cchDoneT = cchDone; /* Is this the beginning of the wide-space zone? */ if (ichFirst + cchDone == vfli.ichFirstWide) { /* Reset the width of the spaces. */ SetTextJustification(vhMDC, ++dxpExtra * cBreakRun, cBreakRun); #ifdef SMFONT SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun); #endif /* SMFONT */ cch = cchRun - cchDone; cchDone = cchRun; } else { cchDone = cch = vfli.ichFirstWide - ichFirst; } /* This run is cut short because of a wide space, so we need to calculate a new width. */ { register int *pdxp; register int cchT = cch; PCH pch = &vfli.rgch[ichFirst + cchDoneT]; dxp = 0; pdxp = &vfli.rgdxp[ichFirst + cchDoneT]; while (cchT-- > 0) { dxp += *pdxp++; if (*pch++ == chSpace) ++cBreakRun; } } } else { cchDone = cch = cchRun; } while (cch > 0) { switch (*pch) { CHAR ch; int dxpT; case chTab: #ifdef CASHMERE /* chLeader contains tab leader character (see FormatLine) */ if ((ch = pchp->chLeader) != chSpace) { int cxpTab; CHAR rgch[32]; int dxpLeader = CharWidth(ch); int xpT = xp; int iLevelT = SaveDC(vhMDC); SetBytes(&rgch[0], ch, 32); dxpT = vfli.rgdxp[ichFirst]; cxpTab = ((dxpT + dxpLeader - 1) / dxpLeader + 31) >> 5; xp += dxpT; while (cxpTab-- > 0) { TextOut(vhMDC, xpT, yp, (LPSTR)rgch, 32); xpT += dxpLeader << 5; } RestoreDC(vhMDC, iLevelT); } else #endif /* CASHMERE */ { #ifdef SMFONT /* Expand the opaque rectangle to include the tab. */ rcOpaque.right += vfli.rgdxp[ichFirst]; #endif /* SMFONT */ xp += vfli.rgdxp[ichFirst]; } if (fTabsKludge && ichFirst >= vfli.ichLastTab) { SetTextJustification(vhMDC, (dxpExtra = vfli.dxpExtra) * cBreakRun, cBreakRun); #ifdef SMFONT SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun); #endif /* SMFONT */ fTabsKludge = FALSE; } dxp -= vfli.rgdxp[ichFirst]; pch++; cch--; goto EndLoop; #ifdef CASHMERE case schPage: if (!pchp->fSpecial) { goto EndLoop; } stBuf[0] = CchExpPgn(&stBuf[1], vpgn, vsepAbs.nfcPgn, flmSandMode, ichMaxLine); goto DrawSpecial; case schFootnote: if (!pchp->fSpecial) { goto EndLoop; } stBuf[0] = CchExpFtn(&stBuf[1], cpMin + ichFirst, flmSandMode, ichMaxLine); DrawSpecial: #else /* not CASHMERE */ case schPage: case schFootnote: if (!pchp->fSpecial) { goto EndLoop; } stBuf[0] = *pch == schPage && (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter) ? CchExpPgn(&stBuf[1], vpgn, 0, flmSandMode, ichMaxLine) : CchExpUnknown(&stBuf[1], flmSandMode, ichMaxLine); #endif /* not CASHMERE */ #ifdef SMFONT /* Calculate the opaque rectangle. */ rcOpaque.right += vfli.rgdxp[ichFirst] + vfmiScreen.dxpOverhang; TextOut(hDC, xp, ypLine+yp, &stBuf[1], stBuf[0]); #else /* not SMFONT */ TextOut(vhMDC, xp, yp, (LPSTR)&stBuf[1], stBuf[0]); #endif /* SMFONT */ break; default: goto EndLoop; } dxp -= vfli.rgdxp[ichFirst]; #ifdef SMFONT /* End the line if no more will fit into the window. */ if ((xp += vfli.rgdxp[ichFirst++]) >= xpMac) { goto EndLine; } rcOpaque.left = (rcOpaque.right = xp) + vfmiScreen.dxpOverhang; #else /* not SMFONT */ xp += vfli.rgdxp[ichFirst++]; #endif /* SMFONT */ pch++; cch--; } EndLoop: #ifdef SMFONT if (cch == 0) { Assert(dxp == 0); } else { /* Calculate the opaque rectangle. */ rcOpaque.right += dxp + vfmiScreen.dxpOverhang; #if 0 { char msg[180]; wsprintf(msg,"putting out %d characters\n\r",cch); OutputDebugString(msg); } #endif /* Output cch characters starting at pch */ TextOut(hDC, xp, ypLine+yp, pch, cch); /* End the line if no more will fit into the window. */ if ((xp += dxp) >= xpMac) { goto EndLine; } rcOpaque.left = (rcOpaque.right = xp) + vfmiScreen.dxpOverhang; pch += cch; } #else /* not SMFONT */ /* Output cch characters starting at pch */ TextOut(vhMDC, xp, yp, (LPSTR)pch, cch); xp += dxp; pch += cch; #endif /* SMFONT */ } /* end while (cchDone0) */ } /* end for dcp=0..dcpMac */ #ifdef SMFONT EndLine: /* Restore the clip region if need be. */ if (xpMin != 0) { SelectClipRgn(hDC, NULL); } EndLine2: #endif /* SMFONT */ #ifdef CASHMERE if (vfVisiMode) { AddVisiSpaces(ww, &(**pwwd->hdndl)[dl], vfli.dypBase, vfli.dypAfter + vfli.dypFont); } #endif /* CASHMERE */ vfTextBltValid = FALSE; if ((ww == wwCur) && (pwwd->doc != docScrap) && !vfSelHidden && (selCur.cpLim >= cpMin)) { if (selCur.cpFirst <= cpMac) { /* Show selection */ int xpFirst; int xpLim; #ifdef ENABLE if (vfli.fSplatNext && selCur.cpFirst == selCur.cpLim && selCur.cpFirst == cpMac) { vfInsEnd = TRUE; ClearInsertLine(); } vfInsertOn = FALSE; #endif /* ENABLE */ if (selCur.cpFirst <= cpMin && selCur.cpLim >= cpMac) { xpFirst = vfli.xpLeft; xpLim = vfli.xpReal; } else if (selCur.cpFirst < cpMac || (selCur.cpLim == cpMac && vfInsEnd)) { typeCP cpBegin = CpMax(cpMin, selCur.cpFirst); typeCP cpEnd = CpMin(cpMac, selCur.cpLim); dxp = DxpDiff((int)(cpBegin - cpMin), (int)(cpEnd - cpBegin), &xpFirst); xpLim = min(xpMin + vfli.xpReal, xpFirst + dxp); } else { goto DidntHighlight; } xpSel = xpSelBar + max(xpFirst - xpMin, 0); if (xpLim > xpFirst) { /* Set highlighting at desired screen position. */ dxpSel = max(xpLim - max(xpFirst, xpMin), 0); } else if (selCur.cpFirst == selCur.cpLim && ((selCur.cpLim != cpMac) ^ vfInsEnd)) { vfInsertOn = FALSE; /* Because we redisplayed insert pt line */ #ifdef CASHMERE vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter); vypCursLine = ypLine + dyp - vfli.dypAfter; #else /* not CASHMERE */ vdypCursLine = vfli.dypFont; vypCursLine = ypLine + dyp; #endif /* not CASHMERE */ vxpCursLine = xpSel; /* Start blinking in a while */ vfSkipNextBlink = TRUE; fInsertOn = xpFirst >= xpMin; } DidntHighlight:; } } #ifdef SMFONT /* Invert the selection */ if (dxpSel != 0) { PatBlt(hDC, xpSel, ypLine, dxpSel, dyp, DSTINVERT); } #else /* not SMFONT */ /* Blt the line of text onto the screen. */ PatBlt(vhMDC, 0, 0, xpSelBar, dyp, vfMonochrome ? ropErase : WHITENESS); if (dxpSel == 0) { BitBlt(hDC, 0, ypLine, xpMac, dyp, vhMDC, 0, 0, SRCCOPY); } else { BitBlt(hDC, 0, ypLine, xpSel, dyp, vhMDC, 0, 0, SRCCOPY); BitBlt(hDC, xpSel, ypLine, dxpSel, dyp, vhMDC, xpSel, 0, NOTSRCCOPY); xpSel += dxpSel; BitBlt(hDC, xpSel, ypLine, xpMac - xpSel, dyp, vhMDC, xpSel, 0, SRCCOPY); } #endif /* SMFONT */ /* Draw the insertion bar if necessary. */ if (fInsertOn) { DrawInsertLine(); } DrawMark: /* Draw the character in the style bar if necessary. */ if (chMark != '\0') { #ifdef SYSENDMARK struct CHP chpT; extern struct CHP vchpNormal; blt(&vchpNormal, &chpT, cwCHP); chpT.ftc = ftcSystem; chpT.ftcXtra = 0; chpT.hps = hpsDefault; /* Draw the style character in the standard font. */ LoadFont(vfli.doc, &chpT, mdFontScreen); TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline, (LPSTR)&chMark, 1); #else /* ifdef SYSENDMARK */ /* Draw the style character in the standard font. */ LoadFont(vfli.doc, NULL, mdFontScreen); TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline, (LPSTR)&chMark, 1); #endif /* if-else-def SYSENDMARK */ } if (vfli.fGraphics) { DisplayGraphics(ww, dl, fDontDisplay); } Finished: Scribble(5,' '); } /* D X P D I F F */ DxpDiff(dcpFirst, dcp, pdxpFirst) int dcpFirst; int dcp; int *pdxpFirst; { #if 1 register int *pdxp = &vfli.rgdxp[0]; register int cch; int dxp = vfli.xpLeft; #ifdef ENABLE /* Not used */ int ichLim = dcpFirst + dcp; #endif if (dcp > vfli.ichMac - dcpFirst) { /* This should not be, but is when we have a CR */ //Assert( dcpFirst < vfli.ichMac ); dcp = vfli.ichMac - dcpFirst; } for (cch = 0; cch < dcpFirst; ++cch) { dxp += *pdxp++; } *pdxpFirst = dxp; dxp = 0; for (cch = 0; cch < dcp; ++cch) { dxp += *pdxp++; } return dxp; #else int dxp; if (dcp > vfli.ichMac - dcpFirst) { /* This should not be, but is when we have a CR */ Assert( dcpFirst < vfli.ichMac ); dcp = vfli.ichMac - dcpFirst; } /* first get space up to first character */ *pdxpFirst = LOWORD(GetTextExtent(hDC,vfli.rgch,dcpFirst)) + vfli.xpLeft; /* now get space between first and first+dcp */ dxp = LOWORD(GetTextExtent(hDC,vfli.rgch+dcpFirst,dcp)); return dxp; #endif } UpdateDisplay(fAbortOK) int fAbortOK; { int ww; if (wwMac <= 0) { return; } #ifdef CASHMERE for (ww = 0; ww < wwMac; ww++) if ( rgwwd[ww].doc != docScrap ) { UpdateWw(ww, fAbortOK); if (rgwwd[ww].fDirty || vfOutOfMemory) { return; /* update has been interrupted */ } } #else /* not CASHMERE */ UpdateWw(wwDocument, fAbortOK); if (wwdCurrentDoc.fDirty || vfOutOfMemory) { /* Update has been interrupted */ return; } #endif /* not CASHMERE */ if (wwdCurrentDoc.fRuler) { UpdateRuler(); } } /* U P D A T E W W */ UpdateWw(ww, fAbortOK) int ww, fAbortOK; { /* Redisplay ww as necessary */ extern int vfWholePictInvalid; register struct WWD *pwwd = &rgwwd[ww]; int dlMac; int dlOld, dlNew; int doc; int ichCp; struct EDL *pedlNew; register struct EDL *pedl; struct EDL (**hdndl)[]=pwwd->hdndl; int dypDiff; int ypTop; int ypFirstInval; int dr; int fLastNotShown; typeCP cp, cpMacWw; if (!pwwd->fDirty) { return; } if (!((**hpdocdod)[pwwd->doc].fDisplayable)) return; if (fAbortOK && FImportantMsgPresent()) return; #if 0 // how to get first and last cp's in invalid rect? #if defined(OLE) /* Load visible objects. Do it now rather than in DisplayGraphics() because here it has less chance of disrupting the state variables upon which UpdateWw depends. */ ObjEnumInRange(docCur,cpMinCur,cpMacCur,ObjLoadObjectInDoc); #endif #endif dlMac = pwwd->dlMac; ypTop = pwwd->ypMin; Assert( ww >= 0 && ww < wwMax ); vfli.doc = docNil; /* An aid to Fast Insert */ UpdateInvalid(); /* InvalBand for what Windows considers to be invalid */ ypFirstInval = pwwd->ypFirstInval; #ifndef CASHMERE Assert( ww == wwCur ); /* A MEMO-only assumption */ #endif /* CASHMERE */ Scribble(5, 'U'); ValidateMemoryDC(); /* to do any update, we need a good memory DC */ if (vhMDC == NULL) { WinFailure(); return; } doc = pwwd->doc; vfli.doc = docNil; if (pwwd->fCpBad) { /* cp first displayed has not been blessed */ #ifdef CASHMERE /* Must do this if ww != wwCur assertion is FALSE */ int wwT = wwCur; if (ww != wwCur && wwCur >= 0) /* CtrBackTrs cache is only good for wwCur. Treat != case */ { if (pwwdCur->fDirty) /* Do wwCur first, saving cache */ UpdateWw(wwCur, fAbortOK); if (fAbortOK && FImportantMsgPresent()) return; ChangeWw(ww, false); CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */ ChangeWw(wwT, false); } else #endif /* CASHMERE */ { if (fAbortOK && FImportantMsgPresent()) return; CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */ } } /* check for cpMin accessible in this ww */ RestartUpdate: vfWholePictInvalid = fTrue; /* Tells DisplayGraphics to abandon accumulated partial pict rect */ fLastNotShown = fFalse; cp = CpMax(pwwd->cpMin, pwwd->cpFirst); cpMacWw = pwwd->cpMac; ichCp = pwwd->ichCpFirst; /* Note test for dlNew==0 that guarantees that there will be at least one dl -- this was added for WRITE because we do not have the ability to enforce a minimum window size */ for (dlNew = dlOld = 0; ypTop < pwwd->ypMac || (dlNew == 0) ; dlNew++) /* we have: cp, ichCP: pints to text desired on the coming line dlNew ypTop: desired position for top of dlNew -1 dlOld: next line to be considered for re-use */ /* check for having to extend dndl array */ { if (dlNew >= (int)pwwd->dlMax) { /* extend the array with uninitialized dl's, increment max, break if no space. We assume that dlMac(Old) was <= dlMax, so the dl's will not be looked at but used only to store new lines */ #define ddlIncr 5 if (!FChngSizeH(hdndl, (pwwd->dlMax + ddlIncr) * cwEDL, fFalse)) break; pwwd->dlMax += ddlIncr; } /* discard unusable dl's */ for (; dlOld < dlMac; dlOld++) { /* Set dlOld and pedl to the next good dl */ int ypTopOld, ypOld; /* Re-entrant Heap Movement */ if (fAbortOK && !fLastNotShown && FImportantMsgPresent()) goto RetInval; pedl = &(**hdndl)[dlOld]; ypOld = pedl->yp; /* loop if: invalid, passed over in cp space, passed over in dl space, passed over in yp space, in invalid band, passed over in ich space */ if (!pedl->fValid || dlOld < dlNew || pedl->cpMin < cp || (ypTopOld = (ypOld - pedl->dyp)) < ypTop || (ypOld >= ypFirstInval && ypTopOld <= pwwd->ypLastInval) || (pedl->cpMin == cp && pedl->ichCpMin < ichCp)) continue; /* now we have dlOld, an acceptable if not necessarily useful dl. now compute dlNew either from scratch or by re-using dlOld. To be re-useable, dlOld must have right cp/ichCp pair, plus be totally on screen or, if it is a partial line, it must stay still or move down - not up */ if (pedl->cpMin == cp && pedl->ichCpMin == ichCp && (ypOld <= pwwd->ypMac || ypTopOld <= ypTop)) { /* Re-use this dl */ int yp = ypTop; if (fLastNotShown) { /* HEAP MOVEMENT */ DisplayFli(ww, dlNew - 1, fLastNotShown = fFalse); pedl = &(**hdndl)[dlOld]; } cp = pedl->cpMin + pedl->dcpMac; ichCp = pedl->fIchCpIncr ? pedl->ichCpMin + 1 : 0; ypTop += pedl->dyp; if (dlOld != dlNew || ypTopOld != yp) { DypScroll(ww, dlOld, dlNew - dlOld, yp); if (vfScrollInval) { /* There was a popup; invalid region might have changed */ /* fLastNotShown test is for interrupting picture display */ /* before we've really displayed it */ (**hdndl) [dlOld].fValid = fFalse; goto Restart1; } dlMac += dlNew - dlOld; } dlOld = dlNew + 1; goto NextDlNew; } break; } /* cpMin > cp, the line is not anywhere so it will have to be formatted from scratch */ if (fAbortOK && !fLastNotShown && FImportantMsgPresent()) goto RetInval; FormatLine(doc, cp, ichCp, cpMacWw, flmSandMode); /* Creates vfli */ if (vfOutOfMemory) goto RetInval; ichCp = vfli.ichCpMac; cp = vfli.cpMac; /* advance invalid band so that update can resume after an interruption */ pwwd->ypFirstInval = (ypTop += vfli.dypLine); pedl = &(**hdndl)[dlOld]; if (dlOld < dlMac && pedl->cpMin == cp && pedl->ichCpMin == ichCp) { int dlT = dlOld; /* line at dlOld is a valid, existing line that will abutt the line just about to be displayed. */ if (dlOld == dlNew && pedl->yp - pedl->dyp <= ypTop) /* the line about to be overwritten will be re-used in the next loop. Hence, it is worthwhile to save this line and its dl */ DypScroll(ww, dlOld++, 1, ypTop); else /* Move the next line to its abutting position. We know that it has not yet been overwritten (yp, dlOld all > than ypTop, dlNew) */ DypScroll(ww, dlOld, 0, ypTop); if (vfScrollInval) { /* There was a popup; invalid region might have changed */ /* fLastNotShown test is for interrupting picture display */ /* before we've really displayed it */ (**hdndl) [dlT].fValid = fFalse; Restart1: if (fLastNotShown) { pwwd->ypFirstInval = pwwd->ypMin; } ypFirstInval = pwwd->ypFirstInval; ypTop = pwwd->ypMin; goto RestartUpdate; } } /* true in 3rd param means put off picture redisplay till later */ /* condition: graphics & not last in picture & not last in y space and not in front of a invalid or valid transition in the picture */ DisplayFli(ww, dlNew, fLastNotShown = (vfli.fGraphics && vfli.ichCpMac!=0 && ypTop < pwwd->ypMac)); NextDlNew:; } Break1: pwwd->dlMac = dlNew; #ifdef CASHMERE /* condition is here to avoid swapping */ if (pwwd->fSplit && rgwwd[pwwd->ww].fFtn) CalcFtnLimits(pwwd); #endif /* CASHMERE */ SetCurWwVScrollPos(); /* Set Scroll bar position */ vfTextBltValid = false; /* reset invalid indications */ pwwd->fDirty = false; pwwd->ypFirstInval = ypMaxAll; pwwd->ypLastInval = 0; /* so that max in InvalBand will work */ Scribble(5, ' '); goto Validate; /* Before returning from an interrupt, invalidate lines that were overwritten within the present update. */ RetInval: Scribble(5, ' '); for (; dlOld < dlMac; dlOld++) { pedl = &(**hdndl)[dlOld]; if ((pedl->yp - pedl->dyp) < ypTop) pedl->fValid = fFalse; else break; } Validate: ; #ifdef ENABLE /* We will let UpdateInvalid handle this in case further invalidation occurred during the update */ { /* Tell Windows that the part we updated is valid */ RECT rc; rc.left = 0; rc.top = pwwd->ypMin; rc.right = pwwd->xpMac; rc.bottom = imin( pwwd->ypMac, ypTop ); ValidateRect( pwwd->wwptr, (LPRECT)&rc ); } #endif } /* D Y P S C R O L L */ DypScroll(ww, dlFirst, ddl, ypTo) int ww, dlFirst, ddl, ypTo; { /* Scroll dl's in a window, from dlFirst to end, down ddl lines (or up -ddl). Bitmap is moved from top of dlFirst to ypTo. The yp's of the dl's are updated. Returns the amount scrolled. (positive means down). */ register struct WWD *pwwd = &rgwwd[ww]; int dlMac; int dlT; int ypFrom; int dypChange; int cdlBelow; struct EDL *pedl; struct EDL *pedlT; /* Do not call procedures while dndl is loaded up to avoid heap movement */ struct EDL *dndl = &(**(pwwd->hdndl))[0]; Assert( ww >= 0 && ww < wwMax ); vfScrollInval = fFalse; /* Number of dl's below (and including) the first one to be scrolled */ cdlBelow = pwwd->dlMac - dlFirst; pwwd->dlMac = min(pwwd->dlMac + ddl, pwwd->dlMax); cdlBelow = max(0, min(cdlBelow, pwwd->dlMac - ddl - dlFirst)); pedlT = &dndl[dlFirst]; ypFrom = pedlT->yp - pedlT->dyp; /* Length of area to be moved */ dypChange = ypTo - ypFrom; if (cdlBelow > 0) { int dlTo = dlFirst + ddl; int ypMac = pwwd->ypMac; pedlT = &dndl[dlTo]; if (ddl != 0) { blt(&dndl[dlFirst], pedlT, cwEDL * cdlBelow); } for (dlT = dlTo; dlT < pwwd->dlMac; ++dlT, ++pedlT) { if (dypChange < 0 && pedlT->yp > ypMac) { /* Invalidate dl's that are pulled in from the ozone below ypMac */ pedlT->fValid = fFalse; } else { pedlT->yp += dypChange; } } } if (dypChange != 0) { RECT rc; SetRect( (LPRECT)&rc, 0, min(ypFrom, ypTo), pwwd->xpMac, pwwd->ypMac ); Assert( ww == wwCur ); /* A MEMO-only assumption */ ScrollCurWw( &rc, 0, dypChange ); } return dypChange; } FImportantMsgPresent() { /* If the next message is important enough to interrupt a screen update, we return TRUE; if it can wait, we return FALSE */ BOOL fToggledKey; extern MSG vmsgLast; #ifdef DEBUG unsigned wHeapVal = *(pLocalHeap + 1); Assert( wHeapVal == 0 ); /* Heap should not be frozen */ #endif #ifdef DBCS if( donteat ) return TRUE; #endif while (PeekMessage((LPMSG) &vmsgLast, NULL, NULL, NULL, PM_NOREMOVE)) { if (((vmsgLast.wParam == VK_MENU) || (vmsgLast.wParam == VK_CONTROL))) { if (vmsgLast.wParam == VK_CONTROL) { GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL); SetShiftFlags(); } return TRUE; } /* Filter uninteresting or easily handled events */ else if (fToggledKey = FCheckToggleKeyMessage(&vmsgLast) || (vmsgLast.message == WM_KEYUP && vmsgLast.hwnd == wwdCurrentDoc.wwptr)) { /* This is so the Windows keyboard interface mechanism will see toggle key and key-up transitions */ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL); #ifdef WIN30 /* PeekMessage has been changed in Win 3.0 so that GetKeyState() called from FCheckToggleKeyMessage() is really only valid if you've done a PeekMessage(...,PM_REMOVE) or GetMessage() first. That is, while the FCheckToggleKeyMessage() call might succeed above, it will NOT have set the vfShiftKey/vfCommandKey flags correctly -- so we do it here ..pault */ if (fToggledKey) FCheckToggleKeyMessage(&vmsgLast); #endif if (vmsgLast.hwnd != wwdCurrentDoc.wwptr) { /* Just in case a modeless dialog's window proc cares */ TranslateMessage((LPMSG)&vmsgLast); DispatchMessage((LPMSG)&vmsgLast); } #ifdef DBCS #ifdef KOREA /* 90.12.23 by sangl */ // jinwoo: 92, 9, 28 if (vmsgLast.message == WM_CHAR || vmsgLast.message == WM_KEYDOWN || vmsgLast.message == WM_INTERIM) { #else /* KOREA */ if (vmsgLast.message == WM_CHAR || vmsgLast.message == WM_KEYDOWN ) { #endif //KOREA 920525 KDLEE; jinwoo: 92, 9, 28 donteat = TRUE; return( TRUE ); } /* else Ok, you are KEYUP message. do normal */ #endif } else { switch (vmsgLast.message) { case WM_MOUSEMOVE: /* Process mouse move messages immediately; they are not really important. NOTE: This assumes that we have not captured all mouse events; in which case, they are important. */ DispatchMessage((LPMSG)&vmsgLast); case WM_TIMER: case WM_SYSTIMER: /* Remove timer and mouse move messages from the queue. */ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL); break; default: Assert( *(pLocalHeap+1) == 0 ); /* Heap should still not be frozen */ return (TRUE); } } } Assert( *(pLocalHeap + 1) == 0 ); /* Heap should still not be frozen */ return (FALSE); } /* C P B E G I N L I N E */ typeCP CpBeginLine(pdl, cp) int *pdl; typeCP cp; { /* return the cp and dl containing cp */ int dlMin, dlLim; typeCP cpGuess; struct EDL *dndl; do { UpdateWw(wwCur, false); PutCpInWwVert(cp); /* Ensure cp on screen */ } while (pwwdCur->fDirty && !vfOutOfMemory); dndl = &(**(pwwdCur->hdndl))[0]; dlMin = 0; dlLim = pwwdCur->dlMac; while (dlMin + 1 < dlLim) { /* Binary search the ww */ int dlGuess = (dlMin + dlLim) >> 1; struct EDL *pedl = &dndl[dlGuess]; if ((cpGuess = pedl->cpMin) <= cp && (cpGuess != cp || pedl->ichCpMin == 0)) { /* guess is low or right */ dlMin = dlGuess; if (cp == cpGuess && pedl->cpMin + pedl->dcpMac != cp) break; /* Got it right */ } else /* Guess is high */ dlLim = dlGuess; } *pdl = dlMin; return dndl[dlMin].cpMin; } /* T O G G L E S E L */ ToggleSel(cpFirst, cpLim, fOn) typeCP cpFirst, cpLim; /* selection bounds */ int fOn; { /* Flip selection highlighting on and off */ extern int vfPMS; struct EDL *pedl; int dlT; int xpMin; int dxpRoom; int xpFirst; int xpLim; int fInsertPoint = (cpFirst == cpLim); if (vfSelHidden || cpFirst > cpLim || cpLim < /*cp0*/ cpMinCur || vfDead) return; if ( vfPictSel && vfPMS && (CachePara( docCur, cpFirst ), vpapAbs.fGraphics) && (vcpLimParaCache == cpLim) ) { /* Don't show inversion if we're moving or sizing a picture */ return; } dxpRoom = pwwdCur->xpMac - xpSelBar; xpMin = pwwdCur->xpMin; for (dlT = 0; dlT < pwwdCur->dlMac; dlT++) { typeCP cpMin, cpMac; /* line bounds */ pedl = &(**(pwwdCur->hdndl))[dlT]; if (!pedl->fValid) continue; cpMin = pedl->cpMin; if (cpMin > cpLim || cpMin > cpMacCur || (cpMin == cpLim && cpLim != cpFirst)) break; cpMac = cpMin + pedl->dcpMac; if (cpFirst <= cpMin && cpLim >= cpMac) { /* entire line is highlighted */ xpFirst = pedl->xpLeft; if (pedl->fGraphics && cpLim == cpMac && cpMin == cpMac) /* Special kludge for graphics paras */ xpLim = xpFirst; else xpLim = pedl->xpMac; } else if (fInsertPoint && cpFirst == cpMac && vfInsEnd) { /* Special kludge for an insert point at the end of a line */ xpLim = xpFirst = pedl->xpMac; } else if (cpFirst < cpMac) { /* Bite the bullet */ int dxp; typeCP cpBegin = CpMax(cpMin, cpFirst); typeCP cpEnd = CpMin(cpMac, cpLim); FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode); dxp = DxpDiff((int) (cpBegin - cpMin), (int) (cpEnd - cpBegin), &xpFirst); xpLim = xpFirst + dxp; /* reload pedl because procedures were called */ pedl = &(**(pwwdCur->hdndl))[dlT]; } else continue; /* now we have: pedl valid, xpFirst, xpLast describe highlight */ /* xpFirst = max(xpFirst, xpMin); */ xpLim = min(xpLim, xpMin + pedl->xpMac); if (xpLim > xpFirst) { if (xpLim > xpMin) { RECT rc; rc.top = pedl->yp - pedl->dyp; rc.left = xpSelBar + max(xpFirst - xpMin, 0); rc.bottom = pedl->yp; rc.right = xpSelBar + xpLim - xpMin; InvertRect( wwdCurrentDoc.hDC, (LPRECT)&rc); } } /* ToggleSel modified 7/28/85 -- added explicit check for fInsertPoint, since the xpLim == xpFirst test sometimes succeeded bogusly when a selection was extended backwards. BL */ else if (fInsertPoint && (xpLim == xpFirst)) /* Insertion point */ { /* vfli should usually be cached already, so will be fast. */ int yp = pedl->yp; FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode); if (fOn ^ vfInsertOn) { if (!vfInsertOn) { vxpCursLine = xpSelBar + xpFirst - xpMin; vypCursLine = yp - vfli.dypAfter; vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter); /* Start blinking in a while */ vfSkipNextBlink = TRUE; } DrawInsertLine(); } return; } } } /* T R A S H W W */ TrashWw(ww) { /* Invalidate all dl's in ww */ Assert( ww >= 0 && ww < wwMax ); InvalBand(&rgwwd[ww], 0, ypMaxAll); } /* I N V A L B A N D */ /* invalidate the band ypFirst, ypLast inclusive */ InvalBand(pwwd, ypFirst, ypLast) struct WWD *pwwd; int ypFirst, ypLast; { /* this covers some peculiar rects received from update event after a window resize by 1 pixel. CS */ if (ypLast < 0 || ypFirst == ypLast) return; pwwd->fDirty = true; pwwd->ypFirstInval = min(pwwd->ypFirstInval, ypFirst); pwwd->ypLastInval = max(ypLast, pwwd->ypLastInval); } /* T R A S H A L L W W S */ TrashAllWws() { /* trash them all */ int ww; #ifdef CASHMERE for (ww = 0; ww < wwMac; ++ww) TrashWw(ww); #else TrashWw( wwDocument ); #endif vfli.doc = docNil; /* Mark vfli invalid */ } /* T U R N O F F S E L */ TurnOffSel() { /* Remove sel highlighting from screen */ /* HideSel has no effect */ if (!vfSelHidden) { ToggleSel(selCur.cpFirst, selCur.cpLim, false); vfSelHidden = true; } } /* D R A W I N S E R T L I N E */ DrawInsertLine() { /* Draw (in Xor mode) a vertical bar at screen position v*CursLine */ /* Toggles both the display and the vfInsertOn flag */ /* Adjustments in cursor draw must be reflected in DisplayFli, above */ /* Last-minute correction for a bug: assure that the insert line does not extend above ypMin */ if (!vfInsertOn && vdypCursLine > vypCursLine - wwdCurrentDoc.ypMin) vdypCursLine = vypCursLine - wwdCurrentDoc.ypMin; /* Tell GDI to invert the caret line */ PatBlt( wwdCurrentDoc.hDC, vxpCursLine, vypCursLine - vdypCursLine, 2, vdypCursLine , DSTINVERT ); vfInsertOn = 1 - vfInsertOn; } /* C L E A R I N S E R T L I N E */ ClearInsertLine() { if ( vfInsertOn) DrawInsertLine(); }