123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202(*
* Copyright 2011 The Savonet Team
*
* This file is part of ocaml-mm.
*
* ocaml-mm is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ocaml-mm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with ocaml-mm; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* As a special exception to the GNU Library General Public License, you may
* link, statically or dynamically, a "work that uses the Library" with a publicly
* distributed version of the Library to produce an executable file containing
* portions of the Library, and distribute that executable file under terms of
* your choice, without any of the additional requirements listed in clause 6
* of the GNU Library General Public License.
* By "a publicly distributed version of the Library", we mean either the unmodified
* Library as distributed by The Savonet Team, or a modified version of the Library that is
* distributed under the conditions defined in clause 3 of the GNU Library General
* Public License. This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU Library General Public License.
*
*)typet=boolarrayarraytypebitmap=tletcreatecwidthheight:t=Array.initheight(fun_->Array.makewidthc)letcreate_white=createtrueletcreate=createfalseletmakedata:t=dataletinitwidthheightf=make(Array.initheight(funj->Array.initwidth(funi->fij)))letwidth(img:t)=ifArray.lengthimg=0then0elseArray.lengthimg.(0)letheight(img:t)=Array.lengthimgletget_pixelimgij=img.(j).(i)letset_pixelimgijc=img.(j).(i)<-cletfillimgf=forj=0toheightimg-1dofori=0towidthimg-1doset_pixelimgij(fij)donedoneletscalesrctgt=letws=widthsrcinletwt=widthtgtinleths=heightsrcinletht=heighttgtinfilltgt(funij->get_pixelsrc(i*ws/wt)(j*hs/ht))letrescalepqimg=letimg2=create(widthimg*p/q)(heightimg*p/q)inscaleimgimg2;img2letblitsrc?(x=0)?(y=0)dst=letwidth=min(widthsrc)(widthdst-x)inletheight=min(heightsrc)(heightdst-y)inforj=0toheight-1dofori=0towidth-1doset_pixeldst(x+i)(y+j)(get_pixelsrcij)donedone(** Bitmap fonts. *)moduleFont=structmoduleCharMap=Map.Make(structtypet=charletcompare(c:t)(d:t)=Stdlib.comparecdend)(** A fixed-size font. *)typenonrect={map:tCharMap.tLazy.t;width:int;(** width of a char in pixels *)height:int;(** height of a char in pixels *)default:t;(** default displayed character when not supported *)uppercase:bool;(** whether only uppercase caracters are supported *)char_space:int;line_space:int;}letheightfont=font.height(** Our native font. *)letnative:t=letprebitmap=[('A',[|" * ";"* *";"***";"* *";"* *"|]);('B',[|"** ";"* *";"** ";"* *";"** "|]);('C',[|" **";"* ";"* ";"* ";" **"|]);('D',[|"** ";"* *";"* *";"* *";"** "|]);('E',[|"***";"* ";"** ";"* ";"***"|]);('F',[|"***";"* ";"** ";"* ";"* "|]);('G',[|" **";"* ";"* *";"* *";" **"|]);('H',[|"* *";"* *";"***";"* *";"* *"|]);('I',[|" * ";" * ";" * ";" * ";" * "|]);('J',[|" *";" *";" *";"* *";" * "|]);('K',[|"* *";"** ";"* ";"** ";"* *"|]);('L',[|"* ";"* ";"* ";"* ";"***"|]);('M',[|"* *";"***";"* *";"* *";"* *"|]);('N',[|"* *";"***";"***";"***";"* *"|]);('O',[|" * ";"* *";"* *";"* *";" * "|]);('P',[|"** ";"* *";"** ";"* ";"* "|]);('Q',[|" * ";"* *";"* *";"* *";" **"|]);('R',[|"** ";"* *";"** ";"* *";"* *"|]);('S',[|" **";"* ";" * ";" *";"** "|]);('T',[|"***";" * ";" * ";" * ";" * "|]);('U',[|"* *";"* *";"* *";"* *";"***"|]);('V',[|"* *";"* *";"* *";"* *";" * "|]);('W',[|"* *";"* *";"* *";"***";"* *"|]);('X',[|"* *";"* *";" * ";"* *";"* *"|]);('Y',[|"* *";"* *";" * ";" * ";" * "|]);('Z',[|"***";" *";" * ";"* ";"***"|]);('0',[|" * ";"* *";"* *";"* *";" * "|]);('1',[|" * ";"** ";" * ";" * ";" * "|]);('2',[|" * ";"* *";" *";" * ";"***"|]);('3',[|"** ";" *";" * ";" *";"** "|]);('4',[|" *";" **";"***";" *";" *"|]);('5',[|"***";"* ";"** ";" *";"** "|]);('6',[|" **";"* ";"** ";"* *";" * "|]);('7',[|"***";" *";" * ";" * ";" * "|]);('8',[|" * ";"* *";" * ";"* *";" * "|]);('9',[|" * ";"* *";" **";" *";" * "|]);(' ',[|" ";" ";" ";" ";" "|]);('.',[|" ";" ";" ";" ";" * "|]);(',',[|" ";" ";" ";" * ";" * "|]);('!',[|" * ";" * ";" * ";" ";" * "|]);('?',[|" * ";"* *";" **";" * ";" * "|]);('-',[|" ";" ";"***";" ";" "|]);('+',[|" ";" * ";"***";" * ";" "|]);('=',[|" ";"***";" ";"***";" "|]);(':',[|" ";" * ";" ";" * ";" "|]);('<',[|" *";" * ";"* ";" * ";" *"|]);('>',[|"* ";" * ";" *";" * ";"* "|]);]inletwidth=3inletheight=5inletmap=Lazy.from_fun(fun()->List.fold_left(funf(c,b)->letbmp=initwidthheight(funij->b.(j).[i]<>' ')inCharMap.addcbmpf)CharMap.emptyprebitmap)inletdefault=create_whitewidthheightin{map;width;height;default;uppercase=true;char_space=1;line_space=2}letrender?(font=native)?sizetext=letheight=Option.value~default:font.heightsizeinlettext_height,text_width=leth=ref1inletmax=ref0inletcur=ref0infori=0toString.lengthtext-1doiftext.[i]='\n'then(max:=Stdlib.max!max!cur;cur:=0;incrh)elseincrcurdone;max:=Stdlib.max!max!cur;!h,!maxinletimg=letwidth=text_width*font.width+(text_width-1)*font.char_spaceinletheight=text_height*font.height+(text_height-1)*font.line_spaceinletwidth=maxwidth0inletheight=maxheight0increatewidthheightinletxoff=ref0inletyoff=ref0infori=0toString.lengthtext-1doletc=text.[i]inifc='\n'then(xoff:=0;yoff:=!yoff+font.height+font.line_space)elseletc=iffont.uppercasethenChar.uppercase_asciicelsecinletc=matchCharMap.find_optc(Lazy.forcefont.map)withSomec->c|None->font.defaultinblitc~x:!xoff~y:!yoffimg;xoff:=!xoff+font.width+font.char_spacedone;rescaleheightfont.heightimgend