unit GCHyper;
 
{$N-}
 
interface
 
{NSRHyper text format:}
 
{'\+xxx ' = start link (xxx = link id) }
{'\-'     = end link }
{'\Fxxx ' = select font xxx}
{'\Sxxx ' = select paragraphs style xxx}
{'\Cxxx ' = select text color xxx}
{'\Bxxx ' = select paragraph background color xxx}
{'\Axxx ' = insert autocharacter (xxx = type id xsize yasc ydesc) [space separated] (if xsize=0 then call callback)}
{'\Oxxx ' = insert frame object: xxx = type id style xoffset xsize ysize}
{           example: /O1 121 WO 0 5 5 }
{'\P'     = page break }
{'\L'     = line break }
{'\H'     = hard space }
 
{Frame styles:}
{ C - Child window. A child window will be created and then properly resized, by calling the callback function}
{ T - Transparent. Ignored if child window. Text goes over or under the frame}
{ W - Wrap around. Text is wrapped around the frame}
{ X - X-expand. The frame is expanded to the right}
{ P - Callback: get object size & offset by calling the callback procedure. This proc may also alter style!}
{ O - Overlaying. Ignored if child window or not transparent. Overlays the text}
{ M - Position is relative to margins; otherwise, it is relative to window/document margins}
{ R - Right aligned (default is left aligned)}
 
uses
  CDEError,CDETypes,CDETools,
  WinProcs,WinTypes,Win31,Strings,
  _CDEHyp,_CDEUsr,CDETask,CDEMem16,
  CDE_Usr;
 
function  NSRHyperCompileText(txt:Pointer;var nct:TNHCompiledText):integer;export;
procedure NSRHyperSetInfo(h:hWnd;p:PNHyperInfo);export;
 
procedure NSRHyperTextInit;export;
procedure NSRHyperTextDone;export;
 
function  NSRHyperHotSpotHandler
  (i:longint;hWindow:hWnd;fnc:integer;var hi:TNHyperInfo):longint;
  export;
 
function  NSRHyperTextHandler
  (p:PChar;hWindow:hWnd;fnc:integer;dc:hDC;s,c,f,x,y:longint;var hi:TNHyperInfo;var li:TNHyperLineInfo):longint;
  export;
 
function  NSRHyperBrushHandler
  (hWindow:hWnd;dc:hDC;s,b:longint;var ir,orr,fr,tr:TRect;var hi:TNHyperInfo):integer;
  export;
 
function  NSRHyperLineHandler
  (hWindow:hWnd;fnc:integer;dc:hDC;s,lt:longint;var i,o,f,t:TRect;var hi:TNHyperInfo):integer;
  export;
 
function  NSRHyperAutoCharHandler
  (p:PNHAutoChar;hWindow:hWnd;fnc:integer;dc:hDC;p1,p2:longint;var tr:TRect;var hi:TNHyperInfo;var l:TNHyperLineInfo):longint;
  export;
 
function  NSRHyperFrameHandler
  (p:PNHFrame;hWindow:hWnd;fnc:integer;dc:hDC;p1,p2:longint;var tr:TRect;var hi:TNHyperInfo):longint;
  export;
 
implementation
 
 
function  NSRHyperHotSpotHandler;
 
  begin
    case fnc of
      hthotspotfnc_GetCursor: NSRHyperHotSpotHandler:=-1;
      hthotspotfnc_GetFont:   NSRHyperHotSpotHandler:=-1;
      hthotspotfnc_GetColor:  NSRHyperHotSpotHandler:=1;
    end
  end;
 
 
function  NSRHyperFrameHandler;
 
  var
    ob:hBrush;
    op:hPen;
    s:array[0..40] of char;
 
  begin
    with p^ do
      case fnc of
        htframefnc_ResizeChild:
          begin
            with tr do
              if hfWindow<>0 then
                MoveWindow(hfWindow,left,top,right-left,bottom-top,true);
          end;
        htframefnc_CreateChild:
          begin
            hfWindow:=CreateWindow(
              'EDIT',
              'Test',
              ws_Child or ws_Visible or ws_Caption or ws_Border,
              0,0,0,0,
              hWindow,
              0,
              hInstance,
              Nil);
          end;
        htframefnc_Paint:
          begin
            ob:=SelectObject(dc,GetStockObject(white_brush));
            op:=SelectObject(dc,GetStockObject(black_pen));
 
            Str(hfIDData,s);
            with hfRect do Rectangle(dc,left+3,top+3,right-3,bottom-3);
            TextOut(dc,hfRect.left,hfRect.top,s,StrLen(s));
 
            SelectObject(dc,ob);
            SelectObject(dc,op);
          end;
        htframefnc_DeleteChild:
          begin
            DestroyWindow(hfWindow);
            hfWindow:=0;
          end;
      end
  end;
 
 
function  NSRHyperTextHandler;
 
  var
    tm:TTextMetric;
    tp:TPoint;
    i:integer;
    b:hBrush;
 
  begin
    case fnc of
      httextfnc_TextOut:
        begin
          with hi.hiFonts^[f] do
            if hfCallbackData=hfcbd_SuperScript then
              begin
                GetTextMetrics(dc,tm);
                y:=li.hliLPTop+tm.tmAscent;
              end;
 
          if li.hliSelected then
            begin
              longint(tp):=GetTextExtent(dc,p,StrLen(p));
 
              with li do
                begin
                  b:=SelectObject(dc,CreateSolidBrush(hi.hiUserInfo[hiuserinfo_TextHandler]));
                  PatBlt(dc,x,hliLPTop,tp.x,hliLPBottom-li.hliLPTop,PatCopy);
                  DeleteObject(SelectObject(dc,b));
                end;
            end;
 
          NSRHyperTextHandler:=longint(TextOut(dc,x,y,p,StrLen(p)));
        end;
      httextfnc_GetCharFromPos:
        begin
          for i:=0 to StrLen(p) do
            begin
              longint(tp):=GetTextExtent(dc,p,i);
              if tp.x>x then Break;
            end;
 
          if i>=StrLen(p) then
            NSRHyperTextHandler:=StrLen(p)-1
          else
            NSRHyperTextHandler:=i-1;
        end;
      httextfnc_GetPosFromChar:
        begin
          if x=0 then
            NSRHyperTextHandler:=0
          else
            begin
              longint(tp):=GetTextExtent(dc,p,x);
              NSRHyperTextHandler:=tp.x;
            end
        end;
      httextfnc_GetTextExtent:
        begin
          NSRHyperTextHandler:=GetTextExtent(dc,p,StrLen(p));
        end;
      httextfnc_GetSpaceExtent:
        begin
          NSRHyperTextHandler:=GetTextExtent(dc,' ',1);
        end;
      httextfnc_GetTextMetrics:
        begin
          NSRHyperTextHandler:=longint(GetTextMetrics(dc,TTextMetric(Pointer(p)^)));
        end;
      httextfnc_SpaceOut,httextfnc_TabFill:
        begin
          if li.hliSelected then
            with li do
              begin
                b:=SelectObject(dc,CreateSolidBrush(hi.hiUserInfo[hiuserinfo_TextHandler]));
                PatBlt(dc,x,hliLPTop,LoWord(longint(p)),hliLPBottom-li.hliLPTop,PatCopy);
                DeleteObject(SelectObject(dc,b));
              end;
        end;
    end;
  end;
 
 
function  NSRHyperBrushHandler;
 
  {when this handler is called; default background brush is already selected}
  {in the dc}
 
  var
    ob:hBrush;
 
  begin
    with orr do
      if (s=-1) then
        begin
          PatBlt(dc,fr.left,fr.top,fr.right-fr.left,fr.bottom-fr.top,PatCopy);
        end
      else
        begin
          PatBlt(dc,fr.left,fr.top,left-fr.left,fr.bottom,PatCopy);
          PatBlt(dc,right,fr.top,fr.right-right,fr.bottom,PatCopy);
 
          if hi.hiBrushes<>Nil then
            ob:=SelectObject(dc,CreateBrushIndirect(PLogBrush(FIncPtr(hi.hiBrushes,WLongMul(b,SizeOf(TLogBrush))))^));
 
          PatBlt(dc,left,top,right-left,bottom-top,PatCopy);
 
          if hi.hiBrushes<>Nil then
            DeleteObject(SelectObject(dc,ob));
        end;
  end;
 
 
function  NSRHyperLineHandler;
 
  var
    op:hPen;
    ys:integer;
 
  begin
    op:=SelectObject(dc,CreatePen(ps_Solid,0,RGB(0,0,0)));
 
    if fnc=htlinefnc_TopLine then
      ys:=(o.top+i.top) div 2
    else
      ys:=(o.bottom+i.bottom) div 2;
 
    MoveTo(dc,i.left,ys);
    LineTo(dc,i.right,ys);
 
    DeleteObject(SelectObject(dc,op));
  end;
 
 
function  NSRHyperAutoCharHandler;
 
  var
    ob:hBrush;
    x,y:integer;
 
  begin
    case fnc of
      htautocharfnc_Paint:
        with p^ do
          begin
            x:=p1;
            y:=p2;
 
            ob:=SelectObject(dc,GetStockObject(black_brush));
            PatBlt(dc,x,y-hacYAsc,hacXSize,hacYAsc,PatCopy);
 
            SelectObject(dc,GetStockObject(white_brush));
            PatBlt(dc,x,y,hacXSize,hacYDsc,PatCopy);
 
            SelectObject(dc,ob);
          end;
    end
  end;
 
 
const
  MaxLineLength               =32767;   {Win32S: correct to MaxLongInt!}
 
  NHFontChar                  =#1;
  NHHiliteChar                =#2;
  NHColorChar                 =#3;
  NHAutoChar                  =#4;
  NHFrameChar                 =#5;
  NHSpaceChar                 =' ';
 
  NHParaChar                  =#10;
  NHNLChar                    =#13;
  NHTabChar                   =#9;
  NHLineBreakChar             =#8;
 
  NHHardSpaceChar             =#7;
 
  NHWordEnd                   =[NHFrameChar,NHParaChar,NHTabChar,NHSpaceChar,NHNLChar,NHLineBreakChar];
  NHLineFractionEnd           =[NHNLChar,NHTabChar,NHLineBreakChar];
 
  dopaint_Paint               =0;
  dopaint_Print               =1;
  dopaint_Calculate           =2;
  dopaint_GetChar             =3;
 
type
  PNHHotSpot                  =^TNHHotSpot;
  TNHHotSpot                  =
    record
      hsIndex                 :longint;   {size fits into 64K!}
    end;
 
  PANHHotSpot                 =^TANHHotSpot;
  TANHHotSpot                 =array[0..0] of TNHHotSpot;
 
  PNHHotRect                  =^TNHHotRect;
  TNHHotRect                  =
    record
      hrIndex                 :longint;
      hrRect                  :TRect;
      hrYPos                  :integer;   {size fits into 64K!}
      hrReserved              :integer;
    end;
 
  PANHHotRect                 =^TANHHotRect;
  TANHHotRect                 =array[0..0] of TNHHotRect;
 
  PNHLineInfo                 =^TNHLineInfo;
  TNHLineInfo                 =
    record
      liLeftPos               :integer;
      liAddPoints             :integer;
      liSpaces                :integer;
      liBottomLine            :integer;
      liTabulator             :integer;   {size fits into 64K!}
      liParagraph             :integer;   {MAXIMUM = 32767 PARAGRAPHS!!!!!!!!}
      liTopLine               :integer;
      liBaseLine              :integer;
    end;
 
  PANHLineInfo                =^TANHLineInfo;
  TANHLineInfo                =array[0..0] of TNHLineInfo;
 
  PNHData                     =^TNHData;
  TNHData                     =
    record
      ndInfo                  :TNHyperInfo;
      ndRects                 :Pointer;
      ndText                  :Pointer;
      ndIndexes               :Pointer;
 
      ndFontTable             :PByte;
      ndParaTable             :PNHParagraph;
      ndColorTable            :PByte;
      ndAutoCharTable         :PNHAutoChar;
      ndFrameTable            :PNHFrame;
 
      ndFontTableSize         :longint;
      ndParaTableSize         :longint;
      ndColorTableSize        :longint;
      ndAutoCharTableSize     :longint;
      ndFrameTableSize        :longint;
 
      ndLineInfo              :Pointer;
      ndLineNum               :longint;
      ndYPos                  :integer;
      ndXPos                  :integer;
      ndYSize                 :integer;
      ndYStep                 :integer;
      ndYEnd                  :integer;
      ndXSize                 :integer;
      ndXStep                 :integer;
      ndXEnd                  :integer;
      ndFreeze                :bool;
 
      ndWidth                 :integer;
 
      ndInSelection           :bool;
      ndSelFirstLine          :longint;
      ndSelLastLine           :longint;
      ndSelFirstPos           :longint;
      ndSelLastPos            :longint;
      ndSelFirstChar          :longint;
      ndSelLastChar           :longint;
      ndSelRect               :TRect;
      ndSelStartPoint         :TPoint;
 
      ndSelPositive           :bool;
      ndSelExtended           :bool;
      ndSelMouseIn            :bool;
 
      ndError                 :integer;
 
      ndVScroll               :bool;        {has scroll}
      ndHScroll               :bool;        {has scroll}
    end;
 
  PNHPaintParam               =^TNHPaintParam;
  TNHPaintParam               =
    record
      nhppCharacter           :longint;
      nhppCharRect            :TSRect;
      nhppCharLine            :longint;
      nhppPoint               :TSPoint;
    end;
 
{========}
 
 
procedure NHCountHiliteFontParaColorCharFrames(p:PChar;var len,hilite,fonts,para,color,achar,frame:longint);
 
  var
    c:longint;
    inslash:bool;
 
  begin
    hilite:=0;
    fonts:=0;
    inslash:=false;
    para:=0;
    color:=0;
    achar:=0;
    frame:=0;
    len:=0;
 
    while p[0]<>#0 do
      begin
        if p[0]='\' then
          inslash:=not inslash
        else
          if (p[0] in ['+','-']) and inslash then
            begin
              Inc(hilite);
              inslash:=false;
            end
          else
            if (p[0] in ['f','F']) and inslash then
              begin
                Inc(fonts);
                inslash:=false;
              end
            else
              if (p[0] in ['c','C']) and inslash then
                begin
                  Inc(color);
                  inslash:=false;
                end
              else
                if (p[0] in ['a','A']) and inslash then
                  begin
                    Inc(achar);
                    inslash:=false
                  end
                else
                  if (p[0] in ['o','O']) and inslash then
                    begin
                      Inc(frame);
                      inslash:=false;
                    end
                  else
                    if (p[0] in ['p','P','b','B','s','S','l','L','\','h','H']) then
                      begin
                        inslash:=false;
                      end
                    else
                      if p[0]=NHParaChar then Inc(para);
 
        p:=FIncPtr1(p);
        Inc(len);
      end;
 
    hilite:=hilite div 2;
  end;
 
 
function  NHCompile(
  p:PChar;
  s:longint;
  var snew:longint;
  spots:PNHHotSpot;
  fonttable,paratable,colortable,achartable,frametable:Pointer;
  paranum:integer):PChar;
 
  function  NHGetFrameStyle(var p:PChar):longint;
 
    var
      result:longint;
 
    begin
      result:=0;
 
      while p[0]=NHSpaceChar do p:=FIncPtr1(p);
      while p[0]<>NHSpaceChar do
        begin
          case p[0] of
            'C','c': result:=BSet(result,hfstyle_ChildWindow      ,true);
            'T','t': result:=BSet(result,hfstyle_Transparent      ,true);
            'W','w': result:=BSet(result,hfstyle_WrapAround       ,true);
            'X','x': result:=BSet(result,hfstyle_XExpand          ,true);
            'O','o': result:=BSet(result,hfstyle_Overlaying       ,true);
            'M','m': result:=BSet(result,hfstyle_RelativeToMargin ,true);
            'P','p': result:=BSet(result,hfstyle_CallbackParameter,true);
            'R','r': result:=BSet(result,hfstyle_RightAligned     ,true);
          end;
 
          p:=FIncPtr1(p);
        end;
 
      NHGetFrameStyle:=result;
    end;
 
  function  NHGetLongint(var p:PChar):longint;
 
    var
      c:integer;
      ch:char;
      res:longint;
      minus:bool;
 
    begin
      while p[0]=NHSpaceChar do p:=FIncPtr1(p);
 
      ch:=p[0];
      res:=0;
 
      while ch in ['0'..'9'] do
        begin
          res:=res*10;
          res:=res+ord(ch)-ord('0');
          p:=FIncPtr1(p);
          ch:=p[0];
        end;
 
      NHGetLongint:=res
    end;
 
  procedure NHAdvance;
 
    begin
      while p[0]<>NHSpaceChar do p:=FIncPtr1(p);
      p:=FIncPtr1(p);
    end;
 
  var
    c2:longint;
    p2,p2org,porg:PChar;
    inslash:bool;
    inhilite:bool;
    curpara:integer;
    b:longint;
    ch:char;
 
  procedure Put(ch:char);
 
    begin
      p2[0]:=ch;
      p2:=FIncPtr1(p2);
      Inc(c2);
    end;
 
  begin
    p2:=NGAlloc(gmem_Moveable,s);
    p2org:=p2;
    porg:=p;
 
    if p2<>Nil then
      begin
        c2:=0;
        inslash:=false;
        inhilite:=false;
        curpara:=0;
 
        PNHParagraph(paratable)^.hpStyle:=0;
        PNHParagraph(paratable)^.hpBkBrush:=0;
        PNHParagraph(paratable)^.hpPageBreak:=false;
 
        repeat
          if inslash then
            begin
              inslash:=false;
              ch:=p[0];
              p:=FIncPtr1(p);
 
              case ch of
                '\':
                  begin
                    Put('\');
                  end;
                'f','F':
                  begin
                    PByte(fonttable)^:=NHGetLongint(p);
                    Put(NHFontChar);
                    fonttable:=FIncPtr1(fonttable);
 
                    NHAdvance;
                  end;
                'c','C':
                  begin
                    PByte(colortable)^:=NHGetLongint(p);
                    Put(NHColorChar);
                    colortable:=FIncPtr1(colortable);
 
                    NHAdvance;
                  end;
                'h','H':
                  begin
                    Put(NHHardSpaceChar);
                    NHAdvance;
                  end;
                'l','L':
                  begin
                    Put(NHLineBreakChar);
                    NHAdvance;
                  end;
                '+','-':
                  if inhilite then
                    begin
                      inhilite:=false;
                      Put(NHHiliteChar);
                    end
                  else
                    begin
                      inhilite:=true;
                      spots^.hsIndex:=NHGetLongint(p);
                      spots:=FIncPtrWord(spots,SizeOf(spots^));
                      Put(NHHiliteChar);
 
                      NHAdvance;
                    end;
                's','S':
                  begin
                    PNHParagraph(paratable)^.hpStyle:=NHGetLongint(p);
                    NHAdvance;
                  end;
                'b','B':
                  begin
                    PNHParagraph(paratable)^.hpBkBrush:=NHGetLongint(p);
                    NHAdvance;
                  end;
                'a','A':
                  begin
                    PNHAutoChar(achartable)^.hacType:=NHGetLongint(p);
                    NHAdvance;
                    PNHAutoChar(achartable)^.hacIDData:=NHGetLongint(p);
                    NHAdvance;
                    PNHAutoChar(achartable)^.hacXSize:=NHGetLongint(p);
                    NHAdvance;
                    PNHAutoChar(achartable)^.hacYAsc:=NHGetLongint(p);
                    NHAdvance;
                    PNHAutoChar(achartable)^.hacYDsc:=NHGetLongint(p);
                    NHAdvance;
 
                    achartable:=FIncPtrWord(achartable,SizeOf(TNHAutoChar));
 
                    Put(NHAutoChar);
                  end;
                'p','P':
                  begin
                    PNHParagraph(paratable)^.hpPageBreak:=true;
                  end;
                'o','O':
                  begin
                    PNHFrame(frametable)^.hfRect.left:=0;
                    PNHFrame(frametable)^.hfRect.top:=0;
                    PNHFrame(frametable)^.hfRect.right:=0;
                    PNHFrame(frametable)^.hfRect.bottom:=0;
                    PNHFrame(frametable)^.hfWindow:=0;
 
                    PNHFrame(frametable)^.hfParagraph:=curpara;
 
                    PNHFrame(frametable)^.hfType:=NHGetLongint(p);
                    NHAdvance;
                    PNHFrame(frametable)^.hfIDData:=NHGetLongint(p);
                    NHAdvance;
                    PNHFrame(frametable)^.hfStyle:=NHGetFrameStyle(p);
                    NHAdvance;
                    PNHFrame(frametable)^.hfOffset:=NHGetFrameStyle(p);
                    NHAdvance;
                    PNHFrame(frametable)^.hfXSize:=NHGetLongint(p);
                    NHAdvance;
                    PNHFrame(frametable)^.hfYSize:=NHGetLongint(p);
                    NHAdvance;
 
                    frametable:=FIncPtr(frametable,SizeOf(TNHFrame));
 
                    Put(NHFrameChar);
                  end;
              end
            end
          else
            begin
              case p[0] of
                '\':
                  begin
                    inslash:=true;
                  end;
                NHNLChar:;
                NHParaChar:
                  begin
                    Put(NHParaChar);
                    paratable:=FIncPtrWord(paratable,SizeOf(TNHParagraph));
 
                    Dec(paranum);
                    Inc(curpara);
                    if paranum>0 then
                      begin
                        PNHParagraph(paratable)^.hpStyle:=0;
                        PNHParagraph(paratable)^.hpBkBrush:=0;
                        PNHParagraph(paratable)^.hpPageBreak:=false;
                      end
                  end
              else
                Put(p[0]);
              end;
 
              p:=FIncPtr1(p);
            end
        until HPtrsDis(porg,p)>=s;
 
        Put(NHSpaceChar);
        Put(#0);
      end
    else
      begin
        NHCompile:=Nil;
        Exit;
      end;
 
    NGReAlloc(Pointer(p2org),c2,gmem_Moveable);
    NHCompile:=p2org;
    snew:=c2;
  end;
 
 
function  NHDeleteHotRect(p:Pointer):Pointer;
 
  begin
    NHDeleteHotRect:=Nil;
    NGFree(p);
  end;
 
 
function  NHCreateHotRect(p:Pointer):Pointer;
 
  begin
    NHDeleteHotRect(p);
    p:=NGAlloc(gmem_Moveable,SizeOf(longint));
    PLongint(p)^:=0;
    NHCreateHotRect:=p;
  end;
 
 
function  NHAddHotRect(p:Pointer;tr:TRect;ndx:longint;var err:bool):Pointer;
 
  var
    ns:longint;
    hnd2:THandle;
 
  begin
    err:=false;
    ns:=(PLongint(p)^+1)*SizeOf(TNHHotRect)+SizeOf(longint);
    GlobalUnlock(HiWord(longint(p)));
    hnd2:=GlobalRealloc(HiWord(longint(p)),ns,gmem_Moveable);
    if hnd2=0 then
      begin
        err:=true;
        p:=GlobalLock(HiWord(longint(p)));
      end
    else
      begin
        p:=GlobalLock(hnd2);
        ns:=PLongint(p)^;
        Inc(PLongint(p)^);
        with PNHHotRect(FIncPtr(p,4+ns*SizeOf(TNHHotRect)))^ do
          begin
            hrRect:=tr;
            hrIndex:=ndx;
          end;
      end;
 
    NHAddHotRect:=p;
  end;
 
 
function  NHFindHotRect(p:Pointer;tp:TPoint):longint;
 
  var
    pr:PNHHotRect;
    num,c:longint;
 
  begin
    if p<>Nil then
      begin
        num:=PLongint(p)^;
        pr:=FIncPtr4(p);
        for c:=0 to num-1 do
          begin
            with pr^ do
              if PtInRect(hrRect,tp) then
                begin
                  NHFindHotRect:=hrIndex;
                  Exit
                end;
 
            pr:=FIncPtrWord(pr,SizeOf(TNHHotRect))
          end
      end;
 
    NHFindHotRect:=-1;
  end;
 
 
procedure NHPrepareText(p:PChar);
 
  begin
    while p[0]<>#0 do
      begin
        if p[0]=NHNLChar then p[0]:=NHSpaceChar;
        p:=FIncPtr1(p);
      end;
  end;
 
 
procedure NHGetAllData(w:hWnd;data:PNHData);
 
  {Get addittional callback data (like frame style P)}
 
  var
    c:longint;
    frametable:PNHFrame;
    autochartable:PNHAutoChar;
    dummy:TRect;
    dummyli:TNHyperLineInfo;
 
  begin
    with data^ do
      begin
        frametable:=ndFrameTable;
        autochartable:=ndAutoCharTable;
 
        for c:=1 to ndAutoCharTableSize do
          begin
            with autochartable^ do
              if hacXSize=0 then
                HTAutoCharHandler(ndInfo.hiAutoCharFnc)(autochartable,w,htautocharfnc_GetSize,0,0,0,dummy,ndInfo,dummyli);
 
            autochartable:=FIncPtrWord(autochartable,SizeOf(autochartable^));
          end;
 
        for c:=1 to ndFrameTableSize do
          begin
            with frametable^ do
              begin
                if BGet(hfStyle,hfstyle_CallbackParameter) then
                  HTFrameHandler(ndInfo.hiFrameFnc)(frametable,w,htframefnc_GetSizeOffset,0,0,0,dummy,ndInfo);
                if BGet(hfStyle,hfstyle_ChildWindow) then
                  HTFrameHandler(ndInfo.hiFrameFnc)(frametable,w,htframefnc_CreateChild,0,0,0,dummy,ndInfo);
              end;
 
            frametable:=FIncPtrWord(frametable,SizeOf(frametable^));
          end;
      end;
  end;
 
 
procedure NHReleaseAllWindows(w:hWnd;data:PNHData);
 
  var
    c:longint;
    frametable:PNHFrame;
    dummy:TRect;
 
  begin
    with data^ do
      begin
        frametable:=ndFrameTable;
 
        for c:=1 to ndFrameTableSize do
          begin
            with frametable^ do
              begin
                if BGet(hfStyle,hfstyle_ChildWindow) then
                  HTFrameHandler(ndInfo.hiFrameFnc)(frametable,w,htframefnc_DeleteChild,0,0,0,dummy,ndInfo);
              end;
 
            frametable:=FIncPtrWord(frametable,SizeOf(frametable^));
          end;
      end;
  end;
 
 
procedure NHInitFonts(data:PNHData);
 
  var
    c:integer;
 
  begin
    with data^.ndInfo do
      for c:=0 to hiNumFonts-1 do
        with hiFonts^[c] do
          hfHandle:=0;
  end;
 
 
procedure NHDoneFonts(data:PNHData);
 
  var
    c:integer;
 
  begin
    with data^.ndInfo do
      for c:=0 to hiNumFonts-1 do
        with hiFonts^[c] do
          begin
            if hfHandle<>0 then DeleteObject(hfHandle);
            hfHandle:=0;
          end
  end;
 
 
procedure NHGetStyle(style_no:integer;var style:TNHStyle;data:PNHData);
 
  begin
    with data^ do
      HUCopy(
        FIncPtrWord(
          ndInfo.hiStyles,
          WLongMul(
            SizeOf(style),
            style_no)),
        @style,
        SizeOf(style));
  end;
 
 
procedure NHCutText(hWindow:hWnd;dc:hDC;width:integer;var ypos,lines,xlen:integer;data:PNHData);
 
  var
    fonttable,oldfonttable:PByte;
    para:longint;
    autochartable,oldautochartable:PNHAutoChar;
    p,oldp,buffer:PChar;
    bufferlen:integer;
    font,oldfont:byte;
    maxysize:integer;
    maxyasc:integer;
    marginleft,marginright,cmarginleft,cmarginright:integer;
    style:TNHStyle;
    indent,tabnumber,newindent,oldindent,tabcount:integer;
    line,lastline:longint;
    frame,advframe:longint;
    wordnumber:integer;
    inframe,rightframe,intab:bool;
    frameto:integer;
    yasc,ydsc,xsize,ya,yd,xs,ys,nextspace:integer;
    tmet:TTextMetric;
    tp:TPoint;
    indexes,oldindexes:PNHHotSpot;
    inhilite,oldinhilite:bool;
    hilitefont,oldhilitefont:integer;
    firstparaline,firstlineline:bool;
    li:TNHyperLineInfo;
 
  procedure NHSelectFont;
 
    var
      f:byte;
 
    begin
      begin
        if inhilite then
          if hilitefont>=0 then
            f:=hilitefont
          else
            f:=font
        else
          f:=font
      end;
 
      with data^ do
        with ndInfo do
          with hiFonts^[f] do
            begin
              if hfHandle=0 then hfHandle:=CreateFontIndirect(hfFont);
              SelectObject(dc,hfHandle);
 
              HTTextHandler(hiTextFnc)(
                PChar(Pointer(@tmet)),
                hWindow,
                httextfnc_GetTextMetrics,
                dc,
                para,
                0,
                font,
                0,
                0,
                ndInfo,
                li);
            end;
    end;
 
  function  NHGetNextWord(var xsize,ysize,yasc,ydsc:integer):bool;
 
    var
      wordstart:PChar;
      partstart:PChar;
      wordend:PChar;
      len:integer;
      tp:TPoint;
      tr:TRect;
      charnum:longint;
 
    begin
      {store everything in case the word does not fit. In such case, we break the line}
      {and try again with the same word and all}
 
      oldfont:=font;
      oldfonttable:=fonttable;
      oldautochartable:=autochartable;
      oldindexes:=indexes;
      oldp:=p;
      oldinhilite:=inhilite;
      oldhilitefont:=hilitefont;
 
      {find start and end of the word}
 
      wordstart:=p;
      while not (p[0] in NHWordEnd) do p:=FIncPtr1(p);
      wordend  :=p;
      p        :=wordstart;
 
      {for now, the yAsc and xAsc are taken from the current font; also, the size of the word}
      {is still zero}
 
      xsize:=0;
      yasc :=tmet.tmAscent;
      ydsc :=tmet.tmDescent;
 
      NHGetNextWord:=false;
 
      with data^ do
        repeat
          partstart:=p;
 
          {part=the characters with the same font&hilite-status&color within the word}
 
          while not ((p[0] in [NHHiliteChar,NHFontChar,NHAutoChar,NHColorChar]) or (longint(p)>=longint(wordend))) do
            p:=FIncPtr1(p);
 
          {the number of characters in the part=}
 
          len:=HPtrsDis(partstart,p);
          if len>=32767 then
            ndError:=nderror_WordTooLong
          else
            if len>0 then
              begin
                {we'll copy the characters in the buffer in case they break the segment limit}
 
                if len>bufferlen then
                  begin
                    if not NGRealloc(Pointer(buffer),len+1,gmem_Moveable) then
                      begin
                        ndError:=nderror_OutOfMem;
                        Exit
                      end;
 
                    bufferlen:=len;
                  end;
 
                HUCopy(partstart,buffer,len);
                PChar(FIncPtrWord(buffer,len))[0]:=#0;
 
                longint(tp):=
                  HTTextHandler(ndInfo.hiTextFnc)
                    (buffer,hWindow,httextfnc_GetTextExtent,dc,para,0,font,0,0,data^.ndInfo,li);
 
                Inc(xsize,tp.x);
 
                {extend the descent & ascent}
 
                if ydsc<tmet.tmDescent then ydsc:=tmet.tmDescent;
                if yasc<tmet.tmAscent  then yasc:=tmet.tmAscent;
              end;
 
          while p[0]=NHFontChar do
            begin
              p:=FIncPtr1(p);
 
              font:=PByte(fonttable)^;
              fonttable:=FIncPtr1(fonttable);
 
              NHSelectFont;
            end;
 
          while p[0]=NHAutoChar do
            begin
              p:=FIncPtr1(p);
 
              with autochartable^ do
                begin
                  Inc(xsize,hacXSize);
                  if yasc<hacYAsc then yasc:=hacYAsc;
                  if ydsc<hacYDsc then ydsc:=hacYDsc;
                end;
 
              autochartable:=FIncPtrWord(autochartable,SizeOf(autochartable^));
            end;
 
          while p[0]=NHHiliteChar do
            begin
              p:=FIncPtr1(p);
 
              if inhilite then
                begin
                  inhilite:=false;
                  indexes:=FIncPtr(indexes,SizeOf(indexes^));
                  NHSelectFont;
                end
              else
                begin
                  inhilite:=true;
                  hilitefont:=
                    HTHotSpotHandler(ndInfo.hiHotSpotFnc)(
                      indexes^.hsIndex,
                      hWindow,
                      hthotspotfnc_GetFont,
                      ndInfo);
                  NHSelectFont
                end;
            end;
 
          while p[0] in [NHColorChar] do p:=FIncPtr1(p);
        until longint(p)>=longint(wordend);
 
      ysize:=yasc+ydsc;
      p:=wordend;
 
      NHGetNextWord:=true;
    end;
 
  procedure NHReturnState;
 
    begin
      {restore old fonts etc}
 
      font:=oldfont;
      fonttable:=oldfonttable;
      autochartable:=oldautochartable;
      p:=oldp;
      inhilite:=oldinhilite;
      hilitefont:=oldhilitefont;
      indexes:=oldindexes;
 
      NHSelectFont;
    end;
 
  function  NFrame(i:longint):PNHFrame;
 
    begin
      NFrame:=FIncPtr(data^.ndFrameTable,i*SizeOf(TNHFrame))
    end;
 
  function  NLineInfo(i:longint):PNHLineInfo;
 
    begin
      NLineInfo:=FIncPtr(data^.ndLineInfo,i*SizeOf(TNHLineInfo))
    end;
 
  function  NPara(i:longint):PNHParagraph;
 
    begin
      NPara:=FIncPtr(data^.ndParaTable,i*SizeOf(TNHParagraph))
    end;
 
  {tukaj naprej se komentiraj!}
 
  procedure NHAddFrame;
 
    procedure NAlignFrame;
 
      var
        style:TNHStyle;
        marginright,marginleft:integer;
 
      begin
        with NFrame(frame)^ do
          with hfRect do
            begin
              top:=ypos;
 
              NHGetStyle(NPara(hfParagraph)^.hpStyle,style,data);
 
              with style do
                begin
                  marginleft:=hsLeftSpace;
                  marginright:=width-hsRightSpace;
                end;
 
              if BGet(hfStyle,hfStyle_RightAligned) then
                begin
                  if BGet(hfStyle,hfStyle_RelativeToMargin) then
                    right:=marginright-hfOffset
                  else
                    right:=width-hfOffset;
 
                  if BGet(hfStyle,hfStyle_XExpand) then
                    if BGet(hfStyle,hfStyle_RelativeToMargin) then
                      left:=marginleft
                    else
                      left:=0
                  else
                    left:=right-hfXSize;
 
                  rightframe:=true;
                end
              else
                begin
                  if BGet(hfStyle,hfStyle_RelativeToMargin) then
                    left:=marginleft+hfOffset
                  else
                    left:=hfOffset;
 
                  if BGet(hfStyle,hfStyle_XExpand) then
                    if BGet(hfStyle,hfStyle_RelativeToMargin) then
                      right:=marginright
                    else
                      right:=width
                  else
                    right:=left+hfXSize;
 
                  rightframe:=false;
                end;
 
              bottom:=top+hfYSize;
              frameto:=bottom;
            end
      end;
 
    begin
      with NFrame(frame)^ do
        begin
          if BGet(hfStyle,hfstyle_Transparent) and (not BGet(hfStyle,hfstyle_ChildWindow)) then
            begin
              NAlignFrame;
              inframe:=true;
            end
          else
            begin
              NAlignFrame;
              if BGet(hfStyle,hfstyle_XExpand) or (not BGet(hfStyle,hfstyle_WrapAround)) then
                begin
                  ypos:=frameto;
                  inframe:=false;
                end
              else
                begin
                  inframe:=true;
 
                  if BGet(hfStyle,hfstyle_RightAligned) then
                    begin
                      if cmarginright>hfRect.left then cmarginright:=hfRect.left
                    end
                  else
                    begin
                      if cmarginleft<hfRect.right then cmarginleft:=hfRect.right;
                    end
                end;
            end
        end;
 
      Inc(frame);
    end;
 
  procedure NHCheckEndOfFrame;
 
    {repairs ypos to fit remaining frames on the 'stack'}
 
    begin
      if inframe then
        if ypos>=frameto then
          begin
            {only if the current paragraph 'swallowed' the current frame we can state}
            {that the frame has been 'put'}
            inframe:=false;
 
            {in that case, margins return to normal}
            cmarginleft:=marginleft;
            cmarginright:=marginright;
          end;
 
      {we have some frames in advance and we have already 'put' current frame; so let's}
      {advance to the next frame}
 
      while (advframe>0) and (not inframe) do
        begin
          NHAddFrame;
          Dec(advframe);
        end;
    end;
 
  procedure NHFeedLine(eol,eopara:bool);
 
    var
      c:longint;
      baseline,bottomline:longint;
 
    {add new line of text to the buffer.}
 
    begin
      with data^ do
        if not NGRealloc(ndLineInfo,(line+1)*SizeOf(TNHLineInfo),gmem_Moveable) then
          ndError:=nderror_OutOfMem
        else
          begin
            with NLineInfo(line)^ do
              begin
                {LeftPos=margin + indent}
                liLeftPos           :=cmarginleft+indent;
                {number of spaces in the line is the same as wordnumber - 1}
                liSpaces            :=wordnumber-1;
                liTopLine           :=ypos;
                liBaseLine          :=ypos+yasc;
                liBottomLine        :=ydsc;
                liAddPoints         :=0;
                liTabulator         :=tabnumber;
                {the paragraph of the line}
                liParagraph         :=para;
 
                {if the tabulating was caused by auto indent, mark it with - sign}
                if not intab then liTabulator:=-liTabulator;
              end;
 
            {do we have the new line (against: only a fraction of a line separated by a tabulator)}
            if eol then
              begin
                {increase the number of lines (meaning <real lines> of text, not NLineInfo lines}
                Inc(lines);
 
                {do the formatting of the line}
                with NLineInfo(line)^ do
                  case style.hsParaFormat of
                    hsparaformat_Right:
                      begin
                        liLeftPos   :=cmarginright-xsize;  {xsize=length of this line!}
                      end;
                    hsparaformat_Center:
                      begin
                        liLeftPos   :=(liLeftPos+cmarginright-xsize) div 2;
                      end;
                    hsparaformat_Justify:
                      begin
                        {we dont' justify the last line in the paragraph}
                        if not eopara then liAddPoints :=cmarginright-liLeftPos-xsize;
                      end;
                    hsparaformat_Continuous:
                      begin
                        if xlen<(xsize+liLeftPos) then xlen:=xsize+liLeftPos;
                      end;
                  end;
 
                {intab=false, so we'll be able to mark liTabulator with - sign if no AutoIndent}
                intab:=false;
 
                if not BGet(style.hsParaStyle,hsparastyle_AutoIndent) then
                  begin
                    {if no autoindent, reset tabulators and indent}
                    tabnumber:=0;
                  end;
 
                {if there is no autoindent [otherwise, keep offset]}
                {reset offset to +0 for next lines!}
                if (tabnumber=0) then
                  if style.hsFirstIndent<0 then
                    {if firstindent is negative, all other lines are moved to the right,}
                    {not the first one to the left}
                    indent:=abs(style.hsFirstIndent)
                  else
                    indent:=0;
 
                {lastline=the first fraction of this line. Because now we have all info for the}
                {whole real line, we can set the baselines to all fractions!}
                if lastline<=line then
                  begin
                    baseline:=0;
                    bottomline:=0;
 
                    {find the lowest baseline and bottomline}
                    for c:=lastline to line do
                      with NLineInfo(c)^ do
                        begin
                          if baseline<liBaseLine then baseline:=liBaseLine;
                          if bottomline<liBottomLine then bottomline:=liBottomLine;
                        end;
 
                    bottomline:=baseline+bottomline;  {it was not bottomline indeed; it was ydsc!!!}
                    ypos:=bottomline;                 {new, corrected ypos}
 
                    for c:=lastline to line do
                      with NLineInfo(c)^ do
                        begin
                          liBaseLine:=baseline;       {all fractions within same line have the same baseline!!!}
                          liBottomLine:=bottomline;
                        end;
                  end;
 
                lastline:=line+1;                     {the NEXT line is the FIRST line of the next set!!!}
 
                Inc(ypos,style.hsLineSpace);          {increase yposition for line space of the paragraph!}
                {check if the frame has already been 'swallowed'};
                NHCheckEndOfFrame;
              end;
 
            yasc:=0;
            ydsc:=0;
            xsize:=0;
            wordnumber:=0;
            nextspace:=0;
 
            Inc(line);
          end;
    end;
 
  function  NHNextParagraphBreak:bool;
 
    {is the next paragraph meant to be kept with current one?}
 
    var
      style:TNHStyle;
 
    begin
      with data^ do
        {not if it's the last paragraph}
        if para>=(ndParaTableSize-1) then
          NHNextParagraphBreak:=true
        else
          with NPara(para+1)^ do
            {not if there's a page break}
            if hpPageBreak then
              NHNextParagraphBreak:=true
            else
              begin
                {not if the next paragraph's style doesn't allow it!}
                NHGetStyle(hpStyle,style,data);
                NHNextParagraphBreak:=not BGet(style.hsParaStyle,hsparastyle_LinkToPrevious);
              end;
    end;
 
  procedure NHCloseParagraph;
 
    var
      c:longint;
 
    begin
      with NPara(para)^ do
        begin
          {place all frames on the 'stack'}
          NHCheckEndOfFrame;
 
          {if the paragraph is not kept with the next one, we have to 'put' all frames from the 'stack'}
          if NHNextParagraphBreak then
            begin
              if inframe then
                begin
                  ypos:=frameto;
                  inframe:=false;
                end;
 
              while advframe>0 do
                begin
                  NHAddFrame;
                  ypos:=frameto;
                  inframe:=false;
                  Dec(advframe);
                end
            end;
 
          Inc(ypos,style.hsBottomSpace);
 
          {place all frames on the 'stack'; remember: because of the bottom paragraph spacing,}
          {the paragraph might have 'swallowed' the frame, so we're testing again}
          NHCheckEndOfFrame;
 
          hpEndPosition:=ypos;
          tabnumber:=0;
        end;
    end;
 
  function NHNewParagraph:bool;
 
    begin
      if para=data^.ndParaTableSize then
        begin
          NHNewParagraph:=false;
          {no more paragraphs}
          Exit;
        end;
 
      NHNewParagraph:=true;
 
      with NPara(para)^ do
        begin
          NHGetStyle(hpStyle,style,data);
 
          {paragraph start position will be the same as current yposition}
          hpPosition:=ypos;
          {+ topspace}
          Inc(ypos,style.hsTopSpace);
 
          {place all frames on the 'stack'}
          NHCheckEndOfFrame;
 
          with style do
            begin
              if hsFirstIndent>0 then
                indent:=hsFirstIndent
              else
                indent:=0;
 
              {set original margins}
              marginleft:=hsLeftSpace;
              marginright:=width-hsRightSpace;
 
              {however, if the frame hasn't been 'put' yet, there is less space for text, so}
              {we keep c(urrent)margins on the frame's side of the paper}
              if inframe then
                if rightframe then
                  begin
                    cmarginleft:=marginleft;
                    if marginright<cmarginright then cmarginright:=marginright;
                  end
                else
                  begin
                    cmarginright:=marginright;
                    if marginleft>cmarginleft then cmarginleft:=marginleft;
                  end
              else
                begin
                  {there is no frame, so current margins are same as paragraph (style) margins}
                  cmarginleft:=marginleft;
                  cmarginright:=marginright;
                end;
 
              {tabposition is zero}
              tabnumber:=0;
            end;
        end
    end;
 
  begin
    with data^ do
      with ndInfo do
        begin
          ndError:=nderror_Ok;
 
          if ndLineInfo<>Nil then NGFree(ndLineInfo);
          ndLineInfo:=NGAlloc(gmem_Moveable,0);
          if ndLineInfo=Nil then
            begin
              ndError:=nderror_OutOfMem;
              Exit;
            end;
 
          NHInitFonts(data);
 
          buffer:=NGAlloc(gmem_Moveable,1);
          bufferlen:=0;
 
          fonttable:=ndFontTable;
          oldfonttable:=Nil;
          autochartable:=ndAutoCharTable;
          oldautochartable:=Nil;
          indexes:=ndIndexes;
          oldindexes:=Nil;
          p:=ndText;
          oldp:=Nil;
 
          hilitefont:=0;
          oldhilitefont:=0;
          inhilite:=false;
          oldinhilite:=false;
          font:=0;
          oldfont:=0;
 
          lines:=0;
          xlen:=0;
 
          NHSelectFont;
 
          advframe:=0;  {!!!!}
          frame:=0;
          para:=0;
 
          indent:=0;
          tabnumber:=0;
          line:=0;
          lastline:=0;
          wordnumber:=0;
 
          xsize:=0;
          ypos:=0;
          yasc:=0;
          ydsc:=0;
          nextspace:=0;
 
          inframe:=false;
 
          NHNewParagraph;
 
          repeat
            case p[0] of
              NHParaChar:
                begin
                  {feed line and make it a real line, end of paragraph}
                  NHFeedLine(true,true);
                  NHCloseParagraph;
                  Inc(para);
                  if not NHNewParagraph then Break;
                  if ndError<>nderror_Ok then Break;
                  p:=FIncPtr1(p);
                  Continue;
                end;
              NHFrameChar:
                begin
                  if (wordnumber=0) and (not inframe) and (advframe=0) then
                    begin
                      advframe:=0;
                      NHAddFrame;
                    end
                  else
                    Inc(advframe);
                  p:=FIncPtr1(p);
                end;
              NHLineBreakChar:
                begin
                  NHFeedLine(true,false);
                  if ndError<>nderror_Ok then Break;
                  p:=FIncPtr1(p);
                  Continue;
                end;
              NHTabChar:
                begin
                  intab:=true;
                  newindent:=indent;
                  oldindent:=indent+xsize;
 
                  NHFeedLine(false,false);
 
                  if ndError<>nderror_Ok then Break;
 
                  with style do
                    while tabnumber<hsNumTabs do
                      begin
                        newindent:=hsTabs[tabnumber].htPosition;
                        Inc(tabnumber);
                        if newindent>=oldindent then Break;
                      end;
                  indent:=newindent;
 
                  p:=FIncPtr1(p);
                  Continue;
                end;
              NHSpaceChar:
                begin
                  p:=FIncPtr1(p);
                  Continue;
                end;
            end;
 
            if not NHGetNextWord(xs,ys,ya,yd) then Break;
 
            if
              (nextspace=0)                                          or
              ((cmarginleft+indent+xsize+nextspace+xs)<cmarginright) or
              (BGet(style.hsParaFormat,hsparaformat_Continuous))
            then
              begin
                if ya>yasc then yasc:=ya;
                if yd>ydsc then ydsc:=yd;
 
                Inc(wordnumber);
                Inc(xsize,nextspace);
                Inc(xsize,xs);
 
                longint(tp):=
                  HTTextHandler(data^.ndInfo.hiTextFnc)
                    (Nil,hWindow,httextfnc_GetSpaceExtent,dc,para,0,font,0,0,data^.ndInfo,li);
 
                if tp.x=0 then tp.x:=1;
                nextspace:=tp.x;
              end
            else
              begin
                NHReturnState;
                NHFeedLine(true,false);
                p:=FDecPtr1(p);
                if p[0]=NHSpaceChar then p[0]:=NHNLChar;
                p:=FIncPtr1(p);
              end;
          until false;
 
          SelectObject(dc,GetStockObject(System_Font));
          NGFree(Pointer(buffer));
 
          NHDoneFonts(data);
        end;
  end;
 
 
procedure NHPaintText(hWindow:hWnd;dc:hDC;var tr:TRect;data:PNHData;doPaint:integer;var prm:TNHPaintParam);
 
  var
    fonttable:PByte;
    para:longint;
    colortable:PByte;
    autochartable:PNHAutoChar;
    p,buffer:PChar;
    bufferlen:integer;
    font:byte;
    line:PNHLineInfo;
    linenum:longint;
    nextspace:integer;
    currentword:integer;
    color:byte;
    inhilite:bool;
    inhilitefont:integer;
    inhilitecolor:integer;
    xpos:integer;
    hotrect:TRect;
    indexes:PNHHotSpot;
    err:bool;
    li:TNHyperLineInfo;
    charnum:longint;
    lchar,lline,llpos,lrpos:longint;{last possible char/line/left,right for GetCharacter; if clicked out of line}
 
  procedure NHSelectColor;
 
    var
      c:byte;
 
    begin
      {we only change color when painting. Isn't it so?}
      if doPaint in [dopaint_Paint,dopaint_Print] then
        begin
          if inhilite then
            if inhilitecolor>=0 then
              c:=inhilitecolor
            else
              c:=color
          else
            c:=color;
 
          with data^.ndInfo do
            SetTextColor(dc,hiColors^[c]);
        end
    end;
 
  procedure NHSelectFont;
 
    var
      f:byte;
 
    begin
      {we change font always: for calculating & for painting}
      if inhilite then
        if inhilitefont>=0 then
          f:=inhilitefont
        else
          f:=font
      else
        f:=font;
 
      with data^.ndInfo.hiFonts^[f] do
        begin
          if hfHandle=0 then hfHandle:=CreateFontIndirect(hfFont);
          SelectObject(dc,hfHandle);
        end;
    end;
 
  function  NHGetSpaceSize:integer;
 
    {returns the size of the next space (justified!)}
 
    begin
      with line^ do
        if (liAddPoints>0) and (liSpaces>0) and (nextspace<>0) then
          begin
            NHGetSpaceSize:=
              nextspace                                       +
              QuadMulDiv(liAddPoints,currentword+1,liSpaces)  -
              QuadMulDiv(liAddPoints,currentword,liSpaces);
          end
        else
          NHGetSpaceSize:=nextspace;
    end;
 
  function  NHCheckInSelection:bool;
 
    {fills the lineinfo structure with selection start and selection end parameters.}
    {it also sets hliSelected to true if the line is selected.}
 
    begin
      with li,data^ do
        begin
          hliSelected:=false;
          hliSelStart:=0;
          hliSelEnd:=MaxLineLength;
 
          if ndInSelection then
            if (linenum>=ndSelFirstLine) and (linenum<=ndSelLastLine) then
              begin
                hliSelected:=true;
 
                if linenum=ndSelFirstLine then hliSelStart:=ndSelFirstPos;
                if linenum=ndSelLastLine  then hliSelEnd:=ndSelLastPos;
              end;
        end;
    end;
 
  function  NHPaintNextWord:bool;
 
    {paints or calculates the next word}
 
    var
      wordstart:PChar;
      partstart:PChar;
      wordend:PChar;
      len:integer;
      tp:TPoint;
      tr:TRect;
      olddc:integer;
      rgn:hRgn;
      charnum:longint;
 
    begin
      wordstart:=p;
      while not (p[0] in NHWordEnd) do p:=FIncPtr1(p);
      wordend  :=p;
      p        :=wordstart;
 
      NHPaintNextWord:=false;
 
      with data^ do
        repeat
          partstart:=p;
          while not ((p[0] in [NHHiliteChar,NHFontChar,NHAutoChar,NHColorChar]) or (longint(p)>=longint(wordend))) do
            p:=FIncPtr1(p);
 
          len:=HPtrsDis(partstart,p);
          if len>=32767 then
            ndError:=nderror_WordTooLong
          else
            if len>0 then
              begin
                if len>bufferlen then
                  begin
                    if not NGRealloc(Pointer(buffer),len+1,gmem_Moveable) then
                      begin
                        ndError:=nderror_OutOfMem;
                        Exit
                      end;
 
                    bufferlen:=len;
                  end;
 
                HUCopy(partstart,buffer,len);
                PChar(FIncPtrWord(buffer,len))[0]:=#0;
 
                {get the index of the character}
                charnum:=HPtrsDis(ndText,partstart);
 
                longint(tp):=
                  HTTextHandler(ndInfo.hiTextFnc)
                    (buffer,hWindow,httextfnc_GetTextExtent,dc,line^.liParagraph,0,font,0,0,data^.ndInfo,li);
 
{Paint}         if dopaint in [dopaint_Paint,dopaint_Print] then
                  with li do
                    begin
                      hliLPLeft:=line^.liLeftPos;
                      hliLPTop:=line^.liTopLine;
                      hliLPBottom:=line^.liBottomLine;
 
                      olddc:=0;
 
                      NHCheckInSelection;
 
                      if hliSelected then
                        if (hliSelStart<=(xpos+tp.x)) and (hliSelEnd>=xpos) then
                          begin
                            hliSelected:=true;
 
                            olddc:=SaveDC(dc);
                            ExcludeClipRect(dc,xpos,line^.liTopline,hliSelStart,line^.liBottomLine);
                            ExcludeClipRect(dc,hliSelEnd,line^.liTopline,xpos+tp.x,line^.liBottomLine);
 
                            HTTextHandler(ndInfo.hiTextFnc)(
                              buffer,
                              hWindow,
                              httextfnc_TextOut,
                              dc,
                              line^.liParagraph,
                              color,
                              font,
                              xpos,
                              line^.liBaseline,
                              data^.ndInfo,
                              li);
 
                            RestoreDC(dc,olddc);
                            olddc:=SaveDC(dc);
 
                            ExcludeClipRect(dc,hliSelStart,line^.liTopline,hliSelEnd,line^.liBottomLine);
 
                            hliSelected:=false
                          end
                        else
                          hliSelected:=(hliSelStart<=xpos) and (hliSelEnd>=(xpos+tp.x));
 
                      HTTextHandler(ndInfo.hiTextFnc)(
                        buffer,
                        hWindow,
                        httextfnc_TextOut,
                        dc,
                        line^.liParagraph,
                        color,
                        font,
                        xpos,
                        line^.liBaseline,
                        data^.ndInfo,
                        li);
 
                      if olddc<>0 then RestoreDC(dc,olddc);
                    end
{Calculate}       else if dopaint in [dopaint_Calculate] then
                    begin
                      {calculating the selection}
 
                      if ndInSelection then
                        begin
                          if (ndSelFirstChar<charnum) and (ndSelFirstPos=-1) then
                            begin
                              {safety: if the SelFirstChar is a formatting character}
 
                              ndSelFirstLine:=linenum;
                              ndSelFirstPos:=xpos;
                            end
                          else if (ndSelFirstChar>=charnum) and (ndSelFirstChar<(charnum+len)) then
                            begin
                              {otherwise, if the selcharacter is within the word, calculate the positions}
 
                              ndSelFirstLine:=linenum;
                              ndSelFirstPos:=xpos+HTTextHandler(ndInfo.hiTextFnc)(
                                buffer,
                                hWindow,
                                httextfnc_GetPosFromChar,
                                dc,
                                para,
                                0,
                                font,
                                ndSelFirstChar-charnum,
                                0,
                                data^.ndInfo,
                                li);
                            end;
 
                          if (ndSelLastChar<charnum) and (ndSelLastPos=-1) then
                            begin
                              {safety: if the SelFirstChar is a formatting character}
 
                              ndSelLastLine:=linenum;
                              ndSelLastPos:=xpos;
                            end
                          else if (ndSelLastChar>=charnum) and (ndSelLastChar<(charnum+len)) then
                            begin
                              {otherwise, if the selcharacter is within the word, calculate the positions}
 
                              ndSelLastLine:=linenum;
                              ndSelLastPos:=xpos+HTTextHandler(ndInfo.hiTextFnc)(
                                buffer,
                                hWindow,
                                httextfnc_GetPosFromChar,
                                dc,
                                para,
                                0,
                                font,
                                ndSelLastChar-charnum+1,   {+1: selection is UP TO the next character}
                                0,
                                data^.ndInfo,
                                li);
                            end;
                        end;
 
                      {calculating hotspots}
 
                      if inhilite then
                        begin
                          SetRect(tr,xpos,line^.liTopLine,xpos+tp.x,line^.liBottomLine);
                          UnionRect(hotrect,hotrect,tr);
                        end;
                    end
{GetChar}         else if dopaint in [dopaint_GetChar] then
                    with prm do
                      begin
                        if (nhppPoint.x<xpos) and (nhppCharacter=-1) then
                          begin
                            nhppCharacter:=charnum; {safety:}
                            nhppCharLine:=linenum;
                            nhppCharRect.left:=xpos;
                            nhppCharRect.right:=xpos+HTTextHandler(ndInfo.hiTextFnc)(
                              buffer,
                              hWindow,
                              httextfnc_GetPosFromChar,
                              dc,
                              para,
                              0,
                              font,
                              1,   {end of the first character}
                              0,
                              data^.ndInfo,
                              li);
                          end
                        else if (nhppPoint.x>=xpos) and (nhppPoint.x<(xpos+tp.x)) then
                          begin
                            nhppCharLine:=linenum;
                            nhppCharacter:=HTTextHandler(ndInfo.hiTextFnc)(
                              buffer,
                              hWindow,
                              httextfnc_GetCharFromPos,
                              dc,
                              line^.liParagraph,
                              0,
                              font,
                              nhppPoint.x-xpos,
                              0,
                              data^.ndInfo,
                              li);
                            nhppCharRect.left:=xpos+HTTextHandler(ndInfo.hiTextFnc)(
                              buffer,
                              hWindow,
                              httextfnc_GetPosFromChar,
                              dc,
                              para,
                              0,
                              font,
                              nhppCharacter,
                              0,
                              data^.ndInfo,
                              li);
                            nhppCharRect.right:=xpos+HTTextHandler(ndInfo.hiTextFnc)(
                              buffer,
                              hWindow,
                              httextfnc_GetPosFromChar,
                              dc,
                              para,
                              0,
                              font,
                              nhppCharacter+1,
                              0,
                              data^.ndInfo,
                              li);
 
                            nhppCharacter:=nhppCharacter+charnum
                          end
                    end;
 
                Inc(xpos,tp.x);
              end;
 
          while p[0]=NHFontChar do
            begin
              p:=FIncPtr1(p);
 
              font:=PByte(fonttable)^;
              fonttable:=FIncPtr1(fonttable);
 
              NHSelectFont;
            end;
 
          while p[0]=NHAutoChar do
            begin
              {get the index of the character}
              charnum:=HPtrsDis(ndText,p);
 
              p:=FIncPtr1(p);
 
{Paint}       if dopaint in [dopaint_Paint,dopaint_Print] then
                begin
                  with li do
                    begin
                      hliLPLeft:=line^.liLeftPos;
                      hliLPTop:=line^.liTopLine;
                      hliLPBottom:=line^.liBottomLine;
 
                      NHCheckInSelection;
                      with li do
                        if hliSelected then
                          hliSelected:=(hliSelStart<=xpos) and (hliSelEnd>=(xpos+autochartable^.hacXSize));
                    end;
 
                  HTAutoCharHandler(ndInfo.hiAutoCharFnc)(
                    autochartable,
                    hWindow,
                    htautocharfnc_Paint,
                    dc,
                    xpos,
                    line^.liBaseline,
                    tr,
                    ndInfo,
                    li);
                end
{Calculate}   else if dopaint in [dopaint_Calculate] then
                begin
                  if ndInSelection then
                    begin
                      if (ndSelFirstChar<charnum) and (ndSelFirstPos=-1) then
                        begin
                          {safety: formatting characters}
 
                          ndSelFirstLine:=linenum;
                          ndSelFirstPos:=xpos;
                        end
                      else if (ndSelFirstChar=charnum) then
                        begin
                          ndSelFirstLine:=linenum;
                          ndSelFirstPos:=xpos;
                        end;
 
                      if (ndSelLastChar<charnum) and (ndSelFirstPos=-1) then
                        begin
                          {safety: formatting characters}
 
                          ndSelLastLine:=linenum;
                          ndSelLastPos:=xpos
                        end
                      else if (ndSelLastChar=charnum) then
                        begin
                          ndSelLastLine:=linenum;
                          ndSelLastPos:=xpos+autochartable^.hacXSize;
                        end;
                    end;
                end
              else if dopaint in [dopaint_GetChar] then
                with prm do
                  begin
                    if (nhppPoint.x<xpos) and (nhppCharacter=-1) then
                      begin
                        nhppCharLine:=linenum;
                        nhppCharacter:=charnum;   {safety}
                        nhppCharRect.left:=xpos;
                        nhppCharRect.right:=xpos+autochartable^.hacXSize;
                      end
                    else if (prm.nhppPoint.x>=xpos) and (prm.nhppPoint.x<(xpos+autochartable^.hacXSize)) then
                      begin
                        nhppCharLine:=linenum;
                        nhppCharacter:=charnum;   {safety}
                        nhppCharRect.left:=xpos;
                        nhppCharRect.right:=xpos+autochartable^.hacXSize;
                      end
                  end;
 
              Inc(xpos,autochartable^.hacXSize);
              autochartable:=FIncPtrWord(autochartable,SizeOf(autochartable^));
            end;
 
          while p[0] in [NHColorChar] do
            begin
              p:=FIncPtr1(p);
 
              color:=colortable^;
              colortable:=FIncPtr1(colortable);
              NHSelectColor;
            end;
 
          while p[0] in [NHHiliteChar] do
            begin
              p:=FIncPtr1(p);
 
              if inhilite then
                begin
                  inhilite:=false;
                  NHSelectColor;
                  NHSelectFont;
 
                  if dopaint in [dopaint_Calculate] then ndRects:=NHAddHotRect(ndRects,hotrect,indexes^.hsIndex,err);
 
                  indexes:=FIncPtr(indexes,SizeOf(indexes^));
                end
              else
                begin
                  inhilite:=true;
                  inhilitefont:=HTHotSpotHandler(ndInfo.hiHotSpotFnc)(indexes^.hsIndex,hWindow,hthotspotfnc_GetFont,ndInfo);
                  inhilitecolor:=HTHotSpotHandler(ndInfo.hiHotSpotFnc)(indexes^.hsIndex,hWindow,hthotspotfnc_GetColor,ndInfo);
                  NHSelectFont;
                  NHSelectColor;
 
                  if dopaint in [dopaint_Calculate] then SetRect(hotrect,32767,32767,-32767,-32767);
                end;
            end;
 
        until longint(p)>=longint(wordend);
 
      p:=wordend;
 
      NHPaintNextWord:=true;
    end;
 
  function NHFeedLine(charnum:longint):bool;
 
    begin
      with data^ do
        with line^,li do
          begin
            if liTabulator<0 then xpos:=0;
            {indented tabulator: 0 - liLeftPos}
 
            if liTabulator<>0 then
{Paint}       if dopaint in [dopaint_Print,dopaint_Paint] then
                begin
                  li.hliLPLeft:=line^.liLeftPos;
                  li.hliLPTop:=line^.liTopLine;
                  li.hliLPBottom:=line^.liBottomLine;
 
                  NHCheckInSelection;
                  if hliSelected then hliSelected:=(hliSelStart<=xpos) and (hliSelEnd>=liLeftPos);
 
                  HTTextHandler(ndInfo.hiTextFnc)(
                    Pointer(MakeLong(liLeftPos-xpos,liTabulator)),
                    hWindow,
                    httextfnc_TabFill,
                    dc,
                    line^.liParagraph,
                    color,
                    font,
                    xpos,
                    line^.liBaseline,
                    data^.ndInfo,
                    li);
                end
{Calculate}   else if dopaint in [dopaint_Calculate] then
                begin
                  if
                    ((ndSelFirstChar<charnum) and (ndSelFirstPos=-1)) or
                    (ndSelFirstChar=charnum)
                  then
                    begin
                      {safety}
 
                      ndSelFirstLine:=linenum;
                      ndSelFirstPos:=xpos;
                    end;
 
                  if (ndSelLastChar<charnum) and (ndSelFirstPos=-1) then
                    begin
                      {safety}
 
                      ndSelLastLine:=linenum;
                      ndSelLastPos:=xpos;
                    end
                  else if (ndSelLastChar=charnum) then
                    begin
                      ndSelLastLine:=linenum;
                      ndSelLastPos:=liLeftPos
                    end
                end
{GetChar}     else if dopaint in [dopaint_GetChar] then
                with prm do
                  begin
                    if (nhppPoint.x<xpos) and (nhppCharacter=-1) then
                      begin
                        nhppCharLine:=linenum;
                        nhppCharacter:=charnum;   {safety}
                        nhppCharRect.left:=xpos;
                        nhppCharRect.right:=liLeftPos;
                      end
                    else if (prm.nhppPoint.x>=xpos) and (prm.nhppPoint.x<liLeftPos) then
                      begin
                        nhppCharLine:=linenum;
                        nhppCharacter:=charnum;
                        nhppCharRect.left:=xpos;
                        nhppCharRect.right:=liLeftPos;
                      end
                  end;
 
            xpos:=liLeftPos;
            currentword:=0;
            nextspace:=0;
 
            NHFeedLine:=(liTopLine<tr.bottom) or (not (dopaint in [dopaint_Print,dopaint_Paint]));
          end;
    end;
 
  label
    Out;
 
  begin
    with data^ do
      with ndInfo do
        begin
{Calc}    if dopaint in [dopaint_Calculate] then
            begin
              ndRects:=NHCreateHotRect(ndRects);
 
              ndSelFirstPos:=-1;
              ndSelLastPos:=-1;
            end
{GetChr}  else if dopaint in [dopaint_GetChar] then
            with prm do
              begin
                nhppCharacter:=-1;
              end;
 
          inhilite:=false;
          xpos:=0;
 
          indexes:=ndIndexes;
 
          para:=0;
 
          NHInitFonts(data);
 
          ndError:=nderror_Ok;
 
          buffer:=NGAlloc(gmem_Moveable,1);
          bufferlen:=0;
 
          fonttable:=ndFontTable;
          colortable:=ndColorTable;
          autochartable:=ndAutoCharTable;
          p:=ndText;
 
          line:=ndLineInfo;
          linenum:=0;
 
          font :=0;
          color:=0;
 
          {first, we find the first displayed line!}
 
          if dopaint in [dopaint_Paint,dopaint_Print,dopaint_GetChar] then
            repeat
              if dopaint in [dopaint_Paint,dopaint_Print] then
                begin
{Paint}           if line^.liBottomLine>=tr.top then Break
                end
{GetChar}     else
                with prm do
                  if (nhppPoint.y<=line^.liBottomLine) then
                    begin
                      nhppCharRect.top:=line^.liTopLine;
                      nhppCharRect.bottom:=line^.liBottomLine;
 
                      if nhppPoint.y<line^.liTopLine then goto Out;
 
                      Break;
                    end;
 
              repeat
                case p[0] of
                  NHParaChar:
                    begin
                      Inc(para);
                      line:=FIncPtr(line,SizeOf(line^));
                      Inc(linenum);
                      p:=FIncPtr1(p);
                      Break;
                    end;
                  NHLineBreakChar:
                    begin
                      line:=FIncPtr(line,SizeOf(line^));
                      Inc(linenum);
                      p:=FIncPtr1(p);
                      Break;
                    end;
                  NHNLChar:
                    begin
                      line:=FIncPtr(line,SizeOf(line^));
                      Inc(linenum);
                      p:=FIncPtr1(p);
                      Break;
                    end;
                  NHTabChar:
                    begin
                      line:=FIncPtr(line,SizeOf(line^));
                      Inc(linenum);
                    end;
                  NHFontChar:
                    begin
                      font:=fonttable^;
                      fonttable:=FIncPtr(fonttable,SizeOf(fonttable^));
                    end;
                  NHColorChar:
                    begin
                      color:=colortable^;
                      colortable:=FIncPtr(colortable,SizeOf(colortable^));
                    end;
                  NHHiliteChar:
                    begin
                      inhilite:=not inhilite;
                      if inhilite=false then
                        indexes:=FIncPtr(indexes,SizeOf(indexes^))
                      else
                        begin
                          inhilitefont:=HTHotSpotHandler(ndInfo.hiHotSpotFnc)
                            (indexes^.hsIndex,hWindow,hthotspotfnc_GetFont,ndInfo);
 
                          inhilitecolor:=HTHotSpotHandler(ndInfo.hiHotSpotFnc)
                            (indexes^.hsIndex,hWindow,hthotspotfnc_GetColor,ndInfo);
                        end
                    end;
                  NHAutoChar:
                    begin
                      autochartable:=FIncPtr(autochartable,SizeOf(autochartable^));
                    end;
                end;
 
                p:=FIncPtr1(p);
              until false;
            until para=ndParaTableSize;
 
          {now, we paint it!}
 
          if para<ndParaTableSize then
            begin
              charnum:=HPtrsDis(ndText,p);
 
              NHSelectFont;
              NHSelectColor;
              NHFeedLine(charnum);
 
              SetBkMode(dc,Transparent);
              SetTextAlign(dc,ta_Left or ta_BaseLine);
 
              repeat
                case p[0] of
                  NHParaChar:
                    begin
                      llpos:=xpos;
                      lrpos:=xpos;
                      lchar:=HPtrsDis(ndText,p);
                      lline:=linenum;               {in case: if clicked right of the end of the line}
 
                      if (dopaint in [dopaint_Calculate]) and inhilite then
                        begin
                          ndRects:=NHAddHotRect(ndRects,hotrect,indexes^.hsIndex,err);
                          SetRect(hotrect,32767,32767,-32767,-32767);
                        end;
 
                      Inc(para);
                      if para=ndParaTableSize then Break;
 
                      line:=FIncPtr(line,SizeOf(line^));
                      Inc(linenum);
                      if not NHFeedLine(lchar) then Break;
 
                      p:=FIncPtr1(p);
 
                      Continue;
                    end;
                  NHTabChar,NHNLChar,NHLineBreakChar:
                    begin
                      llpos:=xpos;
                      lrpos:=xpos;
                      lchar:=HPtrsDis(ndText,p);
                      lline:=linenum;               {in case: if clicked right of the end of the line}
 
                      if (dopaint in [dopaint_Calculate]) and inhilite then
                        begin
                          ndRects:=NHAddHotRect(ndRects,hotrect,indexes^.hsIndex,err);
                          SetRect(hotrect,32767,32767,-32767,-32767);
                        end;
 
                      line:=FIncPtr(line,SizeOf(line^));
                      Inc(linenum);
                      if not NHFeedLine(lchar) then Break;
 
                      p:=FIncPtr1(p);
 
                      Continue;
                    end;
                  NHFrameChar:
                    begin
                      p:=FIncPtr1(p);
                      Continue;
                    end;
                  NHSpaceChar:
                    begin
                      charnum:=HPtrsDis(ndText,p);  {last space}
 
                      p:=FIncPtr1(p);
                      Continue;
                    end;
                end;
 
                nextspace:=NHGetSpaceSize;          {nextspace correction}
                if nextspace>0 then
{Paint}           if dopaint in [dopaint_Paint,dopaint_Print] then
                    begin
                      li.hliLPLeft:=line^.liLeftPos;
                      li.hliLPTop:=line^.liTopLine;
                      li.hliLPBottom:=line^.liBottomLine;
 
                      NHCheckInSelection;
                      with li do
                        if hliSelected then hliSelected:=(hliSelStart<=xpos) and (hliSelEnd>=(xpos+nextspace));
 
                      HTTextHandler(data^.ndInfo.hiTextFnc)(
                        Pointer(MakeLong(nextspace,0)),
                        hWindow,
                        httextfnc_SpaceOut,
                        dc,
                        line^.liParagraph,
                        color,
                        font,
                        xpos,
                        line^.liBaseline,
                        data^.ndInfo,
                        li);
                    end
{Calculate}       else if dopaint in [dopaint_Calculate] then
                    begin
                      if
                        ((ndSelFirstChar<charnum) and (ndSelFirstPos=-1)) or
                        (ndSelFirstChar=charnum)
                      then
                        begin
                          {safety}
 
                          ndSelFirstLine:=linenum;
                          ndSelFirstPos:=xpos;
                        end;
 
                      if (ndSelLastChar<charnum) and (ndSelFirstPos=-1) then
                        begin
                          {safety}
 
                          ndSelLastLine:=linenum;
                          ndSelLastPos:=xpos;
                        end
                      else if (ndSelLastChar=charnum) then
                        begin
                          ndSelLastLine:=linenum;
                          ndSelLastPos:=xpos+nextspace
                        end
                    end
{GetChar}         else if dopaint in [dopaint_GetChar] then
                    with prm do
                      begin
                        if (nhppPoint.x<xpos) and (nhppCharacter=-1) then
                          begin
                            nhppCharLine:=linenum;
                            nhppCharacter:=charnum;   {safety}
                            nhppCharRect.left:=xpos;
                            nhppCharRect.right:=xpos+nextspace;
                          end
                        else if (nhppPoint.x>=xpos) and (nhppPoint.x<(xpos+nextspace)) then
                          begin
                            nhppCharLine:=linenum;
                            nhppCharacter:=charnum;
                            nhppCharRect.left:=xpos;
                            nhppCharRect.right:=xpos+nextspace;
                          end
                      end;
 
                xpos:=xpos+nextspace;
 
                if not NHPaintNextWord then Break;
 
                nextspace:=
                  HTTextHandler(data^.ndInfo.hiTextFnc)(
                    Nil,
                    hWindow,
                    httextfnc_GetSpaceExtent,
                    dc,
                    line^.liParagraph,
                    0,
                    font,
                    0,
                    0,
                    data^.ndInfo,
                    li);
 
                Inc(currentword);
 
                if dopaint in [dopaint_GetChar] then
                  begin
                    if prm.nhppCharacter<>-1 then
                      Break
                    else if prm.nhppPoint.y<line^.liTopLine then
                      with prm do
                        begin
                          nhppCharacter:=lchar;
                          nhppCharLine:=lline;
                          nhppCharRect.left:=llpos;
                          nhppCharRect.right:=lrpos;
 
                          Break
                        end
                  end;
              until false;
            end;
 
        Out:
          if dopaint in [dopaint_Calculate] then
            begin
              {have we calculated the positions correctly?}
              if (ndSelFirstPos=-1) or (ndSelLastPos=-1) then ndInSelection:=false;
            end;
        end;
 
    SelectObject(dc,GetStockObject(System_Font));
    NGFree(Pointer(buffer));
    NHDoneFonts(data);
  end;
 
 
procedure NHPaint(hWindow:hWnd;dc:hDC;var ps:TPaintStruct;data:PNHData);
 
  var
    ob,b:hBrush;
    c:longint;
    tr:TRect;
    paratable:PNHParagraph;
    frametable:PNHFrame;
    para:longint;
    style:TNHStyle;
    irect,orect,frame,fr,cr:TRect;
    mdc,olddc:hDC;
    oldbitmap:hBitmap;
    xoff,yoff:integer;
    prm:TNHPaintParam;
 
  begin
    with data^ do
      begin
        GetClientRect(hWindow,cr);
 
        b:=CreateSolidBrush(ndInfo.hiBgrndColor);
        tr:=ps.rcPaint;
 
        olddc:=dc;
        mdc:=CreateCompatibleDCRect(dc,ps.rcPaint,oldbitmap);
        if mdc<>0 then
          begin
            dc:=mdc;
 
            xoff:=-tr.left;
            yoff:=-tr.top;
          end
        else
          begin
            xoff:=0;
            yoff:=0;
          end;
 
        ExtSetViewportOrg(olddc,0,-ndYPos);
        DPToLP(olddc,tr,2);
        ExtSetViewportOrg(dc,xoff,yoff-ndYPos);
 
        paratable:=ndParaTable;
        for para:=0 to ndParaTableSize-1 do
          begin
            with paratable^ do
              if (hpPosition<=tr.bottom) and (hpEndPosition>=tr.top) then
                begin
                  UnrealizeObject(b);
                  ob:=SelectObject(dc,b);
                  NHGetStyle(hpStyle,style,data);
 
                  frame.left:=-ndXPos;
                  frame.right:=ndWidth;
                  frame.top:=hpPosition;
                  frame.bottom:=hpEndPosition;
 
                  orect:=frame;
                  if style.hsParaFormat<>hsparaformat_Continuous then
                    orect.right:=orect.left+ndWidth;
                  Inc(orect.left,ndInfo.hiLeftSpace);
                  if style.hsParaFormat<>hsparaformat_Continuous then
                    Dec(orect.right,ndInfo.hiRightSpace);
 
                  irect:=orect;
                  Inc(irect.left,style.hsLeftSpace);
                  Inc(irect.top,style.hsTopSpace);
                  Dec(irect.bottom,style.hsBottomSpace);
                  if style.hsParaFormat<>hsparaformat_Continuous then
                    Dec(irect.right,style.hsRightSpace);
 
                  HTBrushHandler(ndInfo.hiBrushFnc)(
                    hWindow,
                    dc,
                    para,
                    hpBkBrush,
                    irect,
                    orect,
                    frame,
                    tr,
                    ndInfo);
 
                  SelectObject(dc,ob);
 
                  if BGet(style.hsParaStyle,hsparastyle_TopLine) then
                    HTLineHandler(ndInfo.hiLineFnc)(
                      hWindow,
                      htlinefnc_TopLine,
                      dc,
                      para,
                      style.hsTopLine,
                      irect,
                      orect,
                      frame,
                      tr,
                      ndInfo);
 
                  if BGet(style.hsParaStyle,hsparastyle_BottomLine) then
                    HTLineHandler(ndInfo.hiLineFnc)(
                      hWindow,
                      htlinefnc_BottomLine,
                      dc,
                      para,
                      style.hsBottomLine,
                      irect,
                      orect,
                      frame,
                      tr,
                      ndInfo);
                end;
 
            paratable:=FIncPtr(paratable,SizeOf(paratable^));
          end;
 
        if ndYSize<tr.Bottom then
          begin
            UnrealizeObject(b);
            ob:=SelectObject(dc,b);
 
            DPToLP(olddc,cr,2);
 
            frame.left:=-ndXPos;
            frame.right:=ndWidth;
            frame.top:=ndYSize;
            frame.bottom:=cr.bottom;
 
            HTBrushHandler(ndInfo.hiBrushFnc)(
              hWindow,
              dc,
              -1,
              -1,
              frame,
              frame,
              frame,
              tr,
              ndInfo);
 
            SelectObject(dc,ob);
          end;
 
        tr:=ps.rcPaint;
        ExtSetViewportOrg(olddc,-ndXPos+ndInfo.hiLeftSpace,-ndYPos);
        DPToLP(olddc,tr,2);
        ExtSetViewportOrg(dc,xoff-ndXPos+ndInfo.hiLeftSpace,yoff-ndYPos);
 
        frametable:=ndFrameTable;
        for c:=0 to ndFrameTableSize-1 do
          begin
            with frametable^ do
              if not BGet(hfStyle,hfstyle_ChildWindow) then
                if not BGet(hfStyle,hfstyle_Overlaying) then
                  begin
                    HTFrameHandler(ndInfo.hiFrameFnc)(
                      frametable,
                      hWindow,
                      htframefnc_Paint,
                      dc,
                      0,
                      0,
                      tr,
                      ndInfo);
                  end;
 
            frametable:=FIncPtr(frametable,SizeOf(frametable^));
          end;
 
        NHPaintText(hWindow,dc,tr,data,dopaint_Paint,prm);
 
        frametable:=ndFrameTable;
        for c:=0 to ndFrameTableSize-1 do
          begin
            with frametable^ do
              if not BGet(hfStyle,hfstyle_ChildWindow) then
                if BGet(hfStyle,hfstyle_Overlaying) then
                  begin
                    HTFrameHandler(ndInfo.hiFrameFnc)(
                      frametable,
                      hWindow,
                      htframefnc_Paint,
                      dc,
                      0,
                      0,
                      tr,
                      ndInfo);
                  end;
 
            frametable:=FIncPtr(frametable,SizeOf(frametable^));
          end;
 
        DeleteObject(b);
 
        if mdc<>0 then
          begin
            SetViewportOrg(mdc,0,0);
            SetViewportOrg(olddc,0,0);
 
            with ps.rcPaint do
              BitBlt(olddc,left,top,right-left,bottom-top,mdc,0,0,SrcCopy);
 
            DeleteObject(SelectObject(mdc,oldbitmap));
            DeleteDC(mdc);
          end;
      end;
  end;
 
 
function  NHCreateSelRegion(data:PNHData;sfline,sfpos,slline,slpos:longint;wid:longint):hRgn;
 
  var
    rgn1,rgn2:hRgn;
    line:PNHLineInfo;
    top1,bottom1,top2,bottom2,base1,base2:longint;
 
  begin
    with data^ do
      begin
        line:=FIncPtr(ndLineInfo,sfline*SizeOf(line^));
 
        if sfline=slline then
          begin
            rgn1:=CreateRectRgn(sfpos,line^.liTopLine,slpos,line^.liBottomLine)
          end
        else
          begin
            top1:=line^.liTopLine;
            bottom1:=line^.liBottomLine;
            base1:=line^.liBaseLine;
 
            line:=FIncPtr(ndLineInfo,slline*SizeOf(line^));
 
            top2:=line^.liTopLine;
            bottom2:=line^.liBottomLine;
            base2:=line^.liBaseLine;
 
            if (base2=base1) then       {fractions of the same text line}
              rgn1:=CreateRectRgn(sfpos,top1,slpos,bottom2)
            else
              begin
                rgn1:=CreateRectRgn(sfpos,top1,wid,bottom1);
                rgn2:=CreateRectRgn(0,bottom1,wid,top2);
 
                CombineRgn(rgn1,rgn1,rgn2,rgn_Or);
 
                SetRectRgn(rgn2,0,top2,slpos,bottom2);
 
                CombineRgn(rgn1,rgn1,rgn2,rgn_Or);
 
                DeleteObject(rgn2);
              end
          end;
      end;
 
    NHCreateSelRegion:=rgn1;
  end;
 
 
function  NHUpdateSelection(data:PNHData;sfline,sfpos,slline,slpos:longint;wid:longint;insel:bool):hRGN;
 
  var
    rgn1,rgn2:hRgn;
 
  begin
    rgn1:=0;
    with data^ do
      if ndInSelection then
        begin
          rgn1:=NHCreateSelRegion(
            data,
            ndSelFirstLine,
            ndSelFirstPos,
            ndSelLastLine,
            ndSelLastPos,
            wid);
 
          if insel then
            begin
              rgn2:=NHCreateSelRegion(
                data,
                sfline,
                sfpos,
                slline,
                slpos,
                wid);
 
              CombineRgn(rgn1,rgn1,rgn2,rgn_XOr);
              DeleteObject(rgn2);
            end;
 
          OffsetRgn(rgn1,-ndXPos+ndInfo.hiLeftSpace,-ndYPos);
        end
      else
        if insel then
          begin
            rgn1:=NHCreateSelRegion(
              data,
              sfline,
              sfpos,
              slline,
              slpos,
              wid);
 
            OffsetRgn(rgn1,-ndXPos+ndInfo.hiLeftSpace,-ndYPos);
          end;
 
    NHUpdateSelection:=rgn1;
  end;
 
 
function  NHyperWindowProc(hWindow:hWnd;msg:word;wParam:word;lParam:longint):longint;export;
 
  var
    result:longint;
    p:PNHData;
    b:hBrush;
    ps:TPaintStruct;
    dc:hDC;
    tr:TRect;
    fonts,hilite:longint;
    oldpos:integer;
    crsr:bool;
    index:longint;
    tp:TPoint;
    nct:TNHCompiledText;
    dummy:TRect;
    is:bool;
    hotcursor:longint;
 
    prr:PANHHotRect;
 
    rgn:hRgn;
 
  function DoIt:bool;
 
    begin
      DoIt:=
        (p<>Nil)                        and
        (p^.ndInfo.hiFonts<>Nil)        and
        (p^.ndInfo.hiColors<>Nil)       and
        (p^.ndInfo.hiStyles<>Nil)       and
        (p^.ndText<>Nil)                and
        (p^.ndParaTable<>Nil)           and
        (p^.ndError=nderror_Ok)
    end;
 
  function  GetCharacter(tp:TPoint;var lne:longint;var tr:TSRect):longint;
 
    var
      dummy:TRect;
      dc:hDC;
      prm:TNHPaintParam;
 
    begin
      dc:=GetDC(0);
 
      with prm do
        begin
          nhppPoint.x:=tp.x;
          nhppPoint.y:=tp.y;
        end;
 
      NHPaintText(
        hWindow,
        dc,
        dummy,
        p,
        dopaint_GetChar,
        prm);
 
      ReleaseDC(0,dc);
 
      lne :=prm.nhppCharLine;
      tr  :=prm.nhppCharRect;
 
      GetCharacter:=prm.nhppCharacter;
    end;
 
  procedure CutText(w,h:integer);
 
    var
      dc:hDC;
      oldsize:integer;
      ypos,lines,xsize:integer;
      mip,map:integer;
      frametable:PNHFrame;
      c:longint;
      tr,dummy:TRect;
      prm:TNHPaintParam;
 
    begin
      if p^.ndInfo.hiVScrollerFnc=Nil then
        begin
          GetScrollRange(hWindow,sb_Vert,mip,map);
          if (mip=map) and (mip=0) then Dec(w,GetSystemMetrics(sm_CXVScroll)+1);
        end;
 
      if p^.ndInfo.hiHScrollerFnc=Nil then
        begin
          GetScrollRange(hWindow,sb_Horz,mip,map);
          if (mip=map) and (mip=0) then Dec(h,GetSystemMetrics(sm_CYVScroll)+1);
        end;
 
      dc:=GetDC(0);
 
      with p^ do
        begin
          ndWidth:=w;
          w:=w-p^.ndInfo.hiRightSpace-p^.ndInfo.hiLeftSpace;
 
          oldsize:=ndYSize;
          NHPrepareText(ndText);
 
          if w<=0 then w:=1;
          NHCutText(
            hWindow,
            dc,
            w,
            ypos,
            lines,
            xsize,
            p);
 
          NHPaintText(
            hWindow,
            dc,
            dummy,
            p,
            dopaint_Calculate,
            prm);
 
          ndYSize:=ypos;
 
          if lines=0 then
            ndYStep:=1
          else
            ndYStep:=ypos div lines;
 
          if oldsize=0 then
            ndYPos:=0
          else
            ndYPos:=QuadMulDiv(ndYPos,ndYSize,oldsize);
        end;
 
      ReleaseDC(0,dc);
 
      with p^ do
        if ndYSize<=h then
          begin
            if (ndInfo.hiVScrollerFnc=Nil) then
              begin
                SetScrollRange(hWindow,sb_Vert,0,0,false);
                SetScrollPos(hWindow,sb_Vert,0,true);
 
                Inc(ndWidth,GetSystemMetrics(sm_CXVScroll)+1)
              end
            else
              begin
                HTScrollerHandler(ndInfo.hiVScrollerFnc)(hWindow,htscrollfnc_SetScrollRange,0,0,ndInfo);
                HTScrollerHandler(ndInfo.hiVScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,0,0,ndInfo);
              end;
 
            ndYPos:=0;
            ndYEnd:=ndYSize;
            ndVScroll:=false;
          end
        else
          begin
            ndYEnd:=ndYSize-(h div 2);
 
            if (ndInfo.hiVScrollerFnc=Nil) then
              begin
                SetScrollRange(hWindow,sb_Vert,0,ndYEnd,false);
                SetScrollPos(hWindow,sb_Vert,ndYPos,true);
              end
            else
              begin
                HTScrollerHandler(ndInfo.hiVScrollerFnc)(hWindow,htscrollfnc_SetScrollRange,ndYEnd,0,ndInfo);
                HTScrollerHandler(ndInfo.hiVScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,ndYPos,0,ndInfo);
              end;
 
            ndVScroll:=true;
          end;
 
      p^.ndXSize:=xsize;
      xsize:=xsize-w;
 
      with p^ do
        if xsize>0 then
          begin
            ndXStep:=w div 10;
            if ndXStep=0 then ndXStep:=1;
            ndXEnd:=xsize;
            ndXPos:=0;
 
            if (ndInfo.hiHScrollerFnc=Nil) then
              begin
                SetScrollRange(hWindow,sb_Horz,0,ndXEnd,false);
                SetScrollPos(hWindow,sb_Horz,ndXPos,true);
              end
            else
              begin
                HTScrollerHandler(ndInfo.hiHScrollerFnc)(hWindow,htscrollfnc_SetScrollRange,ndXEnd,0,ndInfo);
                HTScrollerHandler(ndInfo.hiHScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,ndXPos,0,ndInfo);
              end;
 
            ndHScroll:=true;
          end
        else
          begin
            ndXStep:=0;
            ndXEnd:=0;
            ndXPos:=0;
 
            if (ndInfo.hiHScrollerFnc=Nil) then
              begin
                SetScrollRange(hWindow,sb_Horz,0,0,false);
                SetScrollPos(hWindow,sb_Horz,0,true);
              end
            else
              begin
                HTScrollerHandler(ndInfo.hiHScrollerFnc)(hWindow,htscrollfnc_SetScrollRange,0,0,ndInfo);
                HTScrollerHandler(ndInfo.hiHScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,0,0,ndInfo);
              end;
 
            ndHScroll:=false;
          end;
 
      with p^ do
        begin
          frametable:=ndFrameTable;
          for c:=0 to ndFrameTableSize-1 do
            begin
              with frametable^ do
                if BGet(hfStyle,hfstyle_ChildWindow) then
                  begin
                    tr:=hfRect;
                    OffsetRect(tr,-ndXPos+ndInfo.hiLeftSpace,-ndYPos);
                    HTFrameHandler(ndInfo.hiFrameFnc)(
                      frametable,
                      hWindow,
                      htframefnc_ResizeChild,
                      dc,
                      0,
                      0,
                      tr,
                      ndInfo);
                  end;
 
              frametable:=FIncPtr(frametable,SizeOf(frametable^));
            end;
        end;
    end;
 
  procedure ReleaseMem;
 
    begin
      with p^ do
        begin
          if ndRects<>Nil         then NGFree(ndRects);
          if ndText<>Nil          then NGFree(ndText);
          if ndFontTable<>Nil     then NGFree(Pointer(ndFontTable));
          if ndIndexes<>Nil       then NGFree(Pointer(ndIndexes));
          if ndLineInfo<>Nil      then NGFree(Pointer(ndLineInfo));
          if ndParaTable<>Nil     then NGFree(Pointer(ndParaTable));
          if ndAutoCharTable<>Nil then NGFree(Pointer(ndAutoCharTable));
          if ndFrameTable<>Nil    then
            begin
              NHReleaseAllWindows(hWindow,p);
              NGFree(Pointer(ndFrameTable));
            end;
          if ndColorTable<>Nil    then NGFree(Pointer(ndColorTable));
        end
    end;
 
  procedure SelectPoint(tp:TPoint;extend:bool);
 
    var
      selchar:longint;
      selrect:TSRect;
      selline:longint;
      sfline,sfpos,slline,slpos,sfchar,slchar:longint;
      rgn:hRgn;
 
    begin
      selchar:=GetCharacter(tp,selline,selrect);
 
      if selchar<>-1 then
        with p^ do
          begin
            if extend then
              begin
                if ndSelPositive then
                  if
                    (selline<ndSelFirstLine) or
                    ((selline=ndSelFirstLine) and (selrect.left<ndSelFirstPos))
                  then
                    begin
                      sfchar:=selchar;
                      sfline:=selline;
                      sfpos:=selrect.left;
                      slchar:=ndSelFirstChar-1;
                      slline:=ndSelFirstLine;
                      slpos:=ndSelFirstPos;
 
                      ndSelPositive:=false;
                    end
                  else
                    begin
                      sfchar:=ndSelFirstChar;
                      sfline:=ndSelFirstLine;
                      sfpos:=ndSelFirstPos;
                      slchar:=selchar;
                      slline:=selline;
                      slpos:=selrect.right;
                    end
                else
                  if
                    (selline>ndSelLastLine) or
                    ((selline=ndSelLastLine) and (selrect.left>ndSelLastPos))
                  then
                    begin
                      sfchar:=ndSelLastChar+1;
                      sfline:=ndSelLastLine;
                      sfpos:=ndSelLastPos;
                      slchar:=selchar;
                      slline:=selline;
                      slpos:=selrect.right;
 
                      ndSelPositive:=true;
                    end
                  else
                    begin
                      sfchar:=selchar;
                      sfline:=selline;
                      sfpos:=selrect.left;
                      slchar:=ndSelLastChar;
                      slline:=ndSelLastLine;
                      slpos:=ndSelLastPos;
                    end;
 
                rgn:=NHUpdateSelection(
                  p,
                  sfline,
                  sfpos,
                  slline,
                  slpos,
                  MaxLineLength div 2,
                  true);
 
                ndSelFirstChar  :=sfchar;
                ndSelFirstLine  :=sfline;
                ndSelFirstPos   :=sfpos;
                ndSelLastChar   :=slchar;
                ndSelLastLine   :=slline;
                ndSelLastPos    :=slpos;
 
                if rgn<>0 then
                  begin
                    InvalidateRgn(hWindow,rgn,false);
                    DeleteObject(rgn);
                  end;
              end
            else
              begin
                rgn:=NHUpdateSelection(
                  p,
                  selline,
                  selrect.left,
                  selline,
                  selrect.right,
                  MaxLineLength div 2,
                  true);
 
                ndSelFirstChar:=selchar;
                ndSelFirstLine:=selline;
                ndSelFirstPos:=selrect.left;
                ndSelLastChar:=selchar;
                ndSelLastLine:=selline;
                ndSelLastPos:=selrect.right;
                ndInSelection:=true;
 
                if rgn<>0 then
                  begin
                    InvalidateRgn(hWindow,rgn,false);
                    DeleteObject(rgn);
                  end;
              end;
 
            SRectToRect(selrect,p^.ndSelRect);
          end
    end;
 
  procedure CorrectClientCursor(var tp:TPoint);
 
    begin
      with p^ do
        begin
          Inc(tp.y,p^.ndYPos);
          Inc(tp.x,p^.ndXPos-ndInfo.hiLeftSpace);
        end;
    end;
 
  procedure HGetCursorPos(var tp:TPoint);
 
    begin
      GetCursorPos(tp);
      ScreenToClient(hWindow,tp);
      CorrectClientCursor(tp);
    end;
 
  function  GetSelection(pchr:PChar;mlen:longint):longint;
 
    var
      src:PChar;
      len:longint;
      pos:longint;
 
      od:array[0..1] of char;
 
    begin
      with p^ do
        if ndInSelection then
          begin
            pos:=0;
            len:=ndSelLastChar-ndSelFirstChar+1;
            src:=FIncPtr(ndText,ndSelFirstChar);
 
            while
              ((pchr=Nil) or ((pos<mlen) or (mlen=0))) and
              (len>0)
            do
              begin
                case src[0] of
                  NHFontChar,
                  NHHiliteChar,
                  NHColorChar,
                  NHAutoChar,
                  NHFrameChar:;
 
                  NHNLChar,
                  NHLineBreakChar,
                  NHSpaceChar,
                  NHHardSpaceChar:
                    begin
                      if pchr<>Nil then
                        begin
                          pchr[0]:=' ';
                          pchr:=FIncPtr1(pchr);
                        end;
 
                      Inc(pos)
                    end;
 
                  NHParaChar:
                    begin
                      if pchr<>Nil then
                        begin
                          pchr[0]:=#13;
                          pchr:=FIncPtr1(pchr);
                          pchr[0]:=#10;
                          pchr:=FIncPtr1(pchr);
                        end;
 
                      Inc(pos,2)
                    end;
 
                  NHTabChar:
                    begin
                      if pchr<>Nil then
                        begin
                          pchr[0]:=#9;
                          pchr:=FIncPtr1(pchr);
                        end;
 
                      Inc(pos);
                    end;
 
                  else
                    begin
                      if pchr<>Nil then
                        begin
                          pchr[0]:=src[0];
                          pchr:=FIncPtr1(pchr);
                        end;
 
                      Inc(pos);
                    end
                end;
 
                Dec(len);
                src:=FIncPtr1(src);
              end;
 
            if pchr<>Nil then pchr[0]:=#0;
 
            GetSelection:=pos;
          end
        else
          GetSelection:=-1;
    end;
 
  begin
    result:=0;
    if msg<>wm_NCCreate then p:=NSRCtlMemoryLock(hWindow);
 
    case msg of
      wm_NCCreate:
        begin
          result:=NSRCtlDefWindowProc(hWindow,msg,wParam,lParam);
 
          NSRCtlInitWindow(hWindow,0,0,0);
          NSRCtlMemoryInit(hWindow,SizeOf(TNHData));
          p:=NSRCtlMemoryLock(hWindow);
 
          with p^ do
            begin
              with ndInfo do
                begin
                  hiBgrndColor:=RGB(255,255,255);
                  hiFonts:=Nil;
                  hiColors:=Nil;
                  hiStyles:=Nil;
                  hiNumFonts:=0;
                end;
 
              ndRects:=Nil;
              ndText:=Nil;
              ndFontTable:=Nil;
              ndColorTable:=Nil;
              ndAutoCharTable:=Nil;
              ndFrameTable:=Nil;
              ndParaTable:=Nil;
              ndIndexes:=Nil;
              ndLineInfo:=Nil;
              ndYPos:=0;
              ndXPos:=0;
              ndError:=nderror_Ok;
              ndFreeze:=false;
 
              ndInSelection:=false;
              ndSelFirstChar:=18;
              ndSelLastChar:=300;
            end;
        end;
      wm_NCDestroy:
        begin
          ReleaseMem;
          NSRCtlMemoryUnlock(hWindow);
          NSRCtlMemoryDone(hWindow);
        end;
      wm_Paint:
        if DoIt then
          with p^ do
            begin
              dc:=BeginPaint(hWindow,ps);
              GetClientRect(hWindow,tr);
 
              if ndLineInfo<>Nil then
                begin
                  NHPaint(
                    hWindow,
                    dc,
                    ps,
                    p);
                end;
              EndPaint(hWindow,ps);
            end
          else
            begin
              BeginPaint(hWindow,ps);
              EndPaint(hWindow,ps);
            end;
      wm_Size:
        begin
          if DoIt and not p^.ndFreeze then
            begin
              p^.ndFreeze:=true;
              CutText(integer(LoWord(lParam)),integer(HiWord(lParam)));
{             InvalidateRect(hWindow,Nil,false);
              UpdateWindow(hWindow);}
              p^.ndFreeze:=false;
            end;
        end;
      wm_GetDlgCode:
        begin
          result:=dlgc_Static
        end;
      wm_SetText:
        begin
          if (p<>Nil) and (p^.ndInfo.hiFonts<>Nil) then
            begin
              p^.ndError:=NSRHyperCompileText(PChar(lParam),nct);
              if p^.ndError=nderror_Ok then SendMessage(hWindow,htm_SetCompiledText,0,longint(@nct));
            end;
 
          result:=NSRCtlDefWindowProc(hWindow,msg,wParam,lParam);
        end;
      htm_SetCompiledText:
        begin
          if (p<>Nil) and (p^.ndInfo.hiFonts<>Nil) then
            with p^,PNHCompiledText(lparam)^ do
              begin
                ReleaseMem;
 
                ndError:=nderror_Ok;
 
                ndIndexes:=nctIndexesTable;
 
                ndFontTable:=nctFontTable;
                ndParaTable:=nctParaTable;
                ndColorTable:=nctColorTable;
                ndAutoCharTable:=nctAutoCharTable;
                ndFrameTable:=nctFrameTable;
 
                ndFontTableSize:=nctFontTableSize;
                ndParaTableSize:=nctParaTableSize;
                ndColorTableSize:=nctColorTableSize;
                ndAutoCharTableSize:=nctAutoCharTableSize;
                ndFrameTableSize:=nctFrameTableSize;
 
                ndText:=nctText;
 
                NHGetAllData(hWindow,p);
 
                ndYPos:=0;
                ndXPos:=0;
 
                if DoIt then
                  begin
                    GetClientRect(hWindow,tr);
                    CutText(tr.right-tr.left,tr.bottom-tr.top);
                    InvalidateRect(hWindow,Nil,false);
                  end;
              end;
 
          result:=nderror_Ok;
        end;
      wm_LButtonDown:
        begin
          if DoIt then
            begin
              SetCapture(hWindow);
              HGetCursorPos(tp);
 
              if GWIsStyle(hWindow,hs_NoSelection) then
                p^.ndInSelection:=false
              else
                with p^ do
                  begin
                    ndSelPositive:=true;
                    ndSelMouseIn:=true;
                    ndSelExtended:=IsCurShift;
 
                    if ndInSelection and (not ndSelExtended) then
                      begin
                        rgn:=NHUpdateSelection(
                          p,
                          0,
                          0,
                          0,
                          0,
                          MaxLineLength div 2,
                          false);
 
                        ndInSelection:=false;
 
                        if rgn<>0 then
                          begin
                            InvalidateRgn(hWindow,rgn,false);
                            DeleteObject(rgn);
                          end;
                      end;
 
                    ndSelStartPoint:=tp;
                  end;
            end;
        end;
      wm_Timer:
        begin
          if DoIt then
            with p^ do
              if (not ndSelMouseIn) and (GetCapture=hWindow) then
                begin
                  GetCursorPos(tp);
                  GetClientRect(hWindow,tr);
                  ScreenToClient(hWindow,tp);
 
                  {decide for direction - based upon the position of the cursor relative to the screen}
 
                  with tr do
                    begin
                      if tp.x>right then
                        begin
                          SendMessage(hWindow,wm_HScroll,sb_linedown,0);
                          tp.x:=tr.right-1
                        end
                      else if tp.x<left then
                        begin
                          SendMessage(hWindow,wm_HScroll,sb_lineup,0);
                          tp.x:=0;
                        end;
 
                      if tp.y>bottom then
                        begin
                          SendMessage(hWindow,wm_VScroll,sb_linedown,0);
                          tp.y:=tr.bottom-1
                        end
                      else if tp.y<top then
                        begin
                          SendMessage(hWindow,wm_VScroll,sb_lineup,0);
                          tp.y:=0
                        end;
 
                      if not GWIsStyle(hWindow,hs_NoSelection) then
                        begin
                          CorrectClientCursor(tp);
                          SelectPoint(tp,true);
                        end;
                    end
                end;
        end;
      wm_MouseMove:
        begin
          if GetCapture=hWindow then
            if DoIt then
              with p^ do
                begin
                  GetClientRect(hWindow,tr);
                  GetCursorPos(tp);
                  ScreenToClient(hWindow,tp);
 
                  {if mouse went out of the screen, then init timer; if it came back, kill}
                  {the timer. If the state remains the same, leave everything}
 
                  if ndSelMouseIn then
                    begin
                      if PtInRect(tr,tp) then
                        is:=true
                      else
                        begin
                          ndSelMouseIn:=false;
                          NSRCtrlInitTimer(hWindow);
                          is:=false
                        end
                    end
                  else
                    begin
                      if PtInRect(tr,tp) then
                        begin
                          is:=true;
                          NSRCtrlKillTimer(hWindow);
                          ndSelMouseIn:=true
                        end
                      else
                        is:=false;
                    end;
 
                  if is then
                    begin
                      HGetCursorPos(tp);
 
                      if not GWIsStyle(hWindow,hs_NoSelection) then
                        if ndInSelection then
                          begin
                            if not PtInRect(ndSelRect,tp) then SelectPoint(tp,true);
                          end
                        else
                          begin
                            SelectPoint(ndSelStartPoint,ndSelExtended);
                            if not ndInSelection then ndSelStartPoint:=tp;
                          end
                    end
                end
        end;
      wm_LButtonUp:
        begin
          if DoIt then
            begin
              ReleaseCapture;
 
              HGetCursorPos(tp);
 
              with p^ do
                if not ndInSelection then
                  begin
                    index:=NHFindHotRect(p^.ndRects,tp);
 
                    if index<>-1 then PostMessage(p^.ndInfo.hiReceiver,wm_HyperLink,0,index)
                  end
            end;
 
          if not crsr then SetCursor(LoadCursor(0,idc_Arrow));
        end;
      wm_SetCursor:
        begin
          crsr:=false;
          if (LoWord(lParam)=htClient) and DoIt then
            with p^ do
              begin
                HGetCursorPos(tp);
 
                if ndInSelection then
                  index:=-1
                else
                  index:=NHFindHotRect(ndRects,tp);
 
                if index<>-1 then
                  begin
                    crsr:=true;
                    hotcursor:=HTHotSpotHandler(ndInfo.hiHotSpotFnc)(
                      PNHHotSpot(FIncPtr(ndIndexes,index*SizeOf(TNHHotSpot)))^.hsIndex,
                      hWindow,
                      hthotspotfnc_GetCursor,
                      ndInfo);
 
                    if hotcursor=-1 then
                      SetCursor(p^.ndInfo.hiCursorLink)
                    else
                      SetCursor(hotcursor)
                  end
                else
                  begin
                    crsr:=true;
                    SetCursor(p^.ndInfo.hiCursor)
                  end
              end;
 
          if not crsr then SetCursor(LoadCursor(0,idc_Arrow));
        end;
      wm_HScroll:
        if DoIt then
          with p^ do
            if ndHScroll then
              begin
                oldpos:=ndXPos;
 
                GetClientRect(hWindow,tr);
 
                case wParam of
                  sb_Top:           ndXPos:=0;
                  sb_Bottom:        ndXPos:=ndXEnd;
                  sb_PageUp:        Dec(ndXPos,tr.right);
                  sb_PageDown:      Inc(ndXPos,tr.right);
                  sb_LineUp:        Dec(ndXPos,ndXStep);
                  sb_LineDown:      Inc(ndXPos,ndXStep);
                  sb_ThumbPosition: ndXPos:=integer(LoWord(lParam));
                end;
 
                if ndXPos<0 then ndXPos:=0;
                if ndXPos>ndXEnd then ndXPos:=ndXEnd;
 
                if ndInfo.hiHScrollerFnc=Nil then
                  SetScrollPos(hWindow,sb_Horz,ndXPos,true)
                else
                  HTScrollerHandler(ndInfo.hiHScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,ndXPos,0,ndInfo);
 
                ScrollWindow(hWindow,oldpos-ndXPos,0,Nil,Nil);
              end;
      wm_VScroll:
        if DoIt then
          with p^ do
            if ndVScroll then
              begin
                oldpos:=ndYPos;
 
                GetClientRect(hWindow,tr);
 
                case wParam of
                  sb_Top:           ndYPos:=0;
                  sb_Bottom:        ndYPos:=ndYEnd;
                  sb_PageUp:        Dec(ndYPos,tr.bottom);
                  sb_PageDown:      Inc(ndYPos,tr.bottom);
                  sb_LineUp:        Dec(ndYPos,ndYStep);
                  sb_LineDown:      Inc(ndYPos,ndYStep);
                  sb_ThumbPosition: ndYPos:=integer(LoWord(lParam));
                end;
 
                if ndYPos<0 then ndYPos:=0;
                if ndYPos>ndYEnd then ndYPos:=ndYEnd;
 
                if ndInfo.hiVScrollerFnc=Nil then
                  SetScrollPos(hWindow,sb_Vert,ndYPos,true)
                else
                  HTScrollerHandler(ndInfo.hiVScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,ndYPos,0,ndInfo);
 
                ScrollWindow(hWindow,0,oldpos-ndYPos,Nil,Nil);
              end;
        wm_NCPaint:
          begin
            result:=DefWindowProc(hWindow,msg,wParam,lParam);
          end;
        wm_NCCalcSize:
          begin
            result:=DefWindowProc(hWindow,msg,wParam,lParam);
          end;
 
        htm_GetSelection:
          begin
            result:=GetSelection(Pointer(lParam),integer(wParam));
          end;
        htm_SetParaPos:
          begin
            with p^ do
              with PNHParagraph(FIncPtr(ndParaTable,lParam*SizeOf(TNHParagraph)))^ do
                begin
                  if ndInfo.hiVScrollerFnc=Nil then
                    SetScrollPos(hWindow,sb_Vert,hpPosition,true)
                  else
                    HTScrollerHandler(ndInfo.hiVScrollerFnc)(hWindow,htscrollfnc_SetScrollPos,hpPosition,0,ndInfo);
 
                  ScrollWindow(hWindow,0,ndYPos-hpPosition,Nil,Nil);
                end;
          end;
      else
        result:=NSRCtlDefWindowProc(hWindow,msg,wParam,lParam);
    end;
 
    if msg<>wm_NCDestroy then NSRCtlMemoryUnlock(hWindow);
    NHyperWindowProc:=result;
  end;
 
 
procedure NSRHyperSetInfo(h:hWnd;p:PNHyperInfo);
 
  var
    inf:PNHData;
 
  begin
    inf:=NSRCtlMemoryLock(h);
    if inf<>Nil then inf^.ndInfo:=p^;
    NSRCtlMemoryUnlock(h);
  end;
 
 
const
  RegCount:integer=0;
 
 
procedure NSRHyperTextInit;
 
  begin
    if RegCount=0 then
      begin
        NSRCtlCreateClass(
          hInstance,
          NSRHyperTextClassName,
          cs_DblClks or cs_GlobalClass or cs_HRedraw or cs_VRedraw,
          0,
          0,
          LoadCursor(0,PChar(idc_arrow)),
          @NHyperWindowProc);
      end;
 
    Inc(RegCount);
  end;
 
 
function  NSRHyperCompileText;
 
  var
    ndError:integer;
    len:longint;
 
  begin
    with nct do
      begin
        FillChar(nct,SizeOf(nct),#0);
 
        ndError:=nderror_Ok;
 
        NHCountHiliteFontParaColorCharFrames(
          txt,
          len,
          nctIndexesTableSize,
          nctFontTableSize,
          nctParaTableSize,
          nctColorTableSize,
          nctAutoCharTableSize,
          nctFrameTableSize
          );
 
        nctFontTableMSize:=nctFontTableSize*SizeOf(byte);
        nctParaTableMSize:=nctParaTableSize*SizeOf(TNHParagraph);
        nctColorTableMSize:=nctColorTableSize*SizeOf(byte);
        nctAutoCharTableMSize:=nctAutoCharTableSize*SizeOf(TNHAutoChar);
        nctFrameTableMSize:=nctFrameTableSize*SizeOf(TNHFrame);
        nctIndexesTableMSize:=nctIndexesTableSize*SizeOf(TNHHotSpot);
 
        if nctFontTableSize<>0 then
          begin
            nctFontTable:=NGAlloc(gmem_Moveable,nctFontTableMSize);
            if (nctFontTable=Nil) then ndError:=nderror_OutOfMem;
          end;
 
        if nctParaTableSize<>0 then
          begin
            nctParaTable:=NGAlloc(gmem_Moveable,nctParaTableMSize);
            if (nctParaTable=Nil) then ndError:=nderror_OutOfMem;
          end;
 
        if nctColorTableSize<>0 then
          begin
            nctColorTable:=NGAlloc(gmem_Moveable,nctColorTableMSize);
            if (nctColorTable=Nil) then ndError:=nderror_OutOfMem;
          end;
 
        if nctAutoCharTableSize<>0 then
          begin
            nctAutoCharTable:=NGAlloc(gmem_Moveable,nctAutoCharTableMSize);
            if (nctAutoCharTable=Nil) then ndError:=nderror_OutOfMem;
          end;
 
        if nctFrameTableSize<>0 then
          begin
            nctFrameTable:=NGAlloc(gmem_Moveable,nctFrameTableMSize);
            if (nctFrameTable=Nil) then ndError:=nderror_OutOfMem;
          end;
 
        if nctIndexesTableSize<>0 then
          begin
            nctIndexesTable:=NGAlloc(gmem_Moveable,nctIndexesTableMSize);
            if (nctIndexesTable=Nil) then ndError:=nderror_OutOfMem
          end;
 
        if (ndError=nderror_Ok) then
          begin
            nctText:=NHCompile(
              txt,
              len,
              nctTextMSize,
              nctIndexesTable,
              nctFontTable,
              nctParaTable,
              nctColorTable,
              nctAutoCharTable,
              nctFrameTable,
              nctParaTableSize);
 
            if nctText=Nil then ndError:=nderror_OutOfMem;
          end;
 
        if ndError<>nderror_Ok then
          begin
            if nctIndexesTable<>Nil   then NGFree(Pointer(nctIndexesTable));
            if nctFontTable<>Nil      then NGFree(Pointer(nctFontTable));
            if nctParaTable<>Nil      then NGFree(Pointer(nctParaTable));
            if nctColorTable<>Nil     then NGFree(Pointer(nctColorTable));
            if nctAutoCharTable<>Nil  then NGFree(Pointer(nctAutoCharTable));
            if nctFrameTable<>Nil     then NGFree(Pointer(nctFrameTable));
          end;
 
        NSRHyperCompileText:=ndError;
      end;
  end;
 
 
procedure NSRHyperTextDone;
 
  begin
    if RegCount=1 then
      begin
        UnregisterClass(NSRHyperTextClassName,hInstance);
      end;
 
    Dec(RegCount)
  end;
 
 
end.