summaryrefslogtreecommitdiff
path: root/pango-view
diff options
context:
space:
mode:
Diffstat (limited to 'pango-view')
-rw-r--r--pango-view/GLASS.utf8170
-rw-r--r--pango-view/HELLO.utf854
-rw-r--r--pango-view/Makefile.am188
-rw-r--r--pango-view/pango-view.c23
-rw-r--r--pango-view/pangocairo-view.c8
-rw-r--r--pango-view/pangoft2-view.c8
-rw-r--r--pango-view/pangox-view.c8
-rw-r--r--pango-view/pangoxft-view.c8
-rw-r--r--pango-view/renderdemo.c676
-rw-r--r--pango-view/renderdemo.h86
-rw-r--r--pango-view/test-arabic.txt7
-rw-r--r--pango-view/test-chinese.txt7
-rw-r--r--pango-view/test-devanagari.txt9
-rw-r--r--pango-view/test-gurmukhi.txt26
-rw-r--r--pango-view/test-hebrew.txt13
-rw-r--r--pango-view/test-ipa.txt8
-rw-r--r--pango-view/test-lao.txt2
-rw-r--r--pango-view/test-latin.txt9
-rw-r--r--pango-view/test-mixed.txt8
-rw-r--r--pango-view/test-syriac.txt18
-rw-r--r--pango-view/test-tamil.txt13
-rw-r--r--pango-view/test-thai.txt11
-rw-r--r--pango-view/test-tibetan.txt12
-rw-r--r--pango-view/viewer-cairo.c53
-rw-r--r--pango-view/viewer-cairo.h42
-rw-r--r--pango-view/viewer-main.c162
-rw-r--r--pango-view/viewer-pangocairo.c425
-rw-r--r--pango-view/viewer-pangoft2.c162
-rw-r--r--pango-view/viewer-pangox.c122
-rw-r--r--pango-view/viewer-pangoxft.c151
-rw-r--r--pango-view/viewer-win32.c748
-rw-r--r--pango-view/viewer-x.c241
-rw-r--r--pango-view/viewer-x.h70
-rw-r--r--pango-view/viewer.h99
34 files changed, 3647 insertions, 0 deletions
diff --git a/pango-view/GLASS.utf8 b/pango-view/GLASS.utf8
new file mode 100644
index 00000000..610b595e
--- /dev/null
+++ b/pango-view/GLASS.utf8
@@ -0,0 +1,170 @@
+I Can Eat Glass
+In various languages
+
+Adopted from http://www.columbia.edu/kermit/utf8.html#glass
+Do not edit. Submit additions to the URL above and resynch.
+
+Permission is granted by the Kermit project (http://www.columbia.edu/kermit/)
+to redistribute this file, with absolutely no warranty.
+
+
+
+Sanskrit: काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥
+Sanskrit (standard transcription): kācaṃ śaknomyattum; nopahinasti mām.
+Classical Greek: ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.
+Greek: Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.
+Etruscan: (NEEDED)
+Latin: Vitrum edere possum; mihi non nocet.
+Old French: Je puis mangier del voirre. Ne me nuit.
+French: Je peux manger du verre, ça ne me fait pas de mal.
+Provençal / Occitan: Pòdi manjar de veire, me nafrariá pas.
+Québécois: J'peux manger d'la vitre, ça m'fa pas mal.
+Walloon: Dji pou magnî do vêre, çoula m' freut nén må.
+Champenois: (NEEDED)
+Lorrain: (NEEDED)
+Picard: Ch'peux mingi du verre, cha m'foé mie n'ma.
+Corsican: (NEEDED)
+Kreyòl Ayisyen: Mwen kap manje vè, li pa blese'm.
+Basque: Kristala jan dezaket, ez dit minik ematen.
+Catalan: Puc menjar vidre que no em fa mal.
+Spanish: Puedo comer vidrio, no me hace daño.
+Aragones: Puedo minchar beire, no me'n fa mal .
+Galician: Eu podo xantar cristais e non cortarme.
+Portuguese: Posso comer vidro, não me faz mal.
+Brazilian Portuguese (7): Posso comer vidro, não me machuca.
+Caboverdiano: M' podê cumê vidru, ca ta maguâ-m'.
+Papiamentu: Ami por kome glas anto e no ta hasimi daño.
+Italian: Posso mangiare il vetro e non mi fa male.
+Milanese: Sôn bôn de magnà el véder, el me fa minga mal.
+Roman: Me posso magna' er vetro, e nun me fa male.
+Napoletano: M' pozz magna' o'vetr, e nun m' fa mal.
+Sicilian: Puotsu mangiari u vitru, nun mi fa mali.
+Venetian: Mi posso magnare el vetro, no'l me fa mae.
+Zeneise (Genovese): Pòsso mangiâ o veddro e o no me fà mâ.
+Rheto-Romance / Romansch: (NEEDED)
+Romany / Tsigane: (NEEDED)
+Romanian: Pot să mănânc sticlă și ea nu mă rănește.
+Esperanto: Mi povas manĝi vitron, ĝi ne damaĝas min.
+Pictish: (NEEDED)
+Breton: (NEEDED)
+Cornish: Mý a yl dybry gwéder hag éf ny wra ow ankenya.
+Welsh: Dw i'n gallu bwyta gwydr, 'dyw e ddim yn gwneud dolur i mi.
+Manx Gaelic: Foddym gee glonney agh cha jean eh gortaghey mee.
+Old Irish (Ogham): ᚛᚛ᚉᚑᚅᚔᚉᚉᚔᚋ ᚔᚈᚔ ᚍᚂᚐᚅᚑ ᚅᚔᚋᚌᚓᚅᚐ᚜
+Old Irish (Latin): Con·iccim ithi nglano. Ním·géna.
+Irish: Is féidir liom gloinne a ithe. Ní dhéanann sí dochar ar bith dom.
+Scottish Gaelic: S urrainn dhomh gloinne ithe; cha ghoirtich i mi.
+Anglo-Saxon (Runes): ᛁᚳ᛫ᛗᚨᚷ᛫ᚷᛚᚨᛋ᛫ᛖᚩᛏᚪᚾ᛫ᚩᚾᛞ᛫ᚻᛁᛏ᛫ᚾᛖ᛫ᚻᛖᚪᚱᛗᛁᚪᚧ᛫ᛗᛖ᛬
+Anglo-Saxon (Latin): Ic mæg glæs eotan ond hit ne hearmiað me.
+Middle English: Ich canne glas eten and hit hirtiþ me nouȝt.
+English: I can eat glass and it doesn't hurt me.
+English (IPA): [aɪ kæn iːt glɑːs ænd ɪt dɐz nɒt hɜːt miː] (Received Pronunciation)
+English (Braille): ⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑
+Lalland Scots / Doric: Ah can eat gless, it disnae hurt us.
+Glaswegian: (NEEDED)
+Gothic (4): 𐌼𐌰𐌲 𐌲𐌻𐌴𐍃 𐌹̈𐍄𐌰𐌽, 𐌽𐌹 𐌼𐌹𐍃 𐍅𐌿 𐌽𐌳𐌰𐌽 𐌱𐍂𐌹𐌲𐌲𐌹𐌸.
+Old Norse (Runes): ᛖᚴ ᚷᛖᛏ ᛖᛏᛁ ᚧ ᚷᛚᛖᚱ ᛘᚾ ᚦᛖᛋᛋ ᚨᚧ ᚡᛖ ᚱᚧᚨ ᛋᚨᚱ
+Old Norse (Latin): Ek get etið gler án þess að verða sár.
+Norsk / Norwegian (Nynorsk): Eg kan eta glas utan å skada meg.
+Norsk / Norwegian (Bokmål): Jeg kan spise glass uten å skade meg.
+Føroyskt / Faroese: (NEEDED)
+Íslenska / Icelandic: Ég get etið gler án þess að meiða mig.
+Svenska / Swedish: Jag kan äta glas utan att skada mig.
+Dansk / Danish: Jeg kan spise glas, det gør ikke ondt på mig.
+Soenderjysk: Æ ka æe glass uhen at det go mæ naue.
+Frysk / Frisian: Ik kin glês ite, it docht me net sear.
+Nederlands / Dutch: Ik kan glas eten, het doet mij geen kwaad.
+Kirchröadsj/Bôchesserplat: Iech ken glaas èèse, mer 't deet miech jing pieng.
+Afrikaans: Ek kan glas eet, maar dit doen my nie skade nie.
+Lëtzebuergescht / Luxemburgish: Ech kan Glas iessen, daat deet mir nët wei.
+Deutsch / German: Ich kann Glas essen, ohne mir weh zu tun.
+Ruhrdeutsch: Ich kann Glas verkasematuckeln, ohne dattet mich wat jucken tut.
+Lausitzer Mundart ("Lusatian"): Ich koann Gloos assn und doas dudd merr ni wii.
+Odenwälderisch: Iech konn glaasch voschbachteln ohne dass es mir ebbs daun doun dud.
+Sächsisch / Saxon: 'sch kann Glos essn, ohne dass'sch mer wehtue.
+Pfälzisch: Isch konn Glass fresse ohne dasses mer ebbes ausmache dud.
+Schwäbisch / Swabian: I kå Glas frässa, ond des macht mr nix!
+Bayrisch / Bavarian: I koh Glos esa, und es duard ma ned wei.
+Allemannisch: I kaun Gloos essen, es tuat ma ned weh.
+Schwyzerdütsch: Ich chan Glaas ässe, das tuet mir nöd weeh.
+Hungarian: Meg tudom enni az üveget, nem lesz tőle bajom.
+Suomi / Finnish: Voin syödä lasia, se ei vahingoita minua.
+Sami (Northern): Sáhtán borrat lása, dat ii leat bávččas.
+Erzian: Мон ярсан суликадо, ды зыян эйстэнзэ а ули.
+Karelian: (NEEDED)
+Vepsian: (NEEDED)
+Votian: (NEEDED)
+Livonian: (NEEDED)
+Estonian: Ma võin klaasi süüa, see ei tee mulle midagi.
+Latvian: Es varu ēst stiklu, tas man nekaitē.
+Lithuanian: Aš galiu valgyti stiklą ir jis manęs nežeidžia
+Old Prussian: (NEEDED)
+Sorbian (Wendish): (NEEDED)
+Czech: Mohu jíst sklo, neublíží mi.
+Slovak: Môžem jesť sklo. Nezraní ma.
+Polska / Polish: Mogę jeść szkło i mi nie szkodzi.
+Slovenian: Lahko jem steklo, ne da bi mi škodovalo.
+Croatian: Ja mogu jesti staklo i ne boli me.
+Serbian (Latin): Mogu jesti staklo a da mi ne škodi.
+Serbian (Cyrillic): Могу јести стакло а да ми не шкоди.
+Macedonian: Можам да јадам стакло, а не ме штета.
+Russian: Я могу есть стекло, оно мне не вредит.
+Belarusian (Cyrillic): Я магу есці шкло, яно мне не шкодзіць.
+Belarusian (Lacinka): Ja mahu jeści škło, jano mne ne škodzić.
+Ukrainian: Я можу їсти шкло, й воно мені не пошкодить.
+Bulgarian: Мога да ям стъкло, то не ми вреди.
+Georgian: მინას ვჭამ და არა მტკივა.
+Armenian: Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։
+Albanian: Unë mund të ha qelq dhe nuk më gjen gjë.
+Turkish: Cam yiyebilirim, bana zararı dokunmaz.
+Turkish (Ottoman): جام ييه بلورم بڭا ضررى طوقونمز
+Bangla / Bengali: আমি কাঁচ খেতে পারি, তাতে আমার কোনো ক্ষতি হয় না।
+Marathi: मी काच खाऊ शकतो, मला ते दुखत नाही.
+Hindi: मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती.
+Tamil: நான் கண்ணாடி சாப்பிடுவேன், அதனால் எனக்கு ஒரு கேடும் வராது.
+Urdu(2): میں کانچ کھا سکتا ہوں اور مجھے تکلیف نہیں ہوتی ۔
+Pashto(2): زه شيشه خوړلې شم، هغه ما نه خوږوي
+Farsi / Persian: .من می توانم بدونِ احساس درد شيشه بخورم
+Arabic(2): أنا قادر على أكل الزجاج و هذا لا يؤلمني.
+Aramaic: (NEEDED)
+Hebrew(2): אני יכול לאכול זכוכית וזה לא מזיק לי.
+Yiddish(2): איך קען עסן גלאָז און עס טוט מיר נישט װײ.
+Judeo-Arabic: (NEEDED)
+Ladino: (NEEDED)
+Gǝʼǝz: (NEEDED)
+Amharic: (NEEDED)
+Twi: Metumi awe tumpan, ɜnyɜ me hwee.
+Hausa (Latin): Inā iya taunar gilāshi kuma in gamā lāfiyā.
+Hausa (Ajami) (2): إِنا إِىَ تَونَر غِلَاشِ كُمَ إِن غَمَا لَافِىَا
+Yoruba(3): Mo lè je̩ dígí, kò ní pa mí lára.
+(Ki)Swahili: Naweza kula bilauri na sikunyui.
+Malay: Saya boleh makan kaca dan ia tidak mencederakan saya.
+Tagalog: Kaya kong kumain nang bubog at hindi ako masaktan.
+Chamorro: Siña yo' chumocho krestat, ti ha na'lalamen yo'.
+Javanese: Aku isa mangan beling tanpa lara.
+Burmese: (NEEDED)
+Vietnamese (quốc ngữ): Tôi có thể ăn thủy tinh mà không hại gì.
+Vietnamese (nôm) (4): 些 𣎏 世 咹 水 晶 𦓡 空 𣎏 害 咦
+Khmer: (NEEDED)
+Lao: (NEEDED)
+Thai: ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ
+Mongolian (Cyrillic): Би шил идэй чадна, надад хортой биш
+Mongolian (Classic) (5): ᠪᠢ ᠰᠢᠯᠢ ᠢᠳᠡᠶᠦ ᠴᠢᠳᠠᠨᠠ ᠂ ᠨᠠᠳᠤᠷ ᠬᠣᠤᠷᠠᠳᠠᠢ ᠪᠢᠰᠢ
+Dzongkha: (NEEDED)
+Nepali: (NEEDED)
+Tibetan: ཤེལ་སྒོ་ཟ་ནས་ང་ན་གི་མ་རེད།
+Chinese: 我能吞下玻璃而不伤身体。
+Chinese (Traditional): 我能吞下玻璃而不傷身體。
+Taiwanese(6): Góa ē-tàng chia̍h po-lê, mā bē tio̍h-siong.
+Japanese: 私はガラスを食べられます。それは私を傷つけません。
+Korean: 나는 유리를 먹을 수 있어요. 그래도 아프지 않아요
+Bislama: Mi save kakae glas, hemi no save katem mi.
+Hawaiian: Hiki iaʻu ke ʻai i ke aniani; ʻaʻole nō lā au e ʻeha.
+Marquesan: E koʻana e kai i te karahi, mea ʻā, ʻaʻe hauhau.
+Chinook Jargon: Naika məkmək kakshət labutay, pi weyk ukuk munk-sik nay.
+Navajo: Tsésǫʼ yishą́ągo bííníshghah dóó doo shił neezgai da.
+Cherokee (and Cree, Ojibwa, Inuktitut, and other Native American languages): (NEEDED)
+Garifuna: (NEEDED)
+Gullah: (NEEDED)
+Lojban: mi kakne le nu citka le blaci .iku'i le se go'i na xrani mi
+Nórdicg: Ljœr ye caudran créneþ ý jor cẃran.
diff --git a/pango-view/HELLO.utf8 b/pango-view/HELLO.utf8
new file mode 100644
index 00000000..21acb941
--- /dev/null
+++ b/pango-view/HELLO.utf8
@@ -0,0 +1,54 @@
+This is Pango (Παν語)
+
+This is a list of ways to say hello in various languages.
+Its purpose is to illustrate a number of scripts.
+
+---------------------------------------------------------
+Arabic السَّلام عليكُم
+Bengali (বাঙ্লা) ষাগতোম
+Burmese မ္ရန္မာ
+Cherokee (ᏣᎳᎩ) ᎣᏏᏲ
+Czech (česky) Dobrý den
+Danish (Dansk) Hej, Goddag
+English Hello
+Esperanto Saluton
+Estonian Tere, Tervist
+FORTRAN PROGRAM
+Finnish (Suomi) Hei
+French (Français) Bonjour, Salut
+German (Deutsch Nord) Guten Tag
+German (Deutsch Süd) Grüß Gott
+Georgian (ქართველი) გამარჯობა
+Gujarati ગુજરાતિ
+Greek (Ελληνικά) Γειά σας
+Hebrew שלום
+Hindi नमस्ते, नमस्कार।
+Italiano Ciao, Buon giorno
+IPA English (ɪŋglɪʃ) hɛləʊ
+Lao ສບາຍດ
+Maltese Ċaw, Saħħa
+Nederlands, Vlaams Hallo, Dag
+Norwegian (Norsk) Hei, God dag
+Punjabi ਪੁਂਜਾਬਿ
+Polish Dzień dobry, Hej
+Russian (Русский) Здравствуйте!
+Sinhala (සිංහල) ආයුබෝවන්
+Slovak Dobrý deň
+Spanish (Español) ¡Hola!
+Swedish (Svenska) Hej, Goddag
+Thai (ภาษาไทย) สวัสดีครับ, สวัสดีค่ะ
+Tamil (தமிழ்) வணக்கம்
+Turkish (Türkçe) Merhaba
+Vietnamese (Tiếng Việt) Xin Chào
+Yiddish (ײַדישע)‎ דאָס הײַזעלע
+
+Japanese (日本語) こんにちは, コンニチハ
+Chinese (中文,普通话,汉语) 你好
+Cantonese (粵語,廣東話) 早晨, 你好
+Korean (한글) 안녕하세요, 안녕하십니까
+
+Difference among chinese characters in GB, JIS, KSC, BIG5:
+ GB -- 元气 开发
+ JIS -- 元気 開発
+ KSC -- 元氣 開發
+ BIG5 -- 元氣 開發
diff --git a/pango-view/Makefile.am b/pango-view/Makefile.am
new file mode 100644
index 00000000..ad06af85
--- /dev/null
+++ b/pango-view/Makefile.am
@@ -0,0 +1,188 @@
+## Process this file with automake to create Makefile.in.
+
+TEST_TEXTS = \
+ test-arabic.txt \
+ test-chinese.txt \
+ test-devanagari.txt \
+ test-gurmukhi.txt \
+ test-hebrew.txt \
+ test-ipa.txt \
+ test-lao.txt \
+ test-latin.txt \
+ test-syriac.txt \
+ test-tamil.txt \
+ test-thai.txt \
+ test-tibetan.txt \
+ HELLO.utf8 \
+ GLASS.utf8
+
+EXTRA_DIST = \
+ viewer-win32.c \
+ $(TEST_TEXTS)
+
+CLEANFILES = pangorc
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(PANGO_DEBUG_FLAGS) \
+ $(GLIB_CFLAGS) \
+ $(XFT_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(FREETYPE_CFLAGS) \
+ $(X_CFLAGS)
+
+noinst_PROGRAMS =
+bin_PROGRAMS =
+
+#########################################################
+if HAVE_FREETYPE
+noinst_PROGRAMS += pangoft2-view
+
+pangoft2_view_SOURCES = \
+ renderdemo.h \
+ renderdemo.c \
+ viewer.h \
+ viewer-main.c \
+ viewer-pangoft2.c \
+ pangoft2-view.c
+
+pangoft2_view_LDADD = \
+ ../pango/libpango-$(PANGO_API_VERSION).la \
+ ../pango/libpangoft2-$(PANGO_API_VERSION).la \
+ $(GLIB_LIBS) \
+ $(FREETYPE_LIBS)
+endif
+#########################################################
+
+#########################################################
+if HAVE_X
+noinst_PROGRAMS += pangox-view
+
+pangox_view_SOURCES = \
+ renderdemo.h \
+ renderdemo.c \
+ viewer.h \
+ viewer-x.h \
+ viewer-x.c \
+ viewer-main.c \
+ viewer-pangox.c \
+ pangox-view.c
+
+pangox_view_LDADD = \
+ ../pango/libpango-$(PANGO_API_VERSION).la \
+ ../pango/libpangox-$(PANGO_API_VERSION).la \
+ $(GLIB_LIBS) \
+ $(X_LIBS)
+endif
+#########################################################
+
+#########################################################
+if HAVE_XFT
+noinst_PROGRAMS += pangoxft-view
+
+pangoxft_view_SOURCES = \
+ renderdemo.h \
+ renderdemo.c \
+ viewer.h \
+ viewer-x.h \
+ viewer-x.c \
+ viewer-main.c \
+ viewer-pangoxft.c \
+ pangoxft-view.c
+
+pangoxft_view_LDADD = \
+ ../pango/libpango-$(PANGO_API_VERSION).la \
+ ../pango/libpangoft2-$(PANGO_API_VERSION).la \
+ ../pango/libpangoxft-$(PANGO_API_VERSION).la \
+ $(GLIB_LIBS) \
+ $(XFT_LIBS) \
+ $(X_LIBS)
+endif
+#########################################################
+
+#########################################################
+if HAVE_CAIRO
+if HAVE_X
+if HAVE_CAIRO_XLIB
+noinst_PROGRAMS += pangocairo-view
+
+pangocairo_view_SOURCES = \
+ renderdemo.h \
+ renderdemo.c \
+ viewer.h \
+ viewer-cairo.h \
+ viewer-cairo.c \
+ viewer-x.h \
+ viewer-x.c \
+ viewer-main.c \
+ viewer-pangocairo.c \
+ pangocairo-view.c
+
+pangocairo_view_LDADD = \
+ ../pango/libpango-$(PANGO_API_VERSION).la \
+ ../pango/libpangoft2-$(PANGO_API_VERSION).la \
+ ../pango/libpangocairo-$(PANGO_API_VERSION).la \
+ $(GLIB_LIBS) \
+ $(CAIRO_LIBS) \
+ $(X_LIBS)
+endif
+endif
+endif
+#########################################################
+
+#########################################################
+if HAVE_X
+bin_PROGRAMS += pango-view
+pango_view_SOURCES = \
+ renderdemo.h \
+ renderdemo.c \
+ viewer.h \
+ viewer-x.h \
+ viewer-x.c \
+ viewer-main.c \
+ pango-view.c
+pango_view_LDADD = \
+ ../pango/libpango-$(PANGO_API_VERSION).la \
+ $(GLIB_LIBS)
+if HAVE_X
+pango_view_SOURCES += \
+ viewer-pangox.c
+pango_view_LDADD += \
+ ../pango/libpangox-$(PANGO_API_VERSION).la
+endif
+if HAVE_FREETYPE
+pango_view_SOURCES += \
+ viewer-pangoft2.c
+pango_view_LDADD += \
+ ../pango/libpangoft2-$(PANGO_API_VERSION).la \
+ $(FREETYPE_LIBS)
+endif
+if HAVE_XFT
+pango_view_SOURCES += \
+ viewer-pangoxft.c
+pango_view_LDADD += \
+ ../pango/libpangoft2-$(PANGO_API_VERSION).la \
+ ../pango/libpangoxft-$(PANGO_API_VERSION).la \
+ $(XFT_LIBS)
+endif
+if HAVE_CAIRO
+if HAVE_CAIRO_XLIB
+pango_view_SOURCES += \
+ viewer-cairo.h \
+ viewer-cairo.c \
+ viewer-pangocairo.c
+pango_view_LDADD += \
+ ../pango/libpangoft2-$(PANGO_API_VERSION).la \
+ ../pango/libpangocairo-$(PANGO_API_VERSION).la \
+ $(CAIRO_LIBS)
+endif
+endif
+pango_view_LDADD += \
+ $(X_LIBS)
+endif
+#########################################################
+
+BUILT_SOURCES = pangorc
+
+pangorc: $(srcdir)/../modules/pangorc
+ cp $< $@
diff --git a/pango-view/pango-view.c b/pango-view/pango-view.c
new file mode 100644
index 00000000..9771e8cc
--- /dev/null
+++ b/pango-view/pango-view.c
@@ -0,0 +1,23 @@
+#include <config.h>
+#include "viewer.h"
+
+extern const PangoViewer pangocairo_viewer;
+extern const PangoViewer pangoxft_viewer;
+extern const PangoViewer pangoft2_viewer;
+extern const PangoViewer pangox_viewer;
+
+const PangoViewer *viewers[] = {
+#ifdef HAVE_CAIRO_XLIB
+ &pangocairo_viewer,
+#endif
+#ifdef HAVE_XFT
+ &pangoxft_viewer,
+#endif
+#ifdef HAVE_FREETYPE
+ &pangoft2_viewer,
+#endif
+#ifdef HAVE_X
+ &pangox_viewer,
+#endif
+ NULL
+};
diff --git a/pango-view/pangocairo-view.c b/pango-view/pangocairo-view.c
new file mode 100644
index 00000000..c5ba8716
--- /dev/null
+++ b/pango-view/pangocairo-view.c
@@ -0,0 +1,8 @@
+#include "viewer.h"
+
+extern const PangoViewer pangocairo_viewer;
+
+const PangoViewer *viewers[] = {
+ &pangocairo_viewer,
+ NULL
+};
diff --git a/pango-view/pangoft2-view.c b/pango-view/pangoft2-view.c
new file mode 100644
index 00000000..d4ac695c
--- /dev/null
+++ b/pango-view/pangoft2-view.c
@@ -0,0 +1,8 @@
+#include "viewer.h"
+
+extern const PangoViewer pangoft2_viewer;
+
+const PangoViewer *viewers[] = {
+ &pangoft2_viewer,
+ NULL
+};
diff --git a/pango-view/pangox-view.c b/pango-view/pangox-view.c
new file mode 100644
index 00000000..72e97603
--- /dev/null
+++ b/pango-view/pangox-view.c
@@ -0,0 +1,8 @@
+#include "viewer.h"
+
+extern const PangoViewer pangox_viewer;
+
+const PangoViewer *viewers[] = {
+ &pangox_viewer,
+ NULL
+};
diff --git a/pango-view/pangoxft-view.c b/pango-view/pangoxft-view.c
new file mode 100644
index 00000000..bdf893f8
--- /dev/null
+++ b/pango-view/pangoxft-view.c
@@ -0,0 +1,8 @@
+#include "viewer.h"
+
+extern const PangoViewer pangoxft_viewer;
+
+const PangoViewer *viewers[] = {
+ &pangoxft_viewer,
+ NULL
+};
diff --git a/pango-view/renderdemo.c b/pango-view/renderdemo.c
new file mode 100644
index 00000000..ab89b8fe
--- /dev/null
+++ b/pango-view/renderdemo.c
@@ -0,0 +1,676 @@
+/* renderdemo.c: Common code for rendering demos
+ *
+ * Copyright (C) 1999, 2004 Red Hat Software
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <pango/pango.h>
+
+#include "renderdemo.h"
+
+#define DEFAULT_FONT_FAMILY "Sans"
+#define DEFAULT_FONT_SIZE 18
+
+#define _MAKE_FONT_NAME(family, size) family " " #size
+#define MAKE_FONT_NAME(family, size) _MAKE_FONT_NAME(family, size)
+
+const char *prog_name;
+
+gboolean opt_display = TRUE;
+int opt_dpi = 96;
+const char *opt_font = MAKE_FONT_NAME (DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE);
+gboolean opt_header = FALSE;
+const char *opt_output = NULL;
+int opt_margin = 10;
+int opt_markup = FALSE;
+gboolean opt_rtl = FALSE;
+double opt_rotate = 0;
+gboolean opt_auto_dir = TRUE;
+const char *opt_text = NULL;
+gboolean opt_waterfall = FALSE;
+int opt_width = -1;
+int opt_indent = 0;
+int opt_runs = 1;
+PangoEllipsizeMode opt_ellipsize = PANGO_ELLIPSIZE_NONE;
+PangoGravity opt_gravity = PANGO_GRAVITY_SOUTH;
+PangoGravityHint opt_gravity_hint = PANGO_GRAVITY_HINT_NATURAL;
+HintMode opt_hinting = HINT_DEFAULT;
+PangoWrapMode opt_wrap = PANGO_WRAP_WORD_CHAR;
+gboolean opt_wrap_set = FALSE;
+const char *opt_pangorc = NULL;
+const PangoViewer *opt_viewer = NULL;
+
+/* Text (or markup) to render */
+static char *text;
+
+void
+fail (const char *format, ...)
+{
+ const char *msg;
+
+ va_list vap;
+ va_start (vap, format);
+ msg = g_strdup_vprintf (format, vap);
+ g_printerr ("%s: %s\n", prog_name, msg);
+
+ exit (1);
+}
+
+static PangoFontDescription *
+get_font_description (void)
+{
+ PangoFontDescription *font_description = pango_font_description_from_string (opt_font);
+
+ if ((pango_font_description_get_set_fields (font_description) & PANGO_FONT_MASK_FAMILY) == 0)
+ pango_font_description_set_family (font_description, DEFAULT_FONT_FAMILY);
+
+ if ((pango_font_description_get_set_fields (font_description) & PANGO_FONT_MASK_SIZE) == 0)
+ pango_font_description_set_size (font_description, DEFAULT_FONT_SIZE * PANGO_SCALE);
+
+ return font_description;
+}
+
+static PangoLayout *
+make_layout(PangoContext *context,
+ const char *text,
+ double size)
+{
+ static PangoFontDescription *font_description;
+ PangoDirection base_dir;
+ PangoLayout *layout;
+
+ layout = pango_layout_new (context);
+ if (opt_markup)
+ pango_layout_set_markup (layout, text, -1);
+ else
+ pango_layout_set_text (layout, text, -1);
+
+ pango_layout_set_auto_dir (layout, opt_auto_dir);
+ pango_layout_set_ellipsize (layout, opt_ellipsize);
+
+ font_description = get_font_description ();
+ if (size > 0)
+ pango_font_description_set_size (font_description, size * PANGO_SCALE);
+
+ if (opt_width > 0)
+ {
+ pango_layout_set_wrap (layout, opt_wrap);
+ pango_layout_set_width (layout, (opt_width * opt_dpi * PANGO_SCALE + 32) / 72);
+ }
+
+ if (opt_indent != 0)
+ pango_layout_set_indent (layout, (opt_indent * opt_dpi * PANGO_SCALE + 32) / 72);
+
+ base_dir = pango_context_get_base_dir (context);
+ pango_layout_set_alignment (layout,
+ base_dir == PANGO_DIRECTION_LTR ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
+
+ pango_layout_set_font_description (layout, font_description);
+
+ pango_font_description_free (font_description);
+
+ return layout;
+}
+
+gchar *
+get_options_string (void)
+{
+ PangoFontDescription *font_description = get_font_description ();
+ gchar *font_name;
+ gchar *result;
+
+ if (opt_waterfall)
+ pango_font_description_unset_fields (font_description, PANGO_FONT_MASK_SIZE);
+
+ font_name = pango_font_description_to_string (font_description);
+ result = g_strdup_printf ("%s: %s (%d dpi)", opt_viewer->name, font_name, opt_dpi);
+ pango_font_description_free (font_description);
+ g_free (font_name);
+
+ return result;
+}
+
+static void
+output_body (PangoContext *context,
+ const char *text,
+ RenderCallback render_cb,
+ gpointer cb_context,
+ gpointer cb_data,
+ int *width,
+ int *height,
+ gboolean supports_matrix)
+{
+ PangoLayout *layout;
+ PangoRectangle logical_rect;
+ int size, start_size, end_size, increment;
+ int x = 0, y = 0;
+
+ if (!supports_matrix)
+ {
+ const PangoMatrix* matrix;
+ const PangoMatrix identity = PANGO_MATRIX_INIT;
+ matrix = pango_context_get_matrix (context);
+ if (matrix)
+ {
+ x += matrix->x0;
+ y += matrix->y0;
+ }
+ pango_context_set_matrix (context, &identity);
+ }
+
+ if (opt_waterfall)
+ {
+ start_size = 8;
+ end_size = 48;
+ increment = 4;
+ }
+ else
+ {
+ start_size = end_size = -1;
+ increment = 1;
+ }
+
+ *width = 0;
+ *height = 0;
+
+ for (size = start_size; size <= end_size; size += increment)
+ {
+ layout = make_layout (context, text, size);
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+
+ if (render_cb)
+ (*render_cb) (layout, x, y+*height, cb_context, cb_data);
+
+ *width = MAX (*width, PANGO_PIXELS (logical_rect.x + logical_rect.width));
+ *width = MAX (*width, PANGO_PIXELS (pango_layout_get_width (layout)));
+ *height += PANGO_PIXELS (logical_rect.height);
+
+ g_object_unref (layout);
+ }
+}
+
+static void
+set_transform (PangoContext *context,
+ TransformCallback transform_cb,
+ gpointer cb_context,
+ gpointer cb_data,
+ PangoMatrix *matrix)
+{
+ pango_context_set_matrix (context, matrix);
+ if (transform_cb)
+ (*transform_cb) (context, matrix, cb_context, cb_data);
+}
+
+void
+do_output (PangoContext *context,
+ RenderCallback render_cb,
+ TransformCallback transform_cb,
+ gpointer cb_context,
+ gpointer cb_data,
+ int *width_out,
+ int *height_out)
+{
+ PangoLayout *layout;
+ PangoRectangle rect;
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ PangoMatrix *orig_matrix;
+ gboolean supports_matrix;
+ int rotated_width, rotated_height;
+ int x = opt_margin;
+ int y = opt_margin;
+ int width, height;
+
+ width = 0;
+ height = 0;
+
+ orig_matrix = pango_matrix_copy (pango_context_get_matrix (context));
+ /* If the backend sets an all-zero matrix on the context,
+ * means that it doesn't support transformations.
+ */
+ supports_matrix = !orig_matrix ||
+ (orig_matrix->xx != 0. || orig_matrix->xy != 0. ||
+ orig_matrix->yx != 0. || orig_matrix->yy != 0. ||
+ orig_matrix->x0 != 0. || orig_matrix->y0 != 0.);
+
+ set_transform (context, transform_cb, cb_context, cb_data, NULL);
+
+ pango_context_set_language (context, pango_language_get_default ());
+ pango_context_set_base_dir (context,
+ opt_rtl ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR);
+
+ if (opt_header)
+ {
+ char *options_string = get_options_string ();
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
+ layout = make_layout (context, options_string, 10);
+ pango_layout_get_extents (layout, NULL, &rect);
+
+ width = MAX (width, PANGO_PIXELS (rect.width));
+ height += PANGO_PIXELS (rect.height);
+
+ if (render_cb)
+ (*render_cb) (layout, x, y, cb_context, cb_data);
+
+ y += PANGO_PIXELS (rect.height);
+
+ g_object_unref (layout);
+ g_free (options_string);
+ }
+
+ if (opt_rotate != 0)
+ {
+ if (supports_matrix)
+ pango_matrix_rotate (&matrix, opt_rotate);
+ else
+ g_printerr ("The backend does not support rotated text\n");
+ }
+
+ pango_context_set_base_gravity (context, opt_gravity);
+ pango_context_set_gravity_hint (context, opt_gravity_hint);
+
+ set_transform (context, transform_cb, cb_context, cb_data, &matrix);
+
+ output_body (context,
+ text,
+ NULL, NULL, NULL,
+ &rotated_width, &rotated_height,
+ supports_matrix);
+
+ rect.x = rect.y = 0;
+ rect.width = rotated_width;
+ rect.height = rotated_height;
+
+ pango_matrix_transform_pixel_rectangle (&matrix, &rect);
+
+ matrix.x0 = x - rect.x;
+ matrix.y0 = y - rect.y;
+
+ set_transform (context, transform_cb, cb_context, cb_data, &matrix);
+
+ if (render_cb)
+ output_body (context,
+ text,
+ render_cb, cb_context, cb_data,
+ &rotated_width, &rotated_height,
+ supports_matrix);
+
+ width = MAX (width, rect.width);
+ height += rect.height;
+
+ width += 2 * opt_margin;
+ height += 2 * opt_margin;
+
+ if (width_out)
+ *width_out = width;
+ if (height_out)
+ *height_out = height;
+
+ pango_context_set_matrix (context, orig_matrix);
+ pango_matrix_free (orig_matrix);
+}
+
+static gboolean
+parse_enum (GType type,
+ int *value,
+ const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ char *possible_values = NULL;
+ gboolean ret;
+
+ ret = pango_parse_enum (type,
+ arg,
+ value,
+ FALSE,
+ &possible_values);
+
+ if (!ret && error)
+ {
+ g_set_error(error,
+ G_OPTION_ERROR,
+ G_OPTION_ERROR_BAD_VALUE,
+ "Argument for %s must be one of %s",
+ name,
+ possible_values);
+ ret = FALSE;
+ }
+
+ g_free (possible_values);
+
+ return ret;
+}
+
+static gboolean
+parse_ellipsis (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ return parse_enum (PANGO_TYPE_ELLIPSIZE_MODE, &opt_ellipsize,
+ name, arg, data, error);
+}
+
+static gboolean
+parse_gravity (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ return parse_enum (PANGO_TYPE_GRAVITY, &opt_gravity,
+ name, arg, data, error);
+}
+
+static gboolean
+parse_gravity_hint (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ return parse_enum (PANGO_TYPE_GRAVITY_HINT, &opt_gravity_hint,
+ name, arg, data, error);
+}
+
+static gboolean
+parse_hinting (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ gboolean ret = TRUE;
+
+ if (strcmp (arg, "none") == 0)
+ opt_hinting = HINT_NONE;
+ else if (strcmp (arg, "auto") == 0)
+ opt_hinting = HINT_AUTO;
+ else if (strcmp (arg, "full") == 0)
+ opt_hinting = HINT_FULL;
+ else
+ {
+ g_set_error(error,
+ G_OPTION_ERROR,
+ G_OPTION_ERROR_BAD_VALUE,
+ "Argument for --hinting must be one of none/auto/full");
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_wrap (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ gboolean ret;
+ if ((ret = parse_enum (PANGO_TYPE_WRAP_MODE, &opt_wrap,
+ name, arg, data, error)))
+ {
+ opt_wrap_set = TRUE;
+ }
+ return ret;
+}
+
+static gchar *
+backends_to_string (void)
+{
+ GString *backends = g_string_new (NULL);
+ const PangoViewer **viewer;
+
+ for (viewer = viewers; *viewer; viewer++)
+ if ((*viewer)->id)
+ {
+ g_string_append (backends, (*viewer)->id);
+ g_string_append_c (backends, '/');
+ }
+ g_string_truncate (backends, MAX (0, (gint)backends->len - 1));
+
+ return g_string_free(backends,FALSE);
+}
+
+static int
+backends_get_count (void)
+{
+ const PangoViewer **viewer;
+ int i = 0;
+
+ for (viewer = viewers; *viewer; viewer++)
+ if ((*viewer)->id)
+ i++;
+
+ return i;
+}
+
+
+static gchar *
+backend_description (void)
+{
+ GString *description = g_string_new("Pango backend to use for rendering ");
+ int backends_count = backends_get_count ();
+
+ if (backends_count > 1)
+ g_string_append_printf(description,"(default: %s)", (*viewers)->id);
+ else if (backends_count == 1)
+ g_string_append_printf(description,"(only available: %s)", (*viewers)->id);
+ else
+ g_string_append_printf(description,"(no backends found!)");
+
+ return g_string_free(description,FALSE);
+
+}
+
+
+static gboolean
+parse_backend (const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ gboolean ret = TRUE;
+ const PangoViewer **viewer;
+
+ for (viewer = viewers; *viewer; viewer++)
+ if (!g_ascii_strcasecmp ((*viewer)->id, arg))
+ break;
+
+ if (*viewer)
+ opt_viewer = *viewer;
+ else
+ {
+ gchar *backends = backends_to_string ();
+
+ g_set_error(error,
+ G_OPTION_ERROR,
+ G_OPTION_ERROR_BAD_VALUE,
+ "Available --backend options are: %s",
+ backends);
+ g_free(backends);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+static gboolean
+show_version(const char *name,
+ const char *arg,
+ gpointer data,
+ GError **error)
+{
+ g_printf("%s (%s) %s\n", prog_name, PACKAGE_NAME, PACKAGE_VERSION);
+ g_printf("module interface version: %s\n", MODULE_VERSION);
+
+ if (PANGO_VERSION != pango_version())
+ g_printf("\nLinked Pango library has a different version: %s\n", pango_version_string ());
+
+ exit(0);
+}
+
+void
+parse_options (int argc, char *argv[])
+{
+ gchar *backend_options = backends_to_string();
+ GOptionFlags backend_flag = backends_get_count () > 1 ? 0 : G_OPTION_FLAG_HIDDEN;
+ gchar *backend_desc = backend_description ();
+ GOptionEntry entries[] =
+ {
+ {"no-auto-dir", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_auto_dir,
+ "No layout direction according to contents", NULL},
+ {"backend", 0, backend_flag, G_OPTION_ARG_CALLBACK, &parse_backend,
+ backend_desc, backend_options},
+ {"no-display", 'q', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_display,
+ "Do not display (just write to file or whatever)", NULL},
+ {"dpi", 0, 0, G_OPTION_ARG_INT, &opt_dpi,
+ "Set the resolution", "number"},
+ {"ellipsize", 0, 0, G_OPTION_ARG_CALLBACK, &parse_ellipsis,
+ "Ellipsization mode", "start/middle/end"},
+ {"font", 0, 0, G_OPTION_ARG_STRING, &opt_font,
+ "Set the font description", "description"},
+ {"gravity", 0, 0, G_OPTION_ARG_CALLBACK, &parse_gravity,
+ "Base gravity: glyph rotation", "south/east/north/west/auto"},
+ {"gravity-hint", 0, 0, G_OPTION_ARG_CALLBACK, &parse_gravity_hint,
+ "Gravity hint", "natural/strong/line"},
+ {"header", 0, 0, G_OPTION_ARG_NONE, &opt_header,
+ "Display the options in the output", NULL},
+ {"hinting", 0, 0, G_OPTION_ARG_CALLBACK, &parse_hinting,
+ "Hinting style", "none/auto/full"},
+ {"indent", 0, 0, G_OPTION_ARG_INT, &opt_indent,
+ "Width in points to indent paragraphs", "points"},
+ {"margin", 0, 0, G_OPTION_ARG_INT, &opt_margin,
+ "Set the margin on the output in pixels", "pixels"},
+ {"markup", 0, 0, G_OPTION_ARG_NONE, &opt_markup,
+ "Interpret text as Pango markup", NULL},
+ {"output", 'o', 0, G_OPTION_ARG_STRING, &opt_output,
+ "Save rendered image to output file", "file"},
+ {"pangorc", 0, 0, G_OPTION_ARG_STRING, &opt_pangorc,
+ "pangorc file to use (default is ./pangorc)", "file"},
+ {"rtl", 0, 0, G_OPTION_ARG_NONE, &opt_rtl,
+ "Set base direction to right-to-left", NULL},
+ {"rotate", 0, 0, G_OPTION_ARG_DOUBLE, &opt_rotate,
+ "Angle at which to rotate results", "degrees"},
+ {"runs", 'n', 0, G_OPTION_ARG_INT, &opt_runs,
+ "Run Pango layout engine this many times", "integer"},
+ {"text", 't', 0, G_OPTION_ARG_STRING, &opt_text,
+ "Text to display (instead of a file)", "string"},
+ {"version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &show_version,
+ "Show version numbers", NULL},
+ {"waterfall", 0, 0, G_OPTION_ARG_NONE, &opt_waterfall,
+ "Create a waterfall display", NULL},
+ {"width", 'w', 0, G_OPTION_ARG_INT, &opt_width,
+ "Width in points to which to wrap output", "points"},
+ {"wrap", 0, 0, G_OPTION_ARG_CALLBACK, &parse_wrap,
+ "Text wrapping mode (needs a width to be set)", "word/char/word-char"},
+ {NULL}
+ };
+ GError *error = NULL;
+ GError *parse_error = NULL;
+ GOptionContext *context;
+ size_t len;
+
+ prog_name = g_path_get_basename (argv[0]);
+ context = g_option_context_new ("- FILE");
+ g_option_context_add_main_entries (context, entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &parse_error))
+ {
+ if (parse_error != NULL)
+ fail("%s", parse_error->message);
+ else
+ fail("Option parse error");
+ exit(1);
+ }
+ g_option_context_free(context);
+ g_free(backend_options);
+ g_free(backend_desc);
+
+ if ((opt_text && argc != 1) || (!opt_text && argc != 2))
+ {
+ if (opt_text && argc != 1)
+ fail ("When specifying --text, no file should be given");
+
+ g_printerr ("Usage: %s [OPTION...] FILE\n", prog_name);
+ exit (1);
+ }
+
+ /* set up the backend */
+ if (!opt_viewer)
+ {
+ opt_viewer = *viewers;
+ if (!opt_viewer)
+ fail ("No viewer backend found");
+ }
+
+ /* if wrap mode is set then width must be set */
+ if (opt_width < 0 && opt_wrap_set)
+ {
+ g_printerr ("The wrap mode only has effect if a width is set\n");
+ }
+
+ /* Get the text
+ */
+ if (opt_text)
+ {
+ text = g_strdup (opt_text);
+ len = strlen (text);
+ }
+ else
+ {
+ if (!g_file_get_contents (argv[1], &text, &len, &error))
+ fail ("%s\n", error->message);
+ }
+
+ /* Strip one trailing newline
+ */
+ if (len > 0 && text[len - 1] == '\n')
+ len--;
+ if (len > 0 && text[len - 1] == '\r')
+ len--;
+ text[len] = '\0';
+
+ /* Make sure we have valid markup
+ */
+ if (opt_markup &&
+ !pango_parse_markup (text, -1, 0, NULL, NULL, NULL, &error))
+ fail ("Cannot parse input as markup: %s", error->message);
+
+ /* Setup PANGO_RC_FILE
+ */
+ if (!opt_pangorc)
+ if (g_file_test ("./pangorc", G_FILE_TEST_IS_REGULAR))
+ opt_pangorc = "./pangorc";
+ if (opt_pangorc)
+ g_setenv ("PANGO_RC_FILE", opt_pangorc, TRUE);
+}
+
+
+void
+finalize (void)
+{
+ g_free (text);
+}
diff --git a/pango-view/renderdemo.h b/pango-view/renderdemo.h
new file mode 100644
index 00000000..c9d10361
--- /dev/null
+++ b/pango-view/renderdemo.h
@@ -0,0 +1,86 @@
+/* renderdemo.c: Common code for rendering demos
+ *
+ * Copyright (C) 1999, 2004 Red Hat Software
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef RENDERDEMO_H
+#define RENDERDEMO_H
+
+#include <pango/pango-layout.h>
+
+#include "viewer.h"
+
+typedef enum {
+ HINT_DEFAULT,
+ HINT_NONE,
+ HINT_AUTO,
+ HINT_FULL
+} HintMode;
+
+typedef void (*RenderCallback) (PangoLayout *layout,
+ int x,
+ int y,
+ gpointer cb_context,
+ gpointer cb_data);
+typedef void (*TransformCallback) (PangoContext *context,
+ PangoMatrix *transform,
+ gpointer cb_context,
+ gpointer cb_data);
+
+void fail (const char *format, ...) G_GNUC_PRINTF (1, 2) G_GNUC_NORETURN;
+
+void parse_options (int argc,
+ char *argv[]);
+void do_output (PangoContext *context,
+ RenderCallback render_cb,
+ TransformCallback transform_cb,
+ gpointer cb_context,
+ gpointer cb_data,
+ int *width,
+ int *height);
+void finalize (void);
+gchar *get_options_string (void);
+
+extern const char *prog_name;
+
+/* handled by renderdemo.c */
+extern const char *opt_font;
+extern gboolean opt_header;
+extern int opt_margin;
+extern int opt_markup;
+extern gboolean opt_rtl;
+extern double opt_rotate;
+extern gboolean opt_auto_dir;
+extern const char *opt_text;
+extern gboolean opt_waterfall;
+extern int opt_width;
+extern int opt_indent;
+extern PangoEllipsizeMode opt_ellipsize;
+extern const char *opt_pangorc;
+
+/* handled by view.c */
+extern gboolean opt_display;
+extern const char *opt_output;
+extern int opt_runs;
+extern const PangoViewer *opt_viewer;
+
+/* handled by backend-specific code */
+extern int opt_dpi;
+extern HintMode opt_hinting;
+
+#endif /* RENDERDEMO_H */
diff --git a/pango-view/test-arabic.txt b/pango-view/test-arabic.txt
new file mode 100644
index 00000000..58653a6f
--- /dev/null
+++ b/pango-view/test-arabic.txt
@@ -0,0 +1,7 @@
+بِسْمِ ٱللّٰهِ ٱلرَّحْمٰنِ ٱلرَّحِيمِ
+اَلْحَمْدُ لِلّٰهِ رَبِّ الْعَالَمِينَ
+اَلرَّحْمٰنِ الرَّحِيمِ
+مَالِكِ يَوْمِ الدِّينِ
+اِيَّاكَ نَعْبُدُ وَ اِيَّاكَ نَسْتَعِينُ
+اِهْدِنَا الصِّرَاطَ الْمُسْتَقِيمَ
+صِرَاطَ الَّذِينَ اَنْعَمْتَ عَلَيهِمْ غَيْرِ الْمَغْضُوبِ عَلَيْهِم وَ لَا الضَّٓالِّينَ
diff --git a/pango-view/test-chinese.txt b/pango-view/test-chinese.txt
new file mode 100644
index 00000000..d4fb796a
--- /dev/null
+++ b/pango-view/test-chinese.txt
@@ -0,0 +1,7 @@
+你好,这是中文竖排测试。
+欢迎来到中国北京。
+白日依山尽,
+黄河入海流。
+欲穷千里目,
+更上一层楼。
+谢谢!
diff --git a/pango-view/test-devanagari.txt b/pango-view/test-devanagari.txt
new file mode 100644
index 00000000..9cfccc56
--- /dev/null
+++ b/pango-view/test-devanagari.txt
@@ -0,0 +1,9 @@
+कि KI
+किकि KIKI
+क्कि KKI
+क्क्कि KKKI
+क््कि KKI (sp)
+क़्कि KKI (sp)
+क््क्कि KKKI (sp)
+क््क््कि KKKI (sp)
+क़्क़्कि KKKI (sp)
diff --git a/pango-view/test-gurmukhi.txt b/pango-view/test-gurmukhi.txt
new file mode 100644
index 00000000..f3d05920
--- /dev/null
+++ b/pango-view/test-gurmukhi.txt
@@ -0,0 +1,26 @@
+ਹਰੀ ਸਿੰਘ ਨਲੂਆ
+
+ਹਰੀ ਸਿੰਘ ਨਲੂਆ (ਨਲਵਾ)
+
+
+ਸਿੱਖ ਕੌਮ ਦਾ ਅਣਖੀ ਅਤੇ ਬਹਾਦਰ ਜਰਨੈਲ, ਜਿਸ ਦੇ ਨਾਂ ਤੋਂ ਪਠਾਣੀਆਂ ਆਪਣੇ ਬੱਚਿਆਂ ਨੂੰ ਡਰਾਉਦੀਆਂ ਸਨ ਕਿ ਪੁੱਤ ਸੌਂ ਜਾ ਨਹੀਂ ਤਾਂ ਨਲੂਆ ਆ ਜਾਵੇਗਾ।
+
+
+ਵਿਸ਼ਾ-ਸੂਚੀ
+[ਛੁਪਾਓ]
+
+ * ੧ ਜਨਮ ਅਤੇ ਸਿਖਲਾਈ
+ * ੨ ਨਲੂਆ
+ * ੩ ਖਾਲਸਾ ਫੌਜ
+ * ੪ ਕਸ਼ਮੀਰ
+ * ੫ ਜੰਗ ਜਮਰੌਦ
+ * ੬ ਜਾਗੀਰ ਵਾਪਸੀ
+
+ ਜਨਮ ਅਤੇ ਸਿਖਲਾਈ
+
+ਸਰਦਾਰ ਹਰੀ ਸਿੰਘ ਦਾ ਜਨਮ ਗੁੱਜਰਾਵਾਲੇ ਵਿਖੇ ਹੋਇਆ। ਪਿਤਾ ਦੀ ਮੌਤ ਨਿੱਕੀ ਉਮਰ ਵਿੱਚ ਹੋਣ ਉਪਰੰਤ, ਉਹਨਾਂ ਦਾ ਪਾਲਣ ਪੋਸ਼ਣ ਉਹਨਾਂ ਦੇ ਨਾਨਕੇ ਪਰਿਵਾਰ ਵਿੱਚ ਹੋਇਆ।
+
+ਸਰਦਾਰ ਹਰੀ ਸਿੰਘ ਨਲੂਆ ਦੇ ਪਰਿਵਾਰ ਵਿੱਚ ਦੋ ਪਤਨੀਆਂ, ਜਿੰਨ੍ਹਾਂ ਦਾ ਜ਼ੋਰਾਵਰ ਸਿੰਘ ਤੇ ਗੁਰਦਿੱਤ ਸਿੰਘ, ਅਤੇ ਅਰਜਨ ਸਿੰਘ ਤੇ ਪੰਜਾਬ ਸਿੰਘ ਨਾਂ ਦੇ ਚਾਰ ਪੁੱਤਰ ਸਨ। ਚਾਰੇ ਪੁੱਤਰ ਆਪਣੇ ਪਿਓ ਵਾਂਗ ਬਹਾਦਰ ਨਹੀਂ ਸਨ।
+ਇਹਨਾਂ ਕਰਕੇ ਮਹਾਰਾਜਾ ਰਣਜੀਤ ਸਿੰਘ ਨੇ ਅੰਤ ਵਿੱਚ ਸਰਦਾਰ ਹਰੀ ਸਿੰਘ ਦੀ ਸਾਰੀ ਜਾਗੀਰ ਨੂੰ ਵਾਪਸ ਲੈ ਲਈ ਆਪਣੇ ਸਰਦਾਰ ਵਿੱਚ ਵੰਡ ਦਿੱਤੀ।
+ਸਰਦਾਰ ਹਰੀ ਸਿੰਘ ਦੇ ਬਾਅਦ ਇਹਨਾਂ ਕੋਲ 40,000 ਹਜ਼ਾਰ ਦੀ ਸਲਾਨਾ ਜਾਗੀਰ ਅਤੇ 60 ਤੋਂ 70 ਸਵਾਰ ਰਹੇ।
+
diff --git a/pango-view/test-hebrew.txt b/pango-view/test-hebrew.txt
new file mode 100644
index 00000000..15467d87
--- /dev/null
+++ b/pango-view/test-hebrew.txt
@@ -0,0 +1,13 @@
+בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃
+וְהָאָ֗רֶץ הָֽיְתָ֥ה תֹ֨הוּ֙ וָבֹ֔הוּ וְחֹ֖שֶׁךְ עַל־פְּנֵ֣י תְה֑וֹם וְר֣וּחַ אֱלֹהִ֔ים מְרַחֶ֖פֶת עַל־פְּנֵ֥י הַמָּֽיִם׃
+וַיֹּ֥אמֶר אֱלֹהִ֖ים יְהִ֣י א֑וֹר וַֽיְהִי־אֽוֹר׃
+וַיַּ֧רְא אֱלֹהִ֛ים אֶת־הָא֖וֹר כִּי־ט֑וֹב וַיַּבְדֵּ֣ל אֱלֹהִ֔ים בֵּ֥ין הָא֖וֹר וּבֵ֥ין הַחֹֽשֶׁךְ׃
+וַיִּקְרָ֨א אֱלֹהִ֤ים ׀ לָאוֹר֙ י֔וֹם וְלַחֹ֖שֶׁךְ קָ֣רָא לָ֑יְלָה וַֽיְהִי־עֶ֥רֶב וַֽיְהִי־בֹ֖קֶר י֥וֹם אֶחָֽד׃
+וַיֹּ֣אמֶר אֱלֹהִ֔ים יְהִ֥י רָקִ֖יעַ בְּת֣וֹךְ הַמָּ֑יִם וִיהִ֣י מַבְדִּ֔יל בֵּ֥ין מַ֖יִם לָמָֽיִם׃
+וַיַּ֣עַשׂ אֱלֹהִים֮ אֶת־הָֽרָקִיעַ֒ וַיַּבְדֵּ֗ל בֵּ֤ין הַמַּ֨יִם֙ אֲשֶׁר֙ מִתַּ֣חַת לָֽרָקִ֔יעַ וּבֵ֣ין הַמַּ֔יִם אֲשֶׁ֖ר מֵעַ֣ל לָֽרָקִ֑יעַ וַֽיְהִי־כֵֽן׃
+וַיִּקְרָ֧א אֱלֹהִ֛ים לָֽרָקִ֖יעַ שָׁמָ֑יִם וַֽיְהִי־עֶ֥רֶב וַֽיְהִי־בֹ֖קֶר י֥וֹם שֵׁנִֽי׃
+וַיֹּ֣אמֶר אֱלֹהִ֗ים יִקָּו֨וּ הַמַּ֜יִם מִתַּ֤חַת הַשָּׁמַ֨יִם֙ אֶל־מָק֣וֹם אֶחָ֔ד וְתֵֽרָאֶ֖ה הַיַּבָּשָׁ֑ה וַֽיְהִי־כֵֽן׃
+וַיִּקְרָ֨א אֱלֹהִ֤ים ׀ לַיַּבָּשָׁה֙ אֶ֔רֶץ וּלְמִקְוֵ֥ה הַמַּ֖יִם קָרָ֣א יַמִּ֑ים וַיַּ֥רְא אֱלֹהִ֖ים כִּי־טֽוֹב׃
+וַיֹּ֣אמֶר אֱלֹהִ֗ים תַּֽדְשֵׁ֤א הָאָ֨רֶץ֙ דֶּ֗שֶׁא עֵ֚שֶׂב מַזְרִ֣יעַ זֶ֔רַע עֵ֣ץ פְּרִ֞י עֹ֤שֶׂה פְּרִי֙ לְמִינ֔וֹ אֲשֶׁ֥ר זַרְעוֹ־ב֖וֹ עַל־הָאָ֑רֶץ וַֽיְהִי־כֵֽן׃
+וַתּוֹצֵ֨א הָאָ֜רֶץ דֶּ֠שֶׁא עֵ֣שֶׂב מַזְרִ֤יעַ זֶ֨רַע֙ לְמִינֵ֔הוּ וְעֵ֧ץ עֹֽשֶׂה־פְּרִ֛י אֲשֶׁ֥ר זַרְעוֹ־ב֖וֹ לְמִינֵ֑הוּ וַיַּ֥רְא אֱלֹהִ֖ים כִּי־טֽוֹב׃
+וַֽיְהִי־עֶ֥רֶב וַֽיְהִי־בֹ֖קֶר י֥וֹם שְׁלִישִֽׁי׃
diff --git a/pango-view/test-ipa.txt b/pango-view/test-ipa.txt
new file mode 100644
index 00000000..2fdd5e2c
--- /dev/null
+++ b/pango-view/test-ipa.txt
@@ -0,0 +1,8 @@
+n̩ a̩ m̩ w̩ i̩ l̩ j̩̩ ɳ̩ ŋ̩
+n̽ a̽ m̽ w̽ i̽ l̽ j̽ ɳ̽ ŋ̽
+ff fi fl e˥˩ i˦˨˥
+ä̃́ ɛ̃̈̀ ɩ̂́ ɔ̃̂ ʉ̄̈ ɠ̪̥̈
+ŋ̥ n̥ n̪̰
+k͡p m͡i l͡w l͡i m͡w
+
+
diff --git a/pango-view/test-lao.txt b/pango-view/test-lao.txt
new file mode 100644
index 00000000..012025e4
--- /dev/null
+++ b/pango-view/test-lao.txt
@@ -0,0 +1,2 @@
+ເກັບພາບງາມໆມາຝາກໃຫ້ແຟນໆໄດ້ເຫັນເຕັມໆຕາທີ່ມະຫາສານ.ຄອມ
+ ປະຈຸບັນ, ຕ້ອງຍອມຮັບກັນວ່າ ກະແສຕອບຮັບແນວເພງສະຕິງກຳລັງມາແຮງອີ່ຫລີ, ບາງບົດເພງນອກຈາກຈະເປັນທີ່ນິຍົມໃນບ້ານເຮົາ ເມືອງເຮົາແລ້ວ ຍັງຂ້າມຝັ່ງໄປດັງຢູ່ບ້ານເພີ່ນອີກ. ບໍ່ແມ່ນຕັ້ງເວົ້າ ເມື່ອກ່ອນນັກທ່ອງທ່ຽວຊາວຕ່າງຊາດທີ່ເຂົ້າມາທ່ຽວບ້ານເຮົາເພິ່ນມັກຖາມວ່າ ເປັນຫຍັງຄົນລາວຈຶ່ງບໍ່ມັກເປິດເພງລາວໂດຍສະເພາະໃນຮ້ານກິນດື່ມ, ຮ້ານອາຫານ ຫລື ແມ່ນແຕ່ຕາມບ້ານເຮືອນ ແລະ ຕະຫລາດ, ແຕ່ດຽວນີ້ຂໍປະທານໂທດ ເພິ່ນຫັນມາເປີດເພງລາວກັນແລ້ວ ເນື່ອງຈາກສັງຄົມກໍ່ຍອມຮັບ, ບົດເພງກໍ່ມ່ວນ ເນື້ອຫາກໍ່ຖືກໃຈແຖມຍັງເປັນການສົ່ງເສີມໃຫ້ສິລະປິນລາວ ແລະ ຜູ້ຢູ່ເບື້ອງຫລັງມີກຳລັງໃຈພັດທະນາວຽກ ແລະ ຜົນງານຂອງຕົນອີກ... ອີກດ້ານໜື່ງນອກຈານສິລະປິນຈະຕ້ອງບຸກບືນ ເພື່ອໃຫ້ຕົວເອງໄດ້ເຂົ້າມາຢູ່ໃນວົງການແລ້ວ, ຝ່າຍເຈົ້າຂອງຄ້າຍເພງກໍ່ພະຍາຍາມເຟັ້ນຫານັກຮ້ອງສຽງດີ ມີແວວດັງເຂົ້າມາເປັນສະມາຊິກຂອງຄ້າຍເພງຕົນເອງເຊັ່ນກັນ.
diff --git a/pango-view/test-latin.txt b/pango-view/test-latin.txt
new file mode 100644
index 00000000..31fe90bd
--- /dev/null
+++ b/pango-view/test-latin.txt
@@ -0,0 +1,9 @@
+'Twas brillig, and the slithy toves
+Did gyre and gimble in the wabe;
+All mimsy were the borogoves,
+And the mome raths outgrabe.
+
+'Beware the Jabberwock, my son!
+The jaws that bite, the claws that catch!
+Beware the Jubjub bird, and shun
+The frumious Bandersnatch!'
diff --git a/pango-view/test-mixed.txt b/pango-view/test-mixed.txt
new file mode 100644
index 00000000..5c3f1a2f
--- /dev/null
+++ b/pango-view/test-mixed.txt
@@ -0,0 +1,8 @@
+你好,这是中文竖排测试。
+欢迎来到中国北京。
+白日依山尽,
+Roses are Red,
+Grass is Green. 2006
+Arabic is گل‌ها قرمزند،‏
+چمن سبز. ۲۰۰۶
+白日依山尽, 2006
diff --git a/pango-view/test-syriac.txt b/pango-view/test-syriac.txt
new file mode 100644
index 00000000..05fedc7b
--- /dev/null
+++ b/pango-view/test-syriac.txt
@@ -0,0 +1,18 @@
+ܠܫܢܢ
+ܒܝܕܦܪܝܕܐ ܒܢܝܡܝܢ ܐܕܡ
+
+ܐܬܐܡܘܢ ܥܠܝܡܢ ܘܥܠܝܡܬܢ
+ܠܫܢܢ ܡܪܢܝܐ
+ܦܪܝܣܐ ܡܕܘܪܐ ܩܕܡܝܐ
+
+ܠܫܢܢ ܝܠܗ ܐܝܬܘܬܢ
+ܘܬܘܕܝܬܢ ܘܣܦܪܝܘܬܢ
+ܝܠܦܚܠܗ ܒܟܠ ܫܘܒ݂ܗܪܐ
+
+ܡܒܘܥܐ ܗܘܐ ܕܝܘܠܦܢܐ
+ܚܠܝܐ ܒܪܬܡܐ ܘܩܪܝܢܐ
+ܬܓ݂ܐ ܝܠܗ ܠܪܫܢ ܪܡܐ
+
+ܡܠܦܢܢ ܐܢܝ ܓܢܒܪܐ
+ܡܫܘܬܐܣܠܗܘܢ ܡܕܪܫܝܬܐ
+ܡܫܘܬܐܣܠܗܘܢ ܓܘ ܐܡܘܬܐ
diff --git a/pango-view/test-tamil.txt b/pango-view/test-tamil.txt
new file mode 100644
index 00000000..ff080a24
--- /dev/null
+++ b/pango-view/test-tamil.txt
@@ -0,0 +1,13 @@
+முருகன் அல்லது அழகு
+திரு வி.க.
+
+ குமரகுருபரர்
+
+உலகு குளிர எமது மதியில் ஒழுகு மமுத கிரணமே
+ உருகு மடிய ரிதய நெகிழ உணர்வி லெழுந லுதயமே
+கலையு நிறைவு மறிவு முதிர முதிரு மதுர நறவமே
+ கழுவு துகளர் முழுக நெடிய கருணை பெருகு சலதியே
+அலகில் புவன முடியும் வெளியில் அளியு மொளியி னிலயமே
+ அறிவு ளறிவை யறிவு மவரும் அறிய வரிய பிரமமே
+மலையின் மகள்கண் மணியை யனைய மதலை வருக வருகவே
+ வளமை தழுவு பரிதி புரியின் மருவு குமரன் வருகவே
diff --git a/pango-view/test-thai.txt b/pango-view/test-thai.txt
new file mode 100644
index 00000000..4bb8d2e0
--- /dev/null
+++ b/pango-view/test-thai.txt
@@ -0,0 +1,11 @@
+ลำดับนั้น เทวดากล่าวคาถากะพระมหาสัตว์ว่า:
+
+“การงานอันใด ยังไม่ถึงที่สุดด้วยความพยายาม การงานอันนั้นก็ไร้ผล มีความลำบากเกิดขึ้น การทำความพยายามในฐานะอันไม่สมควรใด จนความตายปรากฏขึ้น ความพยายามในฐานะอันไม่สมควรนั้น จะมีประโยชน์อะไร”
+
+เมื่อนางมณีเมขลากล่าวอย่างนี้แล้ว พระมหาสัตว์เมื่อจะทำนางมณีเมขลาให้จำนนต่อถ้อยคำ จึงได้ตรัสคาถาต่อไปว่า:
+
+“ดูก่อนเทวดา ผู้ใดรู้แจ้งการงานที่ทำจะไม่ลุล่วงไปได้จริง ๆ ชื่อว่าไม่รักษาชีวิตของตน ถ้าผู้นั้นละความเพียรในฐานะเช่นนั้นเสีย ก็จะพึงรู้ผลแห่งความเกียจคร้าน ดูก่อนเทวดา คนบางพวกในโลกนี้เห็นผลแห่งความประสงค์ของตน จึงประกอบการงานทั้งหลาย การงานเหล่านั้นจะสำเร็จหรือไม่ก็ตาม ดูก่อนเทวดา ท่านก็เห็นผลแห่งกรรมประจักษ์แก่ตนแล้วมิใช่หรือ คนอื่น ๆ จมในมหาสมุทรหมด เราคนเดียวยังว่ายข้ามอยู่ และได้เห็น ท่าน มาสถิตอยู่ใกล้ ๆ เรา เรานั้นจักพยายามตามสติกำลัง จักทำความเพียรที่บุรุษควรทำ ไปให้ถึงฝั่งแห่งมหาสมุทร”
+
+--
+พระมหาชนก
+พระราชนิพนธ์ พระบาทสมเด็จพระเจ้าอยู่หัว ภูมิพลอดุลยเดชฯ
diff --git a/pango-view/test-tibetan.txt b/pango-view/test-tibetan.txt
new file mode 100644
index 00000000..83d44aab
--- /dev/null
+++ b/pango-view/test-tibetan.txt
@@ -0,0 +1,12 @@
+Regular letters འབྲུག་རྒྱལ་ཁབ་འདི་དགའ་ཏོག་ཏོ་ཡོད།
+Reordering of Digits ༡༿༢༿༣༿ Illegal ཀ༿ སྐ༿༾
+Digits with other combining marks ༡༾༢༘༤༥༦ Illegal ཀ༘ཁ༙སྐ༘༙
+Tsa phru after base ཀ༹ Illegal ཀྱུ༹ ཀི༹
+Tsa phru after subjoined སྐ༹ རྒྱ༹
+A-Chung ཀཱ ཀྲཱ གླཱ གྱཱ༹ Illegal ཀཱུ ཀཱི
+Halanta ཀ྄ ཀ྄ཱ སྐ྄ སྐྱ྄
+Vowels ཀྱུ སྐྱིུ ཀྀ ཀེ ཀོ ལྐཻ ཀཽ
+Anusvara ཀུཾ ཀིཾ ཀཾི ཀིཾ ཀཾིཾ
+Visaraga ཀཿ Illegal ཀ༵ཿ
+Lower Stress Mark ཀ༷ ཀཱ༵
+Candrabindu ཀྃ ཀིྃ Illegal ཀིྃ
diff --git a/pango-view/viewer-cairo.c b/pango-view/viewer-cairo.c
new file mode 100644
index 00000000..baabe2dc
--- /dev/null
+++ b/pango-view/viewer-cairo.c
@@ -0,0 +1,53 @@
+/* viewer-cairo.c: Common code for Cairo-based viewers
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+
+#include "viewer-cairo.h"
+
+#ifdef HAVE_CAIRO_XLIB
+#include "viewer-x.h"
+#include <cairo-xlib.h>
+
+static cairo_surface_t *
+cairo_x_view_create_surface (gpointer instance,
+ gpointer surface,
+ int width,
+ int height)
+{
+ XViewer *x = (XViewer *)instance;
+ Drawable drawable = (Drawable) surface;
+
+ return cairo_xlib_surface_create (x->display, drawable,
+ DefaultVisual (x->display, x->screen),
+ width, height);
+}
+
+static CairoViewerIface cairo_x_viewer_iface = {
+ &x_viewer,
+ cairo_x_view_create_surface
+};
+
+const CairoViewerIface *
+get_default_cairo_viewer_iface (void)
+{
+ return &cairo_x_viewer_iface;
+}
+#endif /* HAVE_CAIRO_XLIB */
diff --git a/pango-view/viewer-cairo.h b/pango-view/viewer-cairo.h
new file mode 100644
index 00000000..6e2adb84
--- /dev/null
+++ b/pango-view/viewer-cairo.h
@@ -0,0 +1,42 @@
+/* viewer-cairo.h: Common headers for Cairo-based viewers
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef VIEWER_CAIRO_H
+#define VIEWER_CAIRO_H
+
+#include <cairo.h>
+
+#include "viewer.h"
+
+typedef struct _CairoViewerIface CairoViewerIface;
+
+struct _CairoViewerIface
+{
+ const PangoViewer *backend_class;
+
+ cairo_surface_t * (*create_surface) (gpointer instance,
+ gpointer surface,
+ int width,
+ int height);
+};
+
+const CairoViewerIface *get_default_cairo_viewer_iface (void);
+
+#endif /* VIEWER_CAIRO_H */
diff --git a/pango-view/viewer-main.c b/pango-view/viewer-main.c
new file mode 100644
index 00000000..9dc7cc88
--- /dev/null
+++ b/pango-view/viewer-main.c
@@ -0,0 +1,162 @@
+/* viewer-main.c: Main routine for viewers
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#ifdef G_OS_UNIX
+#include <sys/wait.h>
+#endif
+
+#include "viewer.h"
+#include "renderdemo.h"
+
+int
+main (int argc,
+ char **argv)
+{
+ const PangoViewer *view;
+ gpointer instance;
+ PangoContext *context;
+ int run;
+ int width, height;
+ gpointer surface;
+
+ g_type_init();
+ setlocale (LC_ALL, "");
+ parse_options (argc, argv);
+
+ view = opt_viewer;
+
+ g_assert (view->id);
+
+ instance = view->create (view);
+ context = view->get_context (instance);
+ do_output (context, NULL, NULL, NULL, NULL, &width, &height);
+ surface = view->create_surface (instance, width, height);
+ for (run = 0; run < MAX(1,opt_runs); run++)
+ view->render (instance, surface, context, width, height, NULL);
+
+ if (opt_output)
+ {
+ if (!view->write)
+ fail ("%s viewer backend does not support writing", view->name);
+ else
+ {
+ FILE *stream;
+
+ if (view->write_suffix && g_str_has_suffix (opt_output, view->write_suffix))
+ {
+ stream = g_fopen (opt_output, "wb");
+ if (!stream)
+ fail ("Cannot open output file %s: %s\n",
+ opt_output, g_strerror (errno));
+ }
+ else
+ {
+ int fd;
+ const gchar *convert_argv[4] = {"convert", "-", "%s"};
+ GError *error;
+
+ convert_argv[2] = opt_output;
+
+ if (!g_spawn_async_with_pipes (NULL, (gchar **)convert_argv, NULL,
+ G_SPAWN_SEARCH_PATH |
+ G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL, NULL, NULL, &fd, NULL, NULL, &error))
+ fail ("When running ImageMagick 'convert' command: %s\n", error->message);
+ stream = fdopen (fd, "wb");
+ }
+ view->write (instance, surface, stream, width, height);
+ fclose (stream);
+ }
+ }
+
+ if (opt_display)
+ {
+ char *title;
+ title = get_options_string ();
+
+ if (view->display)
+ {
+ gpointer window = NULL;
+ gpointer state = NULL;
+
+ if (view->create_window)
+ window = view->create_window (instance, title, width, height);
+
+ while (1)
+ {
+ state = view->display (instance, surface, window, width, height, state);
+ if (!state)
+ break;
+
+ view->render (instance, surface, context, width, height, state);
+ }
+
+ if (view->destroy_window)
+ view->destroy_window (instance, window);
+ }
+ else
+ {
+ int fd;
+ FILE *stream;
+ const gchar *display_argv[5] = {"display", "-title", "%s", "-"};
+ GError *error = NULL;
+ GPid pid;
+
+ if (!view->write)
+ fail ("%s viewer backend does not support displaying or writing", view->name);
+ display_argv[2] = title;
+
+ if (!g_spawn_async_with_pipes (NULL, (gchar **)display_argv, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD |
+ G_SPAWN_SEARCH_PATH |
+ G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL, NULL, &pid, &fd, NULL, NULL, &error))
+ fail ("When running ImageMagick 'display' command: %s\n", error->message);
+ stream = fdopen (fd, "wb");
+ view->write (instance, surface, stream, width, height);
+ fclose (stream);
+#ifdef G_OS_UNIX
+ waitpid (pid, NULL, 0);
+#endif
+ g_spawn_close_pid (pid);
+ }
+
+ g_free (title);
+ }
+
+ view->destroy_surface (instance, surface);
+ g_object_unref (context);
+ view->destroy (instance);
+ finalize ();
+ return 0;
+}
diff --git a/pango-view/viewer-pangocairo.c b/pango-view/viewer-pangocairo.c
new file mode 100644
index 00000000..16c6d8bf
--- /dev/null
+++ b/pango-view/viewer-pangocairo.c
@@ -0,0 +1,425 @@
+/* viewer-pangocairo.c: PangoCairo viewer backend.
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "renderdemo.h"
+#include "viewer-cairo.h"
+
+#include <pango/pangocairo.h>
+
+typedef struct
+{
+ const CairoViewerIface *iface;
+
+ gpointer backend;
+
+ PangoFontMap *fontmap;
+ cairo_font_options_t *font_options;
+} CairoViewer;
+
+/* TODO: hinting */
+static gpointer
+pangocairo_view_create (const PangoViewer *klass)
+{
+ CairoViewer *instance;
+
+ instance = g_slice_new (CairoViewer);
+
+ instance->iface = get_default_cairo_viewer_iface ();
+ instance->backend = instance->iface->backend_class->create (instance->iface->backend_class);
+
+ instance->fontmap = pango_cairo_font_map_get_default ();
+ pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (instance->fontmap), opt_dpi);
+
+ instance->font_options = cairo_font_options_create ();
+ if (opt_hinting != HINT_DEFAULT)
+ {
+ cairo_font_options_set_hint_metrics (instance->font_options, CAIRO_HINT_METRICS_ON);
+
+ if (opt_hinting == HINT_NONE)
+ cairo_font_options_set_hint_style (instance->font_options, CAIRO_HINT_STYLE_NONE);
+ else if (opt_hinting == HINT_FULL)
+ cairo_font_options_set_hint_style (instance->font_options, CAIRO_HINT_STYLE_FULL);
+ }
+
+ return instance;
+}
+
+static void
+pangocairo_view_destroy (gpointer instance)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+
+ cairo_font_options_destroy (c->font_options);
+
+ g_object_unref (c->fontmap);
+
+ c->iface->backend_class->destroy (c->backend);
+
+ g_slice_free (CairoViewer, c);
+}
+
+static PangoContext *
+pangocairo_view_get_context (gpointer instance)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+ PangoContext *context;
+
+ context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (c->fontmap));
+ pango_cairo_context_set_font_options (context, c->font_options);
+
+ return context;
+}
+
+typedef struct
+{
+ gpointer backend;
+
+ cairo_surface_t *cairo;
+} CairoSurface;
+
+static gpointer
+pangocairo_view_create_surface (gpointer instance,
+ int width,
+ int height)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+ CairoSurface *surface;
+
+ surface = g_slice_new (CairoSurface);
+
+ surface->backend = c->iface->backend_class->create_surface (c->backend,
+ width, height);
+
+ surface->cairo = c->iface->create_surface (c->backend,
+ surface->backend,
+ width, height);
+
+ return surface;
+}
+
+static void
+pangocairo_view_destroy_surface (gpointer instance,
+ gpointer surface)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+ CairoSurface *c_surface = (CairoSurface *) surface;
+
+ c->iface->backend_class->destroy_surface (c->backend, c_surface->backend);
+ cairo_surface_destroy (c_surface->cairo);
+
+ g_slice_free (CairoSurface, surface);
+}
+
+static void
+render_callback (PangoLayout *layout,
+ int x,
+ int y,
+ gpointer context,
+ gpointer data)
+{
+ cairo_t *cr = (cairo_t *) context;
+ gboolean show_borders = GPOINTER_TO_UINT (data) == 0xdeadbeef;
+
+ cairo_save (cr);
+ cairo_translate (cr, x, y);
+
+ if (show_borders)
+ {
+ cairo_pattern_t *pattern;
+ PangoRectangle ink, logical;
+ double lw = cairo_get_line_width (cr);
+ PangoLayoutIter* iter;
+
+ pango_layout_get_extents (layout, &ink, &logical);
+
+ /* draw resolved gravity "roof" in blue */
+ cairo_save (cr);
+ cairo_translate (cr,
+ (double)logical.x / PANGO_SCALE,
+ (double)logical.y / PANGO_SCALE);
+ cairo_scale (cr,
+ (double)logical.width / PANGO_SCALE * 0.5,
+ (double)logical.height / PANGO_SCALE * 0.5);
+ cairo_translate (cr, 1.0, 1.0);
+ cairo_rotate (cr,
+ pango_gravity_to_rotation (
+ pango_context_get_base_gravity (
+ pango_layout_get_context (layout))));
+ cairo_move_to (cr, -1.0, -1.0);
+ cairo_rel_line_to (cr, +1.0, -0.2); /* / */
+ cairo_rel_line_to (cr, +1.0, +0.2); /* \ */
+ cairo_close_path (cr); /* - */
+ pattern = cairo_pattern_create_linear (0, -1.0, 0, -1.2);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 1.0, 0.0);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 0.0, 1.0, 0.15);
+ cairo_set_source (cr, pattern);
+ cairo_fill (cr);
+ /* once more, without close_path this time */
+ cairo_move_to (cr, -1.0, -1.0);
+ cairo_rel_line_to (cr, +1.0, -0.2); /* / */
+ cairo_rel_line_to (cr, +1.0, +0.2); /* \ */
+ /* silly line_width is not locked :(. get rid of scale. */
+ cairo_restore (cr);
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.7, 0.2);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+
+ /* draw block progression arrow in green */
+ cairo_save (cr);
+ cairo_translate (cr,
+ (double)logical.x / PANGO_SCALE,
+ (double)logical.y / PANGO_SCALE);
+ cairo_scale (cr,
+ (double)logical.width / PANGO_SCALE * 0.5,
+ (double)logical.height / PANGO_SCALE * 0.5);
+ cairo_translate (cr, 1.0, 1.0);
+ cairo_move_to (cr, -0.4, -0.7);
+ cairo_rel_line_to (cr, +0.8, 0.0); /* -- */
+ cairo_rel_line_to (cr, 0.0, +0.9); /* | */
+ cairo_rel_line_to (cr, +0.4, 0.0); /* - */
+ cairo_rel_line_to (cr, -0.8, +0.5); /* / */
+ cairo_rel_line_to (cr, -0.8, -0.5); /* \ */
+ cairo_rel_line_to (cr, +0.4, 0.0); /* - */
+ cairo_close_path (cr); /* | */
+ pattern = cairo_pattern_create_linear (0, -0.7, 0, 0.7);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 1.0, 0.0, 0.0);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 1.0, 0.0, 0.15);
+ cairo_set_source (cr, pattern);
+ cairo_fill_preserve (cr);
+ /* silly line_width is not locked :(. get rid of scale. */
+ cairo_restore (cr);
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 0.7, 0.0, 0.2);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ /* draw baselines with line direction arrow in orange */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 1.0, 0.5, 0.0, 0.5);
+ iter = pango_layout_get_iter (layout);
+ do
+ {
+ PangoLayoutLine *line = pango_layout_iter_get_line (iter);
+ double width = (double)logical.width / PANGO_SCALE;
+
+ y = pango_layout_iter_get_baseline (iter);
+ cairo_save (cr);
+ cairo_translate (cr,
+ (double)logical.x / PANGO_SCALE + width * 0.5,
+ (double)y / PANGO_SCALE);
+ if (line->resolved_dir)
+ cairo_scale (cr, -1, 1);
+ cairo_move_to (cr, -width * .5, -lw*0.2);
+ cairo_rel_line_to (cr, +width * .9, -lw*0.3);
+ cairo_rel_line_to (cr, 0, -lw);
+ cairo_rel_line_to (cr, +width * .1, +lw*1.5);
+ cairo_rel_line_to (cr, -width * .1, +lw*1.5);
+ cairo_rel_line_to (cr, 0, -lw);
+ cairo_rel_line_to (cr, -width * .9, -lw*0.3);
+ cairo_close_path (cr);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+ while (pango_layout_iter_next_line (iter));
+ pango_layout_iter_free (iter);
+ cairo_restore (cr);
+
+ /* draw the logical rect in red */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
+ cairo_rectangle (cr,
+ (double)logical.x / PANGO_SCALE - lw / 2,
+ (double)logical.y / PANGO_SCALE - lw / 2,
+ (double)logical.width / PANGO_SCALE + lw,
+ (double)logical.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ /* draw the ink rect in green */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 0.5);
+ cairo_rectangle (cr,
+ (double)ink.x / PANGO_SCALE - lw / 2,
+ (double)ink.y / PANGO_SCALE - lw / 2,
+ (double)ink.width / PANGO_SCALE + lw,
+ (double)ink.height / PANGO_SCALE + lw);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ pango_cairo_show_layout (cr, layout);
+
+ cairo_restore (cr);
+}
+
+static void
+transform_callback (PangoContext *context,
+ PangoMatrix *matrix,
+ gpointer cr_context,
+ gpointer state)
+{
+ cairo_t *cr = (cairo_t *)cr_context;
+ cairo_matrix_t cairo_matrix;
+
+ if (matrix)
+ {
+ cairo_matrix.xx = matrix->xx;
+ cairo_matrix.yx = matrix->yx;
+ cairo_matrix.xy = matrix->xy;
+ cairo_matrix.yy = matrix->yy;
+ cairo_matrix.x0 = matrix->x0;
+ cairo_matrix.y0 = matrix->y0;
+ }
+ else
+ {
+ cairo_matrix_init_identity (&cairo_matrix);
+ }
+
+ cairo_set_matrix (cr, &cairo_matrix);
+
+ pango_cairo_update_context (cr, context);
+}
+
+static void
+pangocairo_view_render (gpointer instance,
+ gpointer surface,
+ PangoContext *context,
+ int width,
+ int height,
+ gpointer state)
+{
+ cairo_t *cr;
+ CairoSurface *c_surface = (CairoSurface *) surface;
+
+ if (!surface)
+ {
+ cairo_surface_t *cs;
+ /* This is annoying ... we have to create a temporary surface just to
+ * get the extents of the text.
+ */
+ cs = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
+ cr = cairo_create (cs);
+ cairo_surface_destroy (cs);
+ }
+ else
+ cr = cairo_create (c_surface->cairo);
+
+ transform_callback (context, NULL, cr, state);
+
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_paint (cr);
+
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ do_output (context, render_callback, transform_callback, cr, state, NULL, NULL);
+
+ cairo_destroy (cr);
+}
+
+#ifdef HAVE_CAIRO_PNG
+static cairo_status_t
+write_func (void *closure,
+ const unsigned char *data,
+ unsigned int length)
+{
+ FILE *stream = (FILE *) closure;
+ unsigned int l;
+
+ l = fwrite (data, 1, length, stream);
+
+ return l == length ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR;
+}
+
+static void
+pangocairo_view_write (gpointer instance,
+ gpointer surface,
+ FILE *stream,
+ int width,
+ int height)
+{
+ CairoSurface *c_surface = (CairoSurface *) surface;
+
+ cairo_surface_write_to_png_stream (c_surface->cairo, write_func, stream);
+}
+#endif
+
+static gpointer
+pangocairo_view_create_window (gpointer instance,
+ const char *title,
+ int width,
+ int height)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+
+ return c->iface->backend_class->create_window (c->backend,
+ title,
+ width, height);
+}
+
+static void
+pangocairo_view_destroy_window (gpointer instance,
+ gpointer window)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+
+ c->iface->backend_class->destroy_window (c->backend,
+ window);
+}
+
+static gpointer
+pangocairo_view_display (gpointer instance,
+ gpointer surface,
+ gpointer window,
+ int width, int height,
+ gpointer state)
+{
+ CairoViewer *c = (CairoViewer *) instance;
+ CairoSurface *c_surface = (CairoSurface *) surface;
+
+ return c->iface->backend_class->display (c->backend,
+ c_surface->backend,
+ window,
+ width, height,
+ state);
+}
+
+const PangoViewer pangocairo_viewer = {
+ "PangoCairo",
+ "cairo",
+ NULL,
+ pangocairo_view_create,
+ pangocairo_view_destroy,
+ pangocairo_view_get_context,
+ pangocairo_view_create_surface,
+ pangocairo_view_destroy_surface,
+ pangocairo_view_render,
+#ifdef HAVE_CAIRO_PNG
+ pangocairo_view_write,
+#else
+ NULL,
+#endif
+ pangocairo_view_create_window,
+ pangocairo_view_destroy_window,
+ pangocairo_view_display
+};
diff --git a/pango-view/viewer-pangoft2.c b/pango-view/viewer-pangoft2.c
new file mode 100644
index 00000000..bf73fb50
--- /dev/null
+++ b/pango-view/viewer-pangoft2.c
@@ -0,0 +1,162 @@
+/* viewer-pangoft2.c: PangoFT2 viewer backend.
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "renderdemo.h"
+#include "viewer.h"
+
+#include <pango/pangoft2.h>
+
+static void
+substitute_func (FcPattern *pattern,
+ gpointer data)
+{
+ if (opt_hinting != HINT_DEFAULT)
+ {
+ FcPatternDel (pattern, FC_HINTING);
+ FcPatternAddBool (pattern, FC_HINTING, opt_hinting != HINT_NONE);
+
+ FcPatternDel (pattern, FC_AUTOHINT);
+ FcPatternAddBool (pattern, FC_AUTOHINT, opt_hinting == HINT_AUTO);
+ }
+}
+
+static gpointer
+pangoft2_view_create (const PangoViewer *klass)
+{
+ PangoFontMap *fontmap;
+ fontmap = pango_ft2_font_map_new ();
+
+ pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (fontmap), opt_dpi, opt_dpi);
+ pango_ft2_font_map_set_default_substitute (PANGO_FT2_FONT_MAP (fontmap), substitute_func, NULL, NULL);
+
+ return fontmap;
+}
+
+static void
+pangoft2_view_destroy (gpointer instance)
+{
+ g_object_unref (instance);
+}
+
+static PangoContext *
+pangoft2_view_get_context (gpointer instance)
+{
+ return pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (instance));
+}
+
+static gpointer
+pangoft2_view_create_surface (gpointer instance,
+ int width,
+ int height)
+{
+ FT_Bitmap *bitmap;
+
+ bitmap = g_slice_new (FT_Bitmap);
+ bitmap->width = width;
+ bitmap->pitch = (bitmap->width + 3) & ~3;
+ bitmap->rows = height;
+ bitmap->buffer = g_malloc (bitmap->pitch * bitmap->rows);
+ bitmap->num_grays = 256;
+ bitmap->pixel_mode = ft_pixel_mode_grays;
+ memset (bitmap->buffer, 0x00, bitmap->pitch * bitmap->rows);
+
+ return bitmap;
+}
+
+static void
+pangoft2_view_destroy_surface (gpointer instance,
+ gpointer surface)
+{
+ FT_Bitmap *bitmap = (FT_Bitmap *) surface;
+
+ g_free (bitmap->buffer);
+ g_slice_free (FT_Bitmap, bitmap);
+}
+
+static void
+render_callback (PangoLayout *layout,
+ int x,
+ int y,
+ gpointer context,
+ gpointer state)
+{
+ pango_ft2_render_layout ((FT_Bitmap *)context,
+ layout,
+ x, y);
+}
+
+static void
+pangoft2_view_render (gpointer instance,
+ gpointer surface,
+ PangoContext *context,
+ int width,
+ int height,
+ gpointer state)
+{
+ int pix_idx;
+ FT_Bitmap *bitmap = (FT_Bitmap *) surface;
+
+ do_output (context, render_callback, NULL, surface, state, NULL, NULL);
+
+ for (pix_idx=0; pix_idx<bitmap->pitch * bitmap->rows; pix_idx++)
+ bitmap->buffer[pix_idx] = 255 - bitmap->buffer[pix_idx];
+}
+
+static void
+pangoft2_view_write (gpointer instance,
+ gpointer surface,
+ FILE *stream,
+ int width,
+ int height)
+{
+ int row;
+ FT_Bitmap *bitmap = (FT_Bitmap *) surface;
+
+ /* Write it as pgm to output */
+ fprintf(stream,
+ "P5\n"
+ "%d %d\n"
+ "255\n", width, height);
+ for (row = 0; row < height; row++)
+ fwrite(bitmap->buffer + row * bitmap->pitch, 1, width, stream);
+}
+
+const PangoViewer pangoft2_viewer = {
+ "PangoFT2",
+ "ft2",
+ ".pgm",
+ pangoft2_view_create,
+ pangoft2_view_destroy,
+ pangoft2_view_get_context,
+ pangoft2_view_create_surface,
+ pangoft2_view_destroy_surface,
+ pangoft2_view_render,
+ pangoft2_view_write,
+ NULL,
+ NULL,
+ NULL
+};
diff --git a/pango-view/viewer-pangox.c b/pango-view/viewer-pangox.c
new file mode 100644
index 00000000..f3a88e67
--- /dev/null
+++ b/pango-view/viewer-pangox.c
@@ -0,0 +1,122 @@
+/* viewer-pangox.c: PangoX viewer backend.
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+
+#include "renderdemo.h"
+#include "viewer-x.h"
+
+#include <pango/pangox.h>
+
+static void
+pangox_view_destroy (gpointer instance)
+{
+ XViewer *x = (XViewer *)instance;
+
+ pango_x_shutdown_display (x->display);
+
+ x_view_destroy (instance);
+}
+
+static PangoContext *
+pangox_view_get_context (gpointer instance)
+{
+ XViewer *x = (XViewer *) instance;
+ PangoContext *context;
+ PangoMatrix matrix = {0., 0., 0., 0., 0., 0.};
+
+ context = pango_x_get_context (x->display);
+
+ /* We set an all-zero matrix on the context, to negotiate that
+ * this backend doesn't support transformations.
+ */
+ pango_context_set_matrix (context, &matrix);
+
+ return context;
+}
+
+typedef struct
+{
+ XViewer *x;
+ Drawable drawable;
+ GC gc;
+} MyXContext;
+
+static void
+render_callback (PangoLayout *layout,
+ int x,
+ int y,
+ gpointer context,
+ gpointer state)
+{
+ MyXContext *x_context = (MyXContext *) context;
+
+ pango_x_render_layout (x_context->x->display,
+ x_context->drawable,
+ x_context->gc,
+ layout,
+ x, y);
+}
+
+static void
+pangox_view_render (gpointer instance,
+ gpointer surface,
+ PangoContext *context,
+ int width,
+ int height,
+ gpointer state)
+{
+ XViewer *x = (XViewer *) instance;
+ Pixmap pixmap = (Pixmap) surface;
+ GC gc;
+ MyXContext x_context;
+
+ gc = XCreateGC (x->display, pixmap, 0, NULL);
+
+ XSetForeground(x->display, gc, WhitePixel(x->display, x->screen));
+ XFillRectangle (x->display, pixmap, gc, 0, 0, width, height);
+
+ x_context.x = x;
+ x_context.drawable = pixmap;
+ x_context.gc = gc;
+
+ XSetForeground(x->display, gc, BlackPixel(x->display, x->screen));
+ do_output (context, render_callback, NULL, &x_context, state, NULL, NULL);
+
+ XFlush(x->display);
+
+ XFreeGC (x->display, gc);
+}
+
+const PangoViewer pangox_viewer = {
+ "PangoX",
+ "x",
+ NULL,
+ x_view_create,
+ pangox_view_destroy,
+ pangox_view_get_context,
+ x_view_create_surface,
+ x_view_destroy_surface,
+ pangox_view_render,
+ NULL,
+ x_view_create_window,
+ x_view_destroy_window,
+ x_view_display
+};
diff --git a/pango-view/viewer-pangoxft.c b/pango-view/viewer-pangoxft.c
new file mode 100644
index 00000000..8b308167
--- /dev/null
+++ b/pango-view/viewer-pangoxft.c
@@ -0,0 +1,151 @@
+/* viewer-pangoxft.c: PangoXft viewer backend.
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+
+#include "renderdemo.h"
+#include "viewer-x.h"
+
+#include <pango/pangoxft.h>
+
+static void
+default_substitute (FcPattern *pattern,
+ gpointer data)
+{
+ FcPatternDel (pattern, FC_DPI);
+ FcPatternAddInteger (pattern, FC_DPI, opt_dpi);
+
+ if (opt_hinting != HINT_DEFAULT)
+ {
+ FcPatternDel (pattern, FC_HINTING);
+ FcPatternAddBool (pattern, FC_HINTING, opt_hinting != HINT_NONE);
+
+ FcPatternDel (pattern, FC_AUTOHINT);
+ FcPatternAddBool (pattern, FC_AUTOHINT, opt_hinting == HINT_AUTO);
+ }
+}
+
+static gpointer
+pangoxft_view_create (const PangoViewer *klass)
+{
+ XViewer *instance;
+
+ instance = x_view_create (klass);
+
+ XftInit (NULL);
+
+ pango_xft_set_default_substitute (instance->display, instance->screen,
+ default_substitute, NULL, NULL);
+
+ return instance;
+}
+
+static void
+pangoxft_view_destroy (gpointer instance)
+{
+ XViewer *x = (XViewer *)instance;
+
+ pango_xft_shutdown_display (x->display, x->screen);
+
+ x_view_destroy (instance);
+}
+
+static PangoContext *
+pangoxft_view_get_context (gpointer instance)
+{
+ XViewer *x = (XViewer *) instance;
+
+ return pango_xft_get_context (x->display, x->screen);
+}
+
+typedef struct
+{
+ XftDraw *draw;
+ XftColor color;
+} MyXftContext;
+
+static void
+render_callback (PangoLayout *layout,
+ int x,
+ int y,
+ gpointer context,
+ gpointer state)
+{
+ MyXftContext *xft_context = (MyXftContext *) context;
+
+ pango_xft_render_layout (xft_context->draw,
+ &xft_context->color,
+ layout,
+ x * PANGO_SCALE, y * PANGO_SCALE);
+}
+
+static void
+pangoxft_view_render (gpointer instance,
+ gpointer surface,
+ PangoContext *context,
+ int width,
+ int height,
+ gpointer state)
+{
+ XViewer *x = (XViewer *) instance;
+ Pixmap pixmap = (Pixmap) surface;
+ MyXftContext xft_context;
+ XftDraw *draw;
+ XftColor color;
+
+ draw = XftDrawCreate (x->display, pixmap,
+ DefaultVisual (x->display, x->screen),
+ DefaultColormap (x->display, x->screen));
+
+ color.color.red = 0xffff;
+ color.color.blue = 0xffff;
+ color.color.green = 0xffff;
+ color.color.alpha = 0xffff;
+
+ XftDrawRect (draw, &color, 0, 0, width, height);
+
+ color.color.red = 0x0;
+ color.color.green = 0x0;
+ color.color.blue = 0x0;
+ color.color.alpha = 0xffff;
+
+ xft_context.draw = draw;
+ xft_context.color = color;
+
+ do_output (context, render_callback, NULL, &xft_context, state, NULL, NULL);
+
+ XftDrawDestroy (draw);
+}
+
+const PangoViewer pangoxft_viewer = {
+ "PangoXft",
+ "xft",
+ NULL,
+ pangoxft_view_create,
+ pangoxft_view_destroy,
+ pangoxft_view_get_context,
+ x_view_create_surface,
+ x_view_destroy_surface,
+ pangoxft_view_render,
+ NULL,
+ x_view_create_window,
+ x_view_destroy_window,
+ x_view_display
+};
diff --git a/pango-view/viewer-win32.c b/pango-view/viewer-win32.c
new file mode 100644
index 00000000..3ac67ba0
--- /dev/null
+++ b/pango-view/viewer-win32.c
@@ -0,0 +1,748 @@
+/* Pango
+ * viewer-win32.c: Example program to view a UTF-8 encoding file
+ * using Pango to render result.
+ *
+ * Copyright (C) 1999 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gdk/win32/gdkwin32.h>
+
+#include <pango/pango.h>
+#include <pango/pangowin32.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define BUFSIZE 1024
+
+typedef struct _Paragraph Paragraph;
+
+/* Structure representing a paragraph
+ */
+struct _Paragraph {
+ char *text;
+ int length;
+ int height; /* Height, in pixels */
+ PangoLayout *layout;
+};
+
+GList *paragraphs;
+
+static PangoFontDescription *font_description;
+static Paragraph *highlight_para;
+static int highlight_offset;
+
+GtkWidget *styles_combo;
+
+static GtkWidget *message_label;
+GtkWidget *layout;
+
+PangoContext *context;
+
+static void fill_styles_combo (GtkWidget *combo);
+
+/* Read an entire file into a string
+ */
+static char *
+read_file(char *name)
+{
+ GString *inbuf;
+ FILE *file;
+ char *text;
+ char buffer[BUFSIZE];
+
+ file = fopen (name, "r");
+ if (!file)
+ {
+ fprintf (stderr, "%s: Cannot open %s\n", g_get_prgname (), name);
+ return NULL;
+ }
+
+ inbuf = g_string_new (NULL);
+ while (1)
+ {
+ char *bp = fgets (buffer, BUFSIZE-1, file);
+ if (ferror (file))
+ {
+ fprintf (stderr, "%s: Error reading %s\n", g_get_prgname (), name);
+ g_string_free (inbuf, TRUE);
+ return NULL;
+ }
+ else if (bp == NULL)
+ break;
+
+ g_string_append (inbuf, buffer);
+ }
+
+ fclose (file);
+
+ text = inbuf->str;
+ g_string_free (inbuf, FALSE);
+
+ return text;
+}
+
+/* Take a UTF8 string and break it into paragraphs on \n characters
+ */
+static GList *
+split_paragraphs (char *text)
+{
+ char *p = text;
+ char *next;
+ gunichar wc;
+ GList *result = NULL;
+ char *last_para = text;
+
+ while (*p)
+ {
+ wc = g_utf8_get_char (p);
+ next = g_utf8_next_char (p);
+ if (wc == (gunichar)-1)
+ {
+ fprintf (stderr, "%s: Invalid character in input\n", g_get_prgname ());
+ g_list_foreach (result, (GFunc)g_free, NULL);
+ return NULL;
+ }
+ if (!*p || !wc || wc == '\n')
+ {
+ Paragraph *para = g_new (Paragraph, 1);
+ para->text = last_para;
+ para->length = p - last_para;
+ para->layout = pango_layout_new (context);
+ pango_layout_set_text (para->layout, para->text, para->length);
+ para->height = 0;
+
+ last_para = next;
+
+ result = g_list_prepend (result, para);
+ }
+ if (!wc) /* incomplete character at end */
+ break;
+ p = next;
+ }
+
+ return g_list_reverse (result);
+}
+
+/* Given an x-y position, return the paragraph and offset
+ * within the paragraph of the click.
+ */
+gboolean
+xy_to_cp (int width, int x, int y, Paragraph **para_return, int *index)
+{
+ GList *para_list;
+ int height = 0;
+
+ *para_return = NULL;
+
+ para_list = paragraphs;
+ while (para_list && height < y)
+ {
+ Paragraph *para = para_list->data;
+
+ if (height + para->height >= y)
+ {
+ gboolean result = pango_layout_xy_to_index (para->layout,
+ x * PANGO_SCALE,
+ (y - height) * PANGO_SCALE,
+ index, NULL);
+ if (result && para_return)
+ *para_return = para;
+
+ return result;
+ }
+
+ height += para->height;
+ para_list = para_list->next;
+ }
+
+ return FALSE;
+}
+
+/* Given a paragraph and offset in that paragraph, find the
+ * bounding rectangle for the character at the offset.
+ */
+void
+char_bounds (Paragraph *para, int index, int width, PangoRectangle *rect)
+{
+ GList *para_list;
+
+ int height = 0;
+
+ para_list = paragraphs;
+ while (para_list)
+ {
+ Paragraph *cur_para = para_list->data;
+
+ if (cur_para == para)
+ {
+ PangoRectangle pos;
+
+ pango_layout_index_to_pos (cur_para->layout, index, &pos);
+
+ rect->x = PANGO_PIXELS (MIN (pos.x, pos.x + pos.width));
+ rect->width = PANGO_PIXELS (ABS (pos.width));
+ rect->y = height + PANGO_PIXELS (pos.y);
+ rect->height = PANGO_PIXELS (pos.height);
+ }
+
+ height += cur_para->height;
+ para_list = para_list->next;
+ }
+}
+
+/* XOR a rectangle over a given character
+ */
+void
+xor_char (GtkWidget *layout, GdkRectangle *clip_rect,
+ Paragraph *para, int offset)
+{
+ static GdkGC *gc;
+ PangoRectangle rect; /* GdkRectangle in 1.2 is too limited
+ */
+ if (!gc)
+ {
+ GdkGCValues values;
+ values.foreground = layout->style->white.pixel ?
+ layout->style->white : layout->style->black;
+ values.function = GDK_XOR;
+ gc = gdk_gc_new_with_values (GTK_LAYOUT (layout)->bin_window,
+ &values,
+ GDK_GC_FOREGROUND | GDK_GC_FUNCTION);
+ }
+
+ gdk_gc_set_clip_rectangle (gc, clip_rect);
+
+ char_bounds (para, offset, layout->allocation.width, &rect);
+
+ rect.y -= GTK_LAYOUT (layout)->yoffset;
+
+ if ((rect.y + rect.height >= 0) && (rect.y < layout->allocation.height))
+ gdk_draw_rectangle (GTK_LAYOUT (layout)->bin_window, gc, TRUE,
+ rect.x, rect.y, rect.width, rect.height);
+}
+
+/* Handle a size allocation by re-laying-out each paragraph to
+ * the new width, setting the new size for the layout and
+ * then queing a redraw
+ */
+void
+size_allocate (GtkWidget *layout, GtkAllocation *allocation)
+{
+ GList *tmp_list;
+ guint height = 0;
+ PangoDirection base_dir = pango_context_get_base_dir (context);
+
+ tmp_list = paragraphs;
+ while (tmp_list)
+ {
+ Paragraph *para = tmp_list->data;
+ PangoRectangle logical_rect;
+
+ tmp_list = tmp_list->next;
+
+ pango_layout_set_alignment (para->layout,
+ base_dir == PANGO_DIRECTION_LTR ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
+ pango_layout_set_width (para->layout, layout->allocation.width * PANGO_SCALE);
+
+ pango_layout_get_extents (para->layout, NULL, &logical_rect);
+ para->height = PANGO_PIXELS (logical_rect.height);
+
+ height += para->height;
+ }
+
+ gtk_layout_set_size (GTK_LAYOUT (layout), allocation->width, height);
+
+ if (GTK_LAYOUT (layout)->yoffset + allocation->height > height)
+ gtk_adjustment_set_value (GTK_LAYOUT (layout)->vadjustment, (float)(height - allocation->height));
+}
+
+/* Handle a draw/expose by finding the paragraphs that intersect
+ * the region and reexposing them.
+ */
+void
+draw (GtkWidget *layout, GdkRectangle *area)
+{
+ GList *tmp_list;
+ guint height = 0;
+ HDC hdc;
+ const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND|GDK_GC_FONT;
+
+ gdk_draw_rectangle (GTK_LAYOUT (layout)->bin_window,
+ layout->style->base_gc[layout->state],
+ TRUE,
+ area->x, area->y,
+ area->width, area->height);
+
+ gdk_gc_set_clip_rectangle (layout->style->text_gc[layout->state], area);
+
+ hdc = gdk_win32_hdc_get (GTK_LAYOUT (layout)->bin_window,
+ layout->style->text_gc[GTK_STATE_NORMAL],
+ mask);
+ tmp_list = paragraphs;
+ while (tmp_list &&
+ height < area->y + area->height + GTK_LAYOUT (layout)->yoffset)
+ {
+ Paragraph *para = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ if (height + para->height >= GTK_LAYOUT (layout)->yoffset + area->y)
+ pango_win32_render_layout (hdc, para->layout,
+ 0, height - GTK_LAYOUT (layout)->yoffset);
+ height += para->height;
+ }
+
+ gdk_win32_hdc_release (GTK_LAYOUT (layout)->bin_window,
+ layout->style->text_gc[GTK_STATE_NORMAL],
+ mask);
+ gdk_gc_set_clip_rectangle (layout->style->text_gc[layout->state], NULL);
+
+ if (highlight_para)
+ xor_char (layout, area, highlight_para, highlight_offset);
+}
+
+gboolean
+expose (GtkWidget *layout, GdkEventExpose *event)
+{
+ if (event->window == GTK_LAYOUT (layout)->bin_window)
+ draw (layout, &event->area);
+
+ return TRUE;
+}
+
+void
+button_press (GtkWidget *layout, GdkEventButton *event)
+{
+ Paragraph *para = NULL;
+ int offset;
+ gchar *message;
+
+ xy_to_cp (layout->allocation.width,
+ event->x, event->y + GTK_LAYOUT (layout)->yoffset,
+ &para, &offset);
+
+ if (highlight_para)
+ xor_char (layout, NULL, highlight_para, highlight_offset);
+
+ highlight_para = para;
+ highlight_offset = offset;
+
+ if (para)
+ {
+ gunichar wc;
+
+ wc = g_utf8_get_char (para->text + offset);
+ message = g_strdup_printf ("Current char: U%04x", wc);
+
+ xor_char (layout, NULL, highlight_para, highlight_offset);
+ }
+ else
+ message = g_strdup_printf ("Current char:");
+
+ gtk_label_set_text (GTK_LABEL (message_label), message);
+ g_free (message);
+}
+
+static void
+checkbutton_toggled (GtkWidget *widget, gpointer data)
+{
+ GList *para_list;
+
+ pango_context_set_base_dir (context, GTK_TOGGLE_BUTTON (widget)->active ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR);
+
+ para_list = paragraphs;
+ while (para_list)
+ {
+ Paragraph *para = para_list->data;
+
+ pango_layout_context_changed (para->layout);
+ para_list = para_list->next;
+ }
+
+ gtk_widget_queue_resize (layout);
+}
+
+static void
+reload_font ()
+{
+ GList *para_list;
+
+ pango_context_set_font_description (context, font_description);
+
+ para_list = paragraphs;
+ while (para_list)
+ {
+ Paragraph *para = para_list->data;
+
+ pango_layout_context_changed (para->layout);
+ para_list = para_list->next;
+ }
+
+ if (layout)
+ gtk_widget_queue_resize (layout);
+}
+
+void
+set_family (GtkWidget *entry, gpointer data)
+{
+ gchar *family_name = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+ if (!family_name || family_name[0] == '\0')
+ return;
+ pango_font_description_set_family(font_description, family_name);
+ fill_styles_combo (styles_combo);
+}
+
+void
+set_style (GtkWidget *entry, gpointer data)
+{
+ char *str = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+ PangoFontDescription *tmp_desc;
+
+ tmp_desc = pango_font_description_from_string (str);
+
+ pango_font_description_set_style(font_description, pango_font_description_get_style(tmp_desc));
+ pango_font_description_set_variant(font_description, pango_font_description_get_variant(tmp_desc));
+ pango_font_description_set_weight(font_description, pango_font_description_get_weight(tmp_desc));
+ pango_font_description_set_stretch(font_description, pango_font_description_get_stretch(tmp_desc));
+
+ pango_font_description_free (tmp_desc);
+ g_free (str);
+
+ reload_font ();
+}
+
+void
+font_size_changed (GtkAdjustment *adj)
+{
+ pango_font_description_set_size(font_description, (int)(adj->value * PANGO_SCALE + 0.5));
+ reload_font();
+}
+
+static int
+compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
+{
+ int val = strcmp (pango_font_description_get_family(a), pango_font_description_get_family(b));
+ if (val != 0)
+ return val;
+
+ if (pango_font_description_get_weight(a) != pango_font_description_get_weight(b))
+ return pango_font_description_get_weight(a) - pango_font_description_get_weight(b);
+
+ if (pango_font_description_get_style(a) != pango_font_description_get_style(b))
+ return pango_font_description_get_style(a) - pango_font_description_get_style(b);
+
+ if (pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b))
+ return pango_font_description_get_stretch(a) - pango_font_description_get_stretch(b);
+
+ if (pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b))
+ return pango_font_description_get_stretch(a) - pango_font_description_get_stretch(b);
+
+ return 0;
+}
+
+static int
+font_description_sort_func (const void *a, const void *b)
+{
+ return compare_font_descriptions (*(PangoFontDescription **)a, *(PangoFontDescription **)b);
+}
+
+typedef struct
+{
+ PangoFontDescription **descs;
+ int n_descs;
+} FontDescInfo;
+
+static void
+free_info (FontDescInfo *info)
+{
+ pango_font_descriptions_free (info->descs, info->n_descs);
+}
+
+static void
+fill_styles_combo (GtkWidget *combo)
+{
+ int i;
+ GList *style_list = NULL;
+ PangoFontFace **faces;
+ PangoFontFamily *family, **families;
+ FontDescInfo *info;
+ int n_families;
+ const char *family_name = pango_font_description_get_family(font_description);
+
+ /*
+ * Now map back the given family name to the family. There are more efficient
+ * ways to handle this but it should not matter much ...
+ */
+ pango_context_list_families (context, &families, &n_families);
+ g_assert(n_families > 0);
+ family = families[0]; /* just in case */
+ for (i = 0; i < n_families; i++)
+ {
+ if (0 == g_strcasecmp(pango_font_family_get_name(families[i]), family_name))
+ {
+ family = families[i];
+ break;
+ }
+ }
+ g_free (families);
+
+ info = g_new (FontDescInfo, 1);
+ pango_font_family_list_faces (family, &faces, &info->n_descs);
+
+ info->descs = g_new0 (PangoFontDescription*, info->n_descs);
+ for (i = 0; i < info->n_descs; i++)
+ {
+ info->descs[i] = pango_font_face_describe(faces[i]);
+ }
+ g_free (faces);
+
+ gtk_object_set_data_full (GTK_OBJECT (combo), "descs", info, (GtkDestroyNotify)free_info);
+
+ qsort (info->descs, info->n_descs, sizeof(PangoFontDescription *), font_description_sort_func);
+
+ for (i=0; i<info->n_descs; i++)
+ {
+ char *str;
+
+ PangoFontDescription *tmp_desc;
+
+ tmp_desc = info->descs[i];
+ pango_font_description_set_family(tmp_desc, NULL);
+ pango_font_description_unset_fields(tmp_desc, PANGO_FONT_MASK_SIZE);
+
+ str = pango_font_description_to_string (tmp_desc);
+ style_list = g_list_prepend (style_list, str);
+ }
+
+ style_list = g_list_reverse (style_list);
+
+ gtk_combo_set_popdown_strings (GTK_COMBO (combo), style_list);
+ g_list_foreach (style_list, (GFunc)g_free, NULL);
+}
+
+static GtkWidget *
+make_styles_combo ()
+{
+ GtkWidget *combo;
+
+ combo = gtk_combo_new ();
+ gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE);
+ gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (combo)->entry), FALSE);
+
+ gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
+ GTK_SIGNAL_FUNC (set_style), NULL);
+
+ styles_combo = combo;
+ fill_styles_combo (combo);
+
+ return combo;
+}
+
+static int
+cmp_families (const PangoFontFamily** a, const PangoFontFamily** b)
+{
+ return strcmp (pango_font_family_get_name (*a), pango_font_family_get_name (*b));
+}
+
+GtkWidget *
+make_families_menu ()
+{
+ GtkWidget *combo;
+ int n_families;
+ PangoFontFamily **families;
+ GList *family_list = NULL;
+ int i;
+
+ pango_context_list_families (context, &families, &n_families);
+ qsort (families, n_families, sizeof(char *), cmp_families);
+
+ for (i=0; i<n_families; i++)
+ family_list = g_list_prepend (family_list, pango_font_family_get_name (families[i]));
+
+ family_list = g_list_reverse (family_list);
+
+ combo = gtk_combo_new ();
+ gtk_combo_set_popdown_strings (GTK_COMBO (combo), family_list);
+ gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE);
+ gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (combo)->entry), FALSE);
+
+ gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), pango_font_description_get_family(font_description));
+
+ gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
+ GTK_SIGNAL_FUNC (set_family), NULL);
+
+ g_list_free (family_list);
+
+ return combo;
+}
+
+
+GtkWidget *
+make_font_selector (void)
+{
+ GtkWidget *hbox;
+ GtkWidget *util_hbox;
+ GtkWidget *label;
+ GtkWidget *option_menu;
+ GtkWidget *spin_button;
+ GtkAdjustment *adj;
+
+ hbox = gtk_hbox_new (FALSE, 4);
+
+ util_hbox = gtk_hbox_new (FALSE, 2);
+ label = gtk_label_new ("Family:");
+ gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0);
+ option_menu = make_families_menu ();
+ gtk_box_pack_start (GTK_BOX (util_hbox), option_menu, FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0);
+
+ util_hbox = gtk_hbox_new (FALSE, 2);
+ label = gtk_label_new ("Style:");
+ gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0);
+ option_menu = make_styles_combo ();
+ gtk_box_pack_start (GTK_BOX (util_hbox), option_menu, FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0);
+
+ util_hbox = gtk_hbox_new (FALSE, 2);
+ label = gtk_label_new ("Size:");
+ gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0);
+ spin_button = gtk_spin_button_new (NULL, 1., 0);
+ gtk_box_pack_start (GTK_BOX (util_hbox), spin_button, FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0);
+
+ adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin_button));
+ adj->value = PANGO_PIXELS (pango_font_description_get_size(font_description));
+ adj->lower = 0;
+ adj->upper = 1024;
+ adj->step_increment = 1;
+ adj->page_size = 10;
+ gtk_adjustment_changed (adj);
+ gtk_adjustment_value_changed (adj);
+
+ gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
+ GTK_SIGNAL_FUNC (font_size_changed), NULL);
+
+ return hbox;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *text;
+ GtkWidget *window;
+ GtkWidget *scrollwin;
+ GtkWidget *vbox, *hbox;
+ GtkWidget *frame;
+ GtkWidget *checkbutton;
+
+ gtk_init (&argc, &argv);
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: %s FILE\n", g_get_prgname ());
+ exit(1);
+ }
+
+ /* Create the list of paragraphs from the supplied file
+ */
+ text = read_file (argv[1]);
+ if (!text)
+ exit(1);
+
+ context = pango_win32_get_context ();
+
+ paragraphs = split_paragraphs (text);
+
+ pango_context_set_language (context, pango_language_from_string ("en_US"));
+ pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+
+ font_description = pango_font_description_new ();
+ pango_font_description_set_family(font_description, "sans");
+ pango_font_description_set_size(font_description, 16 * PANGO_SCALE);
+#if 0 /* default init ok? */
+ font_description.style = PANGO_STYLE_NORMAL;
+ font_description.variant = PANGO_VARIANT_NORMAL;
+ font_description.weight = 500;
+ font_description.stretch = PANGO_STRETCH_NORMAL;
+#endif
+
+ pango_context_set_font_description (context, font_description);
+
+ /* Create the user interface
+ */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+
+ vbox = gtk_vbox_new (FALSE, 4);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ hbox = make_font_selector ();
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+ scrollwin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+ gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0);
+
+ layout = gtk_layout_new (NULL, NULL);
+ gtk_widget_set_events (layout, GDK_BUTTON_PRESS_MASK);
+ gtk_widget_set_app_paintable (layout, TRUE);
+
+ gtk_signal_connect (GTK_OBJECT (layout), "size_allocate",
+ GTK_SIGNAL_FUNC (size_allocate), paragraphs);
+ gtk_signal_connect (GTK_OBJECT (layout), "expose_event",
+ GTK_SIGNAL_FUNC (expose), paragraphs);
+ gtk_signal_connect (GTK_OBJECT (layout), "draw",
+ GTK_SIGNAL_FUNC (draw), paragraphs);
+ gtk_signal_connect (GTK_OBJECT (layout), "button_press_event",
+ GTK_SIGNAL_FUNC (button_press), paragraphs);
+#if GTK_CHECK_VERSION (1,3,2)
+ gtk_widget_set_double_buffered (layout, FALSE);
+#endif
+ gtk_container_add (GTK_CONTAINER (scrollwin), layout);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+
+ message_label = gtk_label_new ("Current char:");
+ gtk_misc_set_padding (GTK_MISC (message_label), 1, 1);
+ gtk_misc_set_alignment (GTK_MISC (message_label), 0.0, 0.5);
+ gtk_container_add (GTK_CONTAINER (frame), message_label);
+
+ checkbutton = gtk_check_button_new_with_label ("Use RTL global direction");
+ gtk_signal_connect (GTK_OBJECT (checkbutton), "toggled",
+ GTK_SIGNAL_FUNC (checkbutton_toggled), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/pango-view/viewer-x.c b/pango-view/viewer-x.c
new file mode 100644
index 00000000..e79c6eaf
--- /dev/null
+++ b/pango-view/viewer-x.c
@@ -0,0 +1,241 @@
+/* viewer-x.c: Common code for X-based viewers
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+#include <string.h>
+
+#include "renderdemo.h"
+#include "viewer-x.h"
+
+void
+x_view_init (gpointer instance,
+ const PangoViewer *klass)
+{
+ XViewer *x = (XViewer *)instance;
+
+ x->display = XOpenDisplay (NULL);
+ if (!x->display)
+ fail ("Cannot open display %s\n", XDisplayName (NULL));
+
+ x->screen = DefaultScreen (x->display);
+}
+
+gpointer
+x_view_create (const PangoViewer *klass)
+{
+ XViewer *instance;
+
+ instance = g_slice_new (XViewer);
+
+ x_view_init (instance, klass);
+
+ return instance;
+}
+
+void
+x_view_destroy (gpointer instance)
+{
+ XViewer *x = (XViewer *)instance;
+
+ XCloseDisplay (x->display);
+
+ g_slice_free (XViewer, instance);
+}
+
+gpointer
+x_view_create_surface (gpointer instance,
+ int width,
+ int height)
+{
+ XViewer *x = (XViewer *) instance;
+ Pixmap pixmap;
+
+ pixmap = XCreatePixmap (x->display, DefaultRootWindow (x->display), width, height,
+ DefaultDepth (x->display, x->screen));
+
+ return (gpointer) pixmap;
+}
+
+void
+x_view_destroy_surface (gpointer instance,
+ gpointer surface)
+{
+ XViewer *x = (XViewer *) instance;
+ Pixmap pixmap = (Pixmap) surface;
+
+ XFreePixmap (x->display, pixmap);
+}
+
+static void
+update (Display *display,
+ Pixmap pixmap,
+ Window window,
+ Region *update_region)
+{
+ GC gc;
+ XRectangle extents;
+
+ XClipBox (*update_region, &extents);
+
+ gc = XCreateGC (display, pixmap, 0, NULL);
+
+ XCopyArea (display, pixmap, window, gc,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ extents.x, extents.y);
+
+ XFreeGC (display, gc);
+
+ XDestroyRegion (*update_region);
+ *update_region = NULL;
+}
+
+static void
+expose (XExposeEvent *xev,
+ Region *update_region)
+{
+ XRectangle r;
+
+ if (!*update_region)
+ *update_region = XCreateRegion ();
+
+ r.x = xev->x;
+ r.y = xev->y;
+ r.width = xev->width;
+ r.height = xev->height;
+
+ XUnionRectWithRegion (&r, *update_region, *update_region);
+}
+
+gpointer
+x_view_create_window (gpointer instance,
+ const char *title,
+ int width,
+ int height)
+{
+ XViewer *x = (XViewer *) instance;
+ unsigned long bg;
+ Window window;
+ XSizeHints size_hints;
+
+ bg = WhitePixel (x->display, x->screen);
+ window = XCreateSimpleWindow (x->display, DefaultRootWindow (x->display),
+ 0, 0, width, height, 0,
+ bg, bg);
+
+ XSelectInput (x->display, window, ExposureMask | KeyPressMask);
+
+ XMapWindow (x->display, window);
+ XmbSetWMProperties (x->display, window,
+ title,
+ NULL, NULL, 0, NULL, NULL, NULL);
+
+ memset ((char *)&size_hints, 0, sizeof (XSizeHints));
+ size_hints.flags = PSize | PMaxSize;
+ size_hints.width = width; size_hints.height = height; /* for compat only */
+ size_hints.max_width = width; size_hints.max_height = height;
+
+ XSetWMNormalHints (x->display, window, &size_hints);
+
+ return (gpointer) window;
+}
+
+void
+x_view_destroy_window (gpointer instance,
+ gpointer window)
+{
+ XViewer *x = (XViewer *) instance;
+ Window win = (Window) window;
+
+ XDestroyWindow (x->display, win);
+}
+
+gpointer
+x_view_display (gpointer instance,
+ gpointer surface,
+ gpointer win,
+ int width,
+ int height,
+ gpointer state)
+{
+ XViewer *x = (XViewer *) instance;
+ Pixmap pixmap = (Pixmap) surface;
+ Window window = (Window) win;
+ XEvent xev;
+ XRectangle r;
+ Region update_region;
+ unsigned int quit_keycode;
+ unsigned int borders_keycode;
+ gboolean show_borders = FALSE;
+
+ if (state)
+ show_borders = GPOINTER_TO_UINT (state) == 0xdeadbeef;
+
+ /* force a full redraw */
+ update_region = XCreateRegion ();
+ r.x = 0;
+ r.y = 0;
+ r.width = width;
+ r.height = height;
+ XUnionRectWithRegion (&r, update_region, update_region);
+
+ borders_keycode = XKeysymToKeycode(x->display, 'B');
+ quit_keycode = XKeysymToKeycode(x->display, 'Q');
+
+ while (1)
+ {
+ if (!XPending (x->display) && update_region)
+ update (x->display, pixmap, window, &update_region);
+
+ XNextEvent (x->display, &xev);
+ switch (xev.xany.type) {
+ case KeyPress:
+ if (xev.xkey.keycode == quit_keycode)
+ return NULL;
+ else if (xev.xkey.keycode == borders_keycode)
+ {
+ show_borders = !show_borders;
+ return GUINT_TO_POINTER (show_borders ? 0xdeadbeef : 0xbe);
+ }
+ break;
+ case Expose:
+ expose (&xev.xexpose, &update_region);
+ break;
+ }
+ }
+}
+
+const PangoViewer x_viewer = {
+ "X",
+ NULL,
+ NULL,
+ x_view_create,
+ x_view_destroy,
+ NULL,
+ x_view_create_surface,
+ x_view_destroy_surface,
+ NULL,
+ NULL,
+ x_view_create_window,
+ x_view_destroy_window,
+ x_view_display
+};
+
+const PangoViewer *fallback_viewer = &x_viewer;
diff --git a/pango-view/viewer-x.h b/pango-view/viewer-x.h
new file mode 100644
index 00000000..71c1279e
--- /dev/null
+++ b/pango-view/viewer-x.h
@@ -0,0 +1,70 @@
+/* viewer-x.h: Common headers for X-based viewers
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef VIEWER_X_H
+#define VIEWER_X_H
+
+#include <pango/pango.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "viewer.h"
+
+
+typedef struct
+{
+ Display *display;
+ int screen;
+} XViewer;
+
+
+extern const PangoViewer x_viewer;
+
+void x_view_init (gpointer instance,
+ const PangoViewer *klass);
+
+gpointer x_view_create (const PangoViewer *klass);
+
+void x_view_destroy (gpointer instance);
+
+gpointer x_view_create_surface (gpointer instance,
+ int width,
+ int height);
+
+void x_view_destroy_surface (gpointer instance,
+ gpointer surface);
+
+gpointer x_view_create_window (gpointer instance,
+ const char *title,
+ int width,
+ int height);
+
+void x_view_destroy_window (gpointer instance,
+ gpointer window);
+
+gpointer x_view_display (gpointer instance,
+ gpointer surface,
+ gpointer window,
+ int width,
+ int height,
+ gpointer state);
+
+#endif /* VIEWER_X_H */
diff --git a/pango-view/viewer.h b/pango-view/viewer.h
new file mode 100644
index 00000000..4d1d836a
--- /dev/null
+++ b/pango-view/viewer.h
@@ -0,0 +1,99 @@
+/* viewer.h: PangoViewer class
+ *
+ * Copyright (C) 1999,2004,2005 Red Hat, Inc.
+ * Copyright (C) 2001 Sun Microsystems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef VIEWER_H
+#define VIEWER_H
+
+#include <stdio.h>
+#include <pango/pango.h>
+
+typedef struct _PangoViewer PangoViewer;
+
+struct _PangoViewer {
+
+ const char *name;
+
+ const char *id;
+
+ const char *write_suffix;
+
+ gpointer (*create) (const PangoViewer *klass);
+
+ void (*destroy) (gpointer instance);
+
+ PangoContext * (*get_context) (gpointer instance);
+
+ gpointer (*create_surface) (gpointer instance,
+ int width,
+ int height);
+
+ void (*destroy_surface) (gpointer instance,
+ gpointer surface);
+
+ void (*render) (gpointer instance,
+ gpointer surface,
+ PangoContext *context,
+ int width,
+ int height,
+ gpointer state);
+
+ /* The following can be NULL */
+
+ void (*write) (gpointer instance,
+ gpointer surface,
+ FILE *stream,
+ int width,
+ int height);
+
+ gpointer (*create_window) (gpointer instance,
+ const char *title,
+ int width,
+ int height);
+
+ void (*destroy_window) (gpointer instance,
+ gpointer window);
+
+ gpointer (*display) (gpointer instance,
+ gpointer surface,
+ gpointer window,
+ int width,
+ int height,
+ gpointer state);
+
+ void (*load) (gpointer instance,
+ gpointer surface,
+ guchar *buffer,
+ int width,
+ int height,
+ int stride);
+
+ void (*save) (gpointer instance,
+ gpointer surface,
+ guchar *buffer,
+ int width,
+ int height,
+ int stride);
+
+};
+
+extern const PangoViewer *fallback_viewer;
+extern const PangoViewer *viewers[];
+
+#endif /* VIEWER_H */