Newer
Older
Import / applications / MakePDF / 3rdParty / libharu / unicode / changes.diff
diff --git a/demo/converter_demo.c b/demo/converter_demo.c
index f921ad2..998188b 100644
--- a/demo/converter_demo.c
+++ b/demo/converter_demo.c
@@ -38,12 +38,15 @@ error_handler (HPDF_STATUS   error_no,
 int main (int argc, char **argv)
 {
     const wchar_t *HELLO =
-        L"Hello.\x09 مرحبا.\u200F สวัสดี\x0A नमस्कार.\x0C "
-        L"שלום.\u200F 안녕하세요.\x0D 你好。こんにちは。"
+        L"Hello.\x09 \uFFF9مرحبا.\u200F\uFFFAmarḥába\uFFFB สวัสดี\x0A नमस्कार.\x0C "
+        L"שלום.\u200F 안녕하세요.\x0D\uFFF9你好\uFFFAnǐhǎo\uFFFB。こんにちは。"
+        ;
+    const wchar_t *HELLO_ru =
+        L"Здравствуйте. "
         ;
     const wchar_t *ONCE_UPON_A_TIME =
         L"以前老夫婦が住んでいました。"
-        L"老夫が山へ収穫に行きました。"
+        L"老夫が山へ\uFFF9収穫\uFFFAしばかり\uFFFBに行きました。"
         L"老妻が川へ洗濯に行きました。\n"
         L"老夫婦住。"
         L"老丈夫去到了收穫的山。"
@@ -51,8 +54,8 @@ int main (int argc, char **argv)
         L"老夫妇住。"
         L"老丈夫去到了收获的山。"
         L"老妻在河里去洗。\n"
-        L"이전 노부부가 살고있었습니다. "
-        L"늙은 남편이 산에 수확에갔습니다. "
+        L"이전 노부부가 살고있었습니다."
+        L"늙은 남편이 산에 수확에갔습니다."
         L"늙은 아내가 강에 세탁갔습니다.\n"
         L"Пожилая пара жила раньше. "
         L"Старый муж пошел в урожай в горы. "
@@ -67,8 +70,8 @@ int main (int argc, char **argv)
         L"Հին Ամուսինը գնաց բերքը լեռը. "
         L"Հին կինը գնաց լվանում է գետը.\u200E\n"
         L"عاش زوجين مسنين من قبل. "
-        L"ذه\u0640ب الزوج القديم إلى الحص\u0640اد إلى الجبل. "
-        L"زوجته البالغة من العمر ذه\u0640ب ليغسل في الن\u0640هر.\u200F\n"
+        L"ذهـب الزوج القديم إلى الحصـاد إلى الجبل. "
+        L"زوجته البالغة من العمر ذهـب ليغسل في النـهر.\u200F\n"
         L"זוג קשישים חי בעבר. "
         L"הבעל ישן הלך לקציר להר. "
         L"אישה זקנה הלכה לרחוץ בנהר.\u200F\n"
@@ -83,24 +86,26 @@ int main (int argc, char **argv)
     HPDF_Doc  pdf;
     char fname[256];
     HPDF_Page page;
-    HPDF_Font detail_font;
-    HPDF_Font detail_font_v;
-    HPDF_Font detail_font_v2;
+    HPDF_Font detail_font, detail_font_v, relief_font;
     const char *detail_font_name;
-    HPDF_Font relief_font;
-    HPDF_REAL page_height;
-    HPDF_REAL page_width;
+    HPDF_REAL page_width, page_height;
     HPDF_UINT len;
     HPDF_Rect rect;
+    HPDF_INT ttopt;
 
-    if (1 < argc) {
-        printf ("usage: converter_demo\n");
+    if (2 < argc || (1 < argc &&
+            (argv[1][0] != '-' || argv[1][1] != 'c' || argv[1][2] != 0))) {
+        printf ("usage: converter_demo [-c]\n");
         return 1;
     }
 
     strcpy (fname, argv[0]);
     strcat (fname, ".pdf");
 
+    ttopt = HPDF_FONTOPT_EMBEDDING;
+    if (1 < argc)
+        ttopt |= HPDF_FONTOPT_WITHOUT_CID_MAP;
+
     pdf = HPDF_New (error_handler, NULL);
     if (!pdf) {
         printf ("error: cannot create PdfDoc object\n");
@@ -112,53 +117,54 @@ int main (int argc, char **argv)
         return 1;
     }
 
+    HPDF_SetCompressionMode (pdf, HPDF_COMP_IMAGE | HPDF_COMP_METADATA);
+
     HPDF_UseCNSEncodings (pdf);
-    HPDF_UseCNTEncodings (pdf);
-    HPDF_UseJPEncodings (pdf);
+    //HPDF_UseCNTEncodings (pdf);
+    //HPDF_UseJPEncodings (pdf);
     HPDF_UseKREncodings (pdf);
     HPDF_UseUTFEncodings (pdf);
 
     HPDF_UseCNSFonts (pdf);
-    HPDF_UseCNTFonts (pdf);
-    HPDF_UseJPFonts (pdf);
+    //HPDF_UseCNTFonts (pdf);
+    //HPDF_UseJPFonts (pdf);
     HPDF_UseKRFonts (pdf);
 
 
-    /* Korean */
-    detail_font_name = HPDF_LoadTTFontFromFile2 (pdf,
-            "C:\\Windows\\Fonts\\gulim.ttc", 1,
-            HPDF_FONTOPT_EMBEDDING /* | HPDF_FONTOPT_WITH_CID_MAP */);
-    detail_font = HPDF_GetFont (pdf, detail_font_name, "UTF-8");
+    /* Devanagari */
+    detail_font_name = HPDF_LoadTTFontFromFile (pdf,
+            "C:\\Windows\\Fonts\\mangal.ttf", ttopt);
+    detail_font = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF8-H");
+    detail_font_v = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF16-H");
 
-    /* Simplified Chinese, Traditional Chinese, Japanese */
+    /* Thai, Armenian */
+    detail_font_name = HPDF_LoadTTFontFromFile (pdf,
+            "C:\\Windows\\Fonts\\tahoma.ttf", ttopt);
     relief_font = detail_font;
-    detail_font_name = HPDF_LoadTTFontFromFile2 (pdf,
-            "C:\\Windows\\Fonts\\simsun.ttc", 1,
-            HPDF_FONTOPT_EMBEDDING /* | HPDF_FONTOPT_WITH_CID_MAP */);
-    detail_font = HPDF_GetFont (pdf, detail_font_name, "UTF-8");
+    detail_font = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF8-H");
     HPDF_Font_SetReliefFont (detail_font, relief_font);
+    relief_font = detail_font_v;
+    detail_font_v = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF16-H");
+    HPDF_Font_SetReliefFont (detail_font_v, relief_font);
 
-    /* Devanagari */
+    /* Korean */
+    detail_font_name = HPDF_LoadTTFontFromFile2 (pdf,
+            "C:\\Windows\\Fonts\\gulim.ttc", 1, ttopt);
     relief_font = detail_font;
-    detail_font_name = HPDF_LoadTTFontFromFile (pdf,
-            "C:\\Windows\\Fonts\\mangal.ttf",
-            HPDF_FONTOPT_EMBEDDING /* | HPDF_FONTOPT_WITH_CID_MAP */);
-    detail_font = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF8-H");
+    detail_font = HPDF_GetFont (pdf, detail_font_name, "UniKS-UTF8-H");
     HPDF_Font_SetReliefFont (detail_font, relief_font);
 
-    /* Thai, Armenian */
+    /* Simplified Chinese, Traditional Chinese, Japanese */
+    detail_font_name = HPDF_LoadTTFontFromFile2 (pdf,
+            "C:\\Windows\\Fonts\\simsun.ttc", 1, ttopt);
     relief_font = detail_font;
-    detail_font_name = HPDF_LoadTTFontFromFile (pdf,
-            "C:\\Windows\\Fonts\\tahoma.ttf",
-            HPDF_FONTOPT_EMBEDDING /* | HPDF_FONTOPT_WITH_CID_MAP */);
-    detail_font = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF8-H");
+    detail_font = HPDF_GetFont (pdf, detail_font_name, "UniGB-UTF8-H");
     HPDF_Font_SetReliefFont (detail_font, relief_font);
 
     /* Latin, Cyrillic, Greek, Arabic, Hebrew */
-    relief_font = detail_font;
     detail_font_name = HPDF_LoadTTFontFromFile (pdf,
-            "C:\\Windows\\Fonts\\times.ttf",
-            HPDF_FONTOPT_EMBEDDING /* | HPDF_FONTOPT_WITH_CID_MAP */);
+            "C:\\Windows\\Fonts\\times.ttf", ttopt);
+    relief_font = detail_font;
     detail_font = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF8-H");
     HPDF_Font_SetReliefFont (detail_font, relief_font);
 
@@ -166,38 +172,42 @@ int main (int argc, char **argv)
     HPDF_Font_SetCharacterEncoding (detail_font, HPDF_CHARENC_WCHAR_T);
 
 
-    //detail_font_name = "MS-Mincho";
-    //detail_font_v = HPDF_GetFont (pdf, detail_font_name, "UniJIS-UTF16-V");
-
-    //relief_font = detail_font_v;
+    //detail_font_name = HPDF_LoadTTFontFromFile2 (pdf,
+    //        "C:\\Windows\\Fonts\\batang.ttc", 1, ttopt);
     detail_font_name = "Batang";
+    relief_font = detail_font_v;
     detail_font_v = HPDF_GetFont (pdf, detail_font_name, "UniKS-UTF16-V");
-    //HPDF_Font_SetReliefFont (detail_font_v, relief_font);
+    HPDF_Font_SetReliefFont (detail_font_v, relief_font);
 
-    relief_font = detail_font_v;
+    //detail_font_name = HPDF_LoadTTFontFromFile (pdf,
+    //        "C:\\Windows\\Fonts\\simhei.ttf", ttopt);
     detail_font_name = "SimHei";
+    relief_font = detail_font_v;
     detail_font_v = HPDF_GetFont (pdf, detail_font_name, "UniGB-UTF16-V");
     HPDF_Font_SetReliefFont (detail_font_v, relief_font);
 
-    HPDF_Font_SetCharacterEncoding (detail_font_v, HPDF_CHARENC_WCHAR_T);
-
+    detail_font_name = HPDF_LoadTTFontFromFile (pdf,
+            "C:\\Windows\\Fonts\\arial.ttf", ttopt);
+    relief_font = detail_font_v;
+    detail_font_v = HPDF_GetFont (pdf, detail_font_name, "Ancient-UTF16-H");
+    HPDF_Font_SetReliefFont (detail_font_v, relief_font);
 
-    detail_font_name = "MS-Mincho";
-    detail_font_v2 = HPDF_GetFont (pdf, detail_font_name, "90ms-RKSJ-V");
+    HPDF_Font_PushBuiltInConverter (detail_font_v, "BiDi", NULL);
+    HPDF_Font_SetCharacterEncoding (detail_font_v, HPDF_CHARENC_WCHAR_T);
 
 
     /* Add a new page object. */
     page = HPDF_AddPage (pdf);
 
-    page_height = 841.88976F;
     page_width  = 595.27559F;
+    page_height = 841.88976F;
 
     HPDF_Page_SetWidth  (page, page_width);
     HPDF_Page_SetHeight (page, page_height);
 
-    rect.left   = 30;
+    rect.left   = page_width / 2 - 10;
     rect.bottom = page_height - 60;
-    rect.right  = 50;
+    rect.right  = page_width / 2 + 10;
     rect.top    = page_height - 80;
     HPDF_Page_CreateTextAnnot (page, rect, (const char *)HELLO,
             HPDF_GetUTFEncoder (pdf, HPDF_CHARENC_WCHAR_T));
@@ -205,58 +215,45 @@ int main (int argc, char **argv)
     HPDF_Page_BeginText (page);
 
     HPDF_Page_SetFontAndSize (page, detail_font, 15);
-
-    HPDF_Page_SetWordSpace (page, 10);
+    HPDF_Page_SetWordSpace (page, 5);
     HPDF_Page_SetCharSpace (page, 0);
 
-    HPDF_Page_MoveTextPos (page, 30, page_height - 40);
-    HPDF_Page_ShowText (page, (const char *)HELLO);
+    HPDF_Page_TextOut (page, 20, page_height - 50, (const char *)HELLO);
+    HPDF_Page_ShowText (page, (const char *)HELLO_ru);
 
-    HPDF_Page_SetWordSpace (page, 6);
-    HPDF_Page_SetCharSpace (page, 0);
-    HPDF_Page_SetJustifyRatio (page, 10, 0, 1000);
+    HPDF_Page_SetTextLeading (page, 0);
+    HPDF_Page_SetJustifyRatio (page, 1, 1, 100);
 
-    HPDF_Page_TextRect (page, 30, page_height - 90,
+    HPDF_Page_TextRect (page, 30, page_height - 60,
             page_width / 2 - 29, 30, (const char *)ONCE_UPON_A_TIME,
-            HPDF_TALIGN_JUSTIFY | HPDF_TALIGNOPT_BIDI_EACH_PARAGRAPH | HPDF_TALIGNOPT_REMOVE_TATWEEL, &len);
+            HPDF_TALIGN_JUSTIFY | HPDF_VALIGN_JUSTIFY_ALL |
+            HPDF_ALIGNOPT_BIDI_EACH_PARAGRAPH | HPDF_ALIGNOPT_REMOVE_TATWEEL,
+            &len);
 
     HPDF_Page_SetFontAndSize (page, detail_font_v, 15);
+    HPDF_Page_SetWordSpace (page, 0);
+
+    HPDF_Page_SetTextLeading (page, 30);
+    HPDF_Page_TextOut (page, page_width / 2 + 20, page_height - 90,
+            (const char *)HELLO_ru);
+    HPDF_Page_ShowText (page, (const char *)HELLO);
+    HPDF_Page_ShowTextNextLine (page, NULL);
+    HPDF_Page_ShowText (page, (const char *)HELLO_ru);
+    HPDF_Page_ShowText (page, (const char *)L"!!!!");
+
+    HPDF_Page_SetTextLeading (page, 0);
+
+    HPDF_Page_TextRect (page, page_width / 2 + 40, page_height - 60,
+            page_width - 30, 405, (const char *)ONCE_UPON_A_TIME,
+            HPDF_TALIGN_JUSTIFY | HPDF_VALIGN_JUSTIFY, &len);
+
+    HPDF_Page_SetTextLeading (page, -20);
 
-    HPDF_Page_SetWordSpace (page,  4);
-    HPDF_Page_SetCharSpace (page, -2);
-    HPDF_Page_SetJustifyRatio (page, 1, 1, 0);
-
-    HPDF_Page_TextRect (page, page_width / 2 + 30, page_height - 90,
-            page_width - 30, 450, (const char *)ONCE_UPON_A_TIME,
-            HPDF_TALIGN_JUSTIFY, &len);
-
-    HPDF_Page_SetFontAndSize (page, detail_font_v2, 15);
-
-    HPDF_Page_SetWordSpace (page, -1);
-    HPDF_Page_SetCharSpace (page,  4);
-    HPDF_Page_SetJustifyRatio (page, 2, 1, 0);
-    HPDF_Page_SetTextLeading (page, -10);
-
-    HPDF_Page_TextRect (page, page_width / 2 + 30, 400, page_width - 30, 30,
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. "
-            "A quick brown fox jumps over the lazy dog. ",
-            HPDF_TALIGN_JUSTIFY, &len);
+    HPDF_Page_TextRect (page, page_width / 2 + 40, 380, page_width - 30, 30,
+            (const char *)ONCE_UPON_A_TIME + len,
+            HPDF_TALIGN_JUSTIFY | HPDF_VALIGN_JUSTIFY |
+            HPDF_ALIGNOPT_BIDI_EACH_PARAGRAPH | HPDF_ALIGNOPT_REMOVE_TATWEEL,
+            &len);
 
     /* Finish to print text. */
     HPDF_Page_EndText (page);
@@ -268,16 +265,16 @@ int main (int argc, char **argv)
     HPDF_Page_LineTo (page, page_width - 10, page_height - 25);
     HPDF_Page_Stroke (page);
 
-    HPDF_Page_Rectangle (page, 30, page_height - 90,
-            page_width / 2 - 29 - 30, 30 - (page_height - 90));
+    HPDF_Page_Rectangle (page, 30, page_height - 60,
+            page_width / 2 - 29 - 30, 30 - (page_height - 60));
     HPDF_Page_Stroke (page);
 
-    HPDF_Page_Rectangle (page, page_width / 2 + 30, page_height - 90,
-            page_width - 30 - (page_width / 2 + 30), 450 - (page_height - 90));
+    HPDF_Page_Rectangle (page, page_width / 2 + 40, page_height - 60,
+            page_width - 30 - (page_width / 2 + 40), 405 - (page_height - 60));
     HPDF_Page_Stroke (page);
 
-    HPDF_Page_Rectangle (page, page_width / 2 + 30, 400,
-            page_width - 30 - (page_width / 2 + 30), 30 - 400);
+    HPDF_Page_Rectangle (page, page_width / 2 + 40, 380,
+            page_width - 30 - (page_width / 2 + 40), 30 - 380);
     HPDF_Page_Stroke (page);
 
 
diff --git a/include/hpdf.h b/include/hpdf.h
index fd76c1e..8199a32 100644
--- a/include/hpdf.h
+++ b/include/hpdf.h
@@ -969,19 +969,16 @@ HPDF_Font_MeasureText  (HPDF_Font          font,
 
 
 HPDF_EXPORT(HPDF_UINT)
-HPDF_Font_MeasureTextEx  (HPDF_Font          font,
-                          const char        *text,
-                          HPDF_UINT          len,
-                          HPDF_REAL          width,
-                          HPDF_REAL          font_size,
-                          HPDF_REAL          char_space,
-                          HPDF_REAL          word_space,
-                          HPDF_INT           options,
-                          HPDF_REAL         *real_width,
-                          HPDF_UINT         *numbytes,
-                          HPDF_UINT         *numchars,
-                          HPDF_UINT         *numspaces,
-                          HPDF_UINT         *numtatweels);
+HPDF_Font_MeasureTextLines  (HPDF_Font           font,
+                             const char         *text,
+                             HPDF_UINT           len,
+                             HPDF_REAL           line_width,
+                             HPDF_REAL           font_size,
+                             HPDF_REAL           char_space,
+                             HPDF_REAL           word_space,
+                             HPDF_INT            options,
+                             HPDF_TextLineWidth *width,
+                             HPDF_UINT           max_lines);
 
 
 HPDF_EXPORT(HPDF_STATUS)
@@ -1079,15 +1076,12 @@ HPDF_Page_MeasureText  (HPDF_Page    page,
 
 
 HPDF_EXPORT(HPDF_UINT)
-HPDF_Page_MeasureTextEx  (HPDF_Page    page,
-                          const char  *text,
-                          HPDF_REAL    width,
-                          HPDF_INT     options,
-                          HPDF_REAL   *real_width,
-                          HPDF_UINT   *numbytes,
-                          HPDF_UINT   *numchars,
-                          HPDF_UINT   *numspaces,
-                          HPDF_UINT   *numtatweels);
+HPDF_Page_MeasureTextLines  (HPDF_Page           page,
+                             const char         *text,
+                             HPDF_REAL           line_width,
+                             HPDF_INT            options,
+                             HPDF_TextLineWidth *width,
+                             HPDF_UINT           max_lines);
 
 
 HPDF_EXPORT(HPDF_REAL)
@@ -1649,6 +1643,11 @@ HPDF_Page_SetJustifyRatio  (HPDF_Page page,
                             HPDF_REAL kashida);
 
 
+HPDF_EXPORT(HPDF_STATUS)
+HPDF_Page_InterlinearAnnotationRatio  (HPDF_Page page,
+                                       HPDF_REAL ratio);
+
+
 HPDF_EXPORT(HPDF_STATUS)
 HPDF_Page_SetSlideShow  (HPDF_Page              page,
                          HPDF_TransitionStyle   type,
diff --git a/include/hpdf_consts.h b/include/hpdf_consts.h
index b61d46c..98ac6fe 100644
--- a/include/hpdf_consts.h
+++ b/include/hpdf_consts.h
@@ -550,22 +550,31 @@
 /*----- Font options ---------------------------------------------------------*/
 
 #define   HPDF_FONTOPT_EMBEDDING             0x00000001
-#define   HPDF_FONTOPT_WITH_CID_MAP          0x00000002
+#define   HPDF_FONTOPT_WITHOUT_CID_MAP       0x00000002
 #define   HPDF_FONTOPT_WITHOUT_TOUNICODE_MAP 0x00000004
 
 
 /*----------------------------------------------------------------------------*/
 /*----- MeasureText options --------------------------------------------------*/
 
-#define   HPDF_MEASURE_WORD_WRAP             0x00000001
-#define   HPDF_MEASURE_CAN_SHORTEN           0x00000002
-#define   HPDF_MEASURE_IGNORE_TATWEEL        0x00000004
+#define   HPDF_MEASURE_WORD_WRAP        0x00000001
+#define   HPDF_MEASURE_CAN_SHORTEN      0x00000002
+#define   HPDF_MEASURE_IGNORE_TATWEEL   0x00000004
+
+/*----- TextLineWidth flags --------------------------------------------------*/
+
+#define   HPDF_TLW_WORD_WRAP                0x0001
+#define   HPDF_TLW_SHORTEN                  0x0002
+#define   HPDF_TLW_IGNORE_TATWEEL           0x0004
+#define   HPDF_TLW_HYPHENATION              0x0100
+#define   HPDF_TLW_PRAGRAPH_BREAK           0x0200
+#define   HPDF_TLW_PAGE_BREAK               0x0400
 
 
 /*----------------------------------------------------------------------------*/
-/*----- Convert flag ---------------------------------------------------------*/
+/*----- Convert flags --------------------------------------------------------*/
 
-#define   HPDF_CONVERT_HOLD_CHARACTERS       0x00000001
+#define   HPDF_CONVERT_HOLD_CHARACTERS  0x00000001
 
 
 /*----------------------------------------------------------------------------*/
diff --git a/include/hpdf_font.h b/include/hpdf_font.h
index 5edc6a3..33f5519 100644
--- a/include/hpdf_font.h
+++ b/include/hpdf_font.h
@@ -104,6 +104,13 @@ HPDF_Type0Font_New  (HPDF_MMgr        mmgr,
                      HPDF_Xref        xref);
 
 
+HPDF_TextWidth
+HPDF_Font_TextCacheWidth  (HPDF_Font font,
+                           HPDF_BOOL ignore_flags,
+                           HPDF_UINT cache_begin,
+                           HPDF_UINT cache_end);
+
+
 HPDF_BOOL
 HPDF_Font_Validate  (HPDF_Font font);
 
@@ -147,6 +154,13 @@ HPDF_Font_GetReliefFont  (HPDF_Font  font,
                           HPDF_BYTE *index);
 
 
+#define HPDF_RELIEF_FONT_INDEX_MASK 0x0F
+#define HPDF_INTERLINEAR_ANNOTATED  0x80
+#define HPDF_INTERLINEAR_ANNOTATION 0x40
+/*         reserved for TATECHUYOKO 0x20 */
+/*         reserved                 0x10 */
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/include/hpdf_gstate.h b/include/hpdf_gstate.h
index 3f2a3bb..4cb3b90 100644
--- a/include/hpdf_gstate.h
+++ b/include/hpdf_gstate.h
@@ -60,8 +60,10 @@ typedef struct _HPDF_GState_Rec {
     HPDF_REAL               gray_stroke;
 
     HPDF_Font               font;
-    HPDF_REAL               font_size;
     HPDF_Font               actual_font;
+    HPDF_REAL               font_size;
+    HPDF_REAL               actual_font_size;
+    HPDF_REAL               ia_font_size_ratio;
     HPDF_WritingMode        writing_mode;
 
     HPDF_GState             prev;
diff --git a/include/hpdf_pages.h b/include/hpdf_pages.h
index 44b816c..6e4dd66 100644
--- a/include/hpdf_pages.h
+++ b/include/hpdf_pages.h
@@ -60,12 +60,13 @@ typedef struct _HPDF_PageAttr_Rec {
     HPDF_Point         cur_pos;
     HPDF_Point         text_pos;
     HPDF_TransMatrix   text_matrix;
+    HPDF_BOOL          fake_text_pos;
     HPDF_UINT16        gmode;
     HPDF_Dict          contents;
     HPDF_Stream        stream;
     HPDF_Xref          xref;
     HPDF_UINT          compression_mode;
-	HPDF_PDFVer       *ver; 
+    HPDF_PDFVer       *ver; 
 } HPDF_PageAttr_Rec;
 
 
diff --git a/include/hpdf_types.h b/include/hpdf_types.h
index 422b60d..a54810c 100644
--- a/include/hpdf_types.h
+++ b/include/hpdf_types.h
@@ -209,6 +209,18 @@ typedef struct _HPDF_TextWidth {
 } HPDF_TextWidth;
 
 
+typedef struct _HPDF_TextLineWidth {
+    HPDF_UINT16 flags;
+    HPDF_UINT16 linebytes;
+    HPDF_UINT16 numbytes;
+    HPDF_UINT16 numchars;
+    HPDF_UINT16 numspaces;
+    HPDF_UINT16 numtatweels;
+    HPDF_UINT   charswidth;
+    HPDF_REAL   width;
+} HPDF_TextLineWidth;
+
+
 /*---------------------------------------------------------------------------*/
 /*------ dash mode ----------------------------------------------------------*/
 
@@ -307,6 +319,8 @@ typedef enum _HPDF_TextRenderingMode {
 typedef enum _HPDF_WritingMode {
     HPDF_WMODE_HORIZONTAL = 0,
     HPDF_WMODE_VERTICAL,
+    HPDF_WMODE_SIDEWAYS,        /* gstate only */
+    HPDF_WMODE_MIXED,           /* gstate only */
     HPDF_WMODE_EOF
 } HPDF_WritingMode;
 
@@ -373,8 +387,8 @@ typedef enum _HPDF_AnnotType {
     HPDF_ANNOT_POPUP,
     HPDF_ANNOT_3D,
     HPDF_ANNOT_SQUIGGLY,
-        HPDF_ANNOT_LINE,
-        HPDF_ANNOT_PROJECTION
+    HPDF_ANNOT_LINE,
+    HPDF_ANNOT_PROJECTION
 } HPDF_AnnotType;
 
 
@@ -551,15 +565,24 @@ typedef enum _HPDF_ByteType {
 
 
 typedef enum _HPDF_TextAlignment {
-    HPDF_TALIGN_LEFT = 0,
-    HPDF_TALIGN_RIGHT,
-    HPDF_TALIGN_CENTER,
-    HPDF_TALIGN_JUSTIFY,
-    HPDF_TALIGN_JUSTIFY_ALL,
-    HPDF_TALIGN_STRETCH,
-    HPDF_TALIGN_MASK                   = 0x0000000F,
-    HPDF_TALIGNOPT_BIDI_EACH_PARAGRAPH = 0x40000000,
-    HPDF_TALIGNOPT_REMOVE_TATWEEL      = 0x20000000,
+    HPDF_TALIGN_LEFT                  =          0,
+    HPDF_TALIGN_RIGHT                 =          1,
+    HPDF_TALIGN_CENTER                =          2,
+    HPDF_TALIGN_JUSTIFY               =          3,
+    HPDF_TALIGN_STRETCH               =          4,
+    HPDF_TALIGN_JUSTIFY_ALL           =       0x83,
+    HPDF_TALIGN_STRETCH_ALL           =       0x84,
+    HPDF_TALIGN_MASK                  =       0xFF,
+    HPDF_VALIGN_TOP                   =     0x0000,
+    HPDF_VALIGN_BOTTOM                =     0x0100,
+    HPDF_VALIGN_CENTER                =     0x0200,
+    HPDF_VALIGN_JUSTIFY               =     0x0300,
+    HPDF_VALIGN_STRETCH               =     0x0400,
+    HPDF_VALIGN_JUSTIFY_ALL           =     0x8300,
+    HPDF_VALIGN_STRETCH_ALL           =     0x8400,
+    HPDF_VALIGN_MASK                  =     0xFF00,
+    HPDF_ALIGNOPT_BIDI_EACH_PARAGRAPH = 0x40000000,
+    HPDF_ALIGNOPT_REMOVE_TATWEEL      = 0x20000000,
 } HPDF_TextAlignment;
 
 /*----------------------------------------------------------------------------*/
diff --git a/src/hpdf_encoder_utf.c b/src/hpdf_encoder_utf.c
index de57767..10ec6f2 100644
--- a/src/hpdf_encoder_utf.c
+++ b/src/hpdf_encoder_utf.c
@@ -438,7 +438,7 @@ Ancient_UTF16_H_Init  (HPDF_Encoder  encoder,
 
 static const char MODERN_ENCODERS[][17] = {
   "",
-  "UTF-8",        /* not "Modern-UTF8-H" for backward compatibility */
+  "Modern-UTF8-H",
   "Modern-UTF16-H",
   "Modern-UTF32-H",
   "Modern-UCS2LE-H",
diff --git a/src/hpdf_font.c b/src/hpdf_font.c
index f5db87d..39bac6e 100644
--- a/src/hpdf_font.c
+++ b/src/hpdf_font.c
@@ -67,14 +67,14 @@ IsCIDText  (HPDF_Font font,
 
 
 static HPDF_UINT
-MeasureTextEx  (HPDF_Font          font,
-                HPDF_REAL          width,
-                HPDF_REAL          font_size,
-                HPDF_REAL          char_space,
-                HPDF_REAL          word_space,
-                HPDF_INT           options,
-                HPDF_REAL         *real_width,
-                HPDF_UINT         *numtatweels);
+MeasureTextCache  (HPDF_Font           font,
+                   HPDF_REAL           line_width,
+                   HPDF_REAL           font_size,
+                   HPDF_REAL           char_space,
+                   HPDF_REAL           word_space,
+                   HPDF_INT            options,
+                   HPDF_UINT           cache_begin,
+                   HPDF_TextLineWidth *width);
 
 
 static HPDF_BOOL
@@ -86,10 +86,10 @@ CanBreakBefore  (HPDF_UCS4 b);
 
 
 static HPDF_UINT
-GetUncovertedBytes  (HPDF_Font   font,
-                     const char *text,
-                     HPDF_UINT   len,
-                     HPDF_UINT  *numbytes);
+GetUncovertedBytes  (HPDF_Font           font,
+                     const char         *text,
+                     HPDF_UINT           cache_begin,
+                     HPDF_TextLineWidth *width);
 
 
 static HPDF_CharEnc
@@ -107,10 +107,6 @@ HPDF_Font_TextWidth  (HPDF_Font        font,
 {
     HPDF_TextWidth tw = {0, 0, 0, 0};
     HPDF_FontAttr attr;
-    HPDF_UINT i;
-    HPDF_UCS4 b;
-    HPDF_BYTE *pirf;
-    HPDF_UINT bytes;
 
     HPDF_PTRACE ((" HPDF_Font_TextWidth\n"));
 
@@ -137,38 +133,53 @@ HPDF_Font_TextWidth  (HPDF_Font        font,
         return attr->tw_cache;
     }
 
-    text = attr->text_cache;
-    pirf = attr->text_cache + (attr->text_cache_allocated / 2);
-    len  = attr->text_cache_len;
-    b = 0;
-    i = 0;
+    attr->tw_cache = HPDF_Font_TextCacheWidth (font, HPDF_FALSE,
+            0, attr->text_cache_len);
+
+    return attr->tw_cache;
+}
+
+
+HPDF_TextWidth
+HPDF_Font_TextCacheWidth  (HPDF_Font font,
+                           HPDF_BOOL ignore_flags,
+                           HPDF_UINT cache_begin,
+                           HPDF_UINT cache_end)
+{
+    HPDF_TextWidth tw = {0, 0, 0, 0};
+    HPDF_FontAttr attr = (HPDF_FontAttr)font->attr;
+    const HPDF_BYTE *text = attr->text_cache;
+    HPDF_BYTE *pirf = attr->text_cache + (attr->text_cache_allocated / 2);
+    HPDF_BYTE irf;
+    HPDF_UCS4 b = 0;
+    HPDF_UINT i, bytes;
 
-    while (i < len) {
+    HPDF_PTRACE ((" HPDF_Font_TextCacheWidth\n"));
+
+    for (i = cache_begin; i < cache_end; i += bytes) {
         HPDF_UINT cw;
 
-        cw = attr->char_width_fn (font, HPDF_TRUE, *pirf, text, &bytes, &b);
-        tw.width += cw;
+        irf = pirf[i] & HPDF_RELIEF_FONT_INDEX_MASK;
+        cw = attr->char_width_fn (font, HPDF_TRUE, irf, text+i, &bytes, &b);
+
+        if (!ignore_flags && (pirf[i] & HPDF_INTERLINEAR_ANNOTATION))
+            continue;
 
+        tw.width += cw;
         tw.numchars++;
 
-        if (b == 0x20 && bytes == 1 && !IsCIDText (font, *pirf)) {
+        if (b == 0x20 && bytes == 1 && !IsCIDText (font, irf)) {
             tw.numwords++;
             tw.numspace++;
         }
-
-        pirf += bytes;
-        text += bytes;
-        i    += bytes;
     }
 
     /* 2006.08.19 add. */
-    if (b == 0x20 && bytes == 1 && !IsCIDText (font, *pirf))
+    if (b == 0x20 && bytes == 1 && !IsCIDText (font, irf))
         ; /* do nothing. */
     else
         tw.numwords++;
 
-    attr->tw_cache = tw;
-
     return tw;
 }
 
@@ -184,36 +195,41 @@ HPDF_Font_MeasureText (HPDF_Font          font,
                        HPDF_INT           options,
                        HPDF_REAL         *real_width)
 {
+    HPDF_TextLineWidth tlw;
+    HPDF_UINT lines;
+
     HPDF_PTRACE ((" HPDF_Font_MeasureText\n"));
 
-    return HPDF_Font_MeasureTextEx (font, (const char *)text, len, width,
-            font_size, char_space, word_space, options, real_width,
-            NULL, NULL, NULL, NULL);
+    lines = HPDF_Font_MeasureTextLines (font, (const char *)text, len, width,
+            font_size, char_space, word_space, options, &tlw, 1);
+    if (!lines)
+        return 0;
+
+    if (real_width)
+        *real_width = tlw.width;
+    return tlw.linebytes;
 }
 
 
 HPDF_EXPORT(HPDF_UINT)
-HPDF_Font_MeasureTextEx  (HPDF_Font          font,
-                          const char        *text,
-                          HPDF_UINT          len,
-                          HPDF_REAL          width,
-                          HPDF_REAL          font_size,
-                          HPDF_REAL          char_space,
-                          HPDF_REAL          word_space,
-                          HPDF_INT           options,
-                          HPDF_REAL         *real_width,
-                          HPDF_UINT         *numbytes,
-                          HPDF_UINT         *numchars,
-                          HPDF_UINT         *numspaces,
-                          HPDF_UINT         *numtatweels)
+HPDF_Font_MeasureTextLines  (HPDF_Font           font,
+                             const char         *text,
+                             HPDF_UINT           len,
+                             HPDF_REAL           line_width,
+                             HPDF_REAL           font_size,
+                             HPDF_REAL           char_space,
+                             HPDF_REAL           word_space,
+                             HPDF_INT            options,
+                             HPDF_TextLineWidth *width,
+                             HPDF_UINT           max_lines)
 {
     HPDF_FontAttr attr;
-    HPDF_UINT cvt_len, tmp_len, tatweels;
-    HPDF_REAL rw, margin;
+    HPDF_UINT line, begin, cvt_len;
+    HPDF_REAL margin;
 
-    HPDF_PTRACE ((" HPDF_Font_MeasureTextEx\n"));
+    HPDF_PTRACE ((" HPDF_Font_MeasureTextLines\n"));
 
-    if (!HPDF_Font_Validate(font) || !text)
+    if (!HPDF_Font_Validate(font) || !text || !width)
         return 0;
 
     if (len > HPDF_LIMIT_MAX_STRING_LEN) {
@@ -228,54 +244,60 @@ HPDF_Font_MeasureTextEx  (HPDF_Font          font,
         return 0;
     }
 
-    if (!real_width)
-        real_width = &rw;
-    if (!numtatweels)
-        numtatweels = &tatweels;
-
     margin = 1.25F;             /* margin 25% */
     do { /* estimate result length and convert only the length+margin */
+        HPDF_UINT cache_begin, cache_end;
+        HPDF_REAL w = 0;
+
         if (!attr->width_per_byte) /* expect average width is missing_width/2 */
             attr->width_per_byte = (HPDF_REAL)attr->fontdef->missing_width / 2 /
                     MINBYTES[GetSourceCharEnc (font)];
 
-        cvt_len = (HPDF_UINT)(width / font_size * 1000 / attr->width_per_byte
-                * margin);
+        cvt_len = (HPDF_UINT)(line_width * max_lines / font_size * 1000 *
+                margin / attr->width_per_byte);
         if (len < cvt_len)
             cvt_len = len;
 
         if (HPDF_Font_ConvertText (font, HPDF_CONVERT_HOLD_CHARACTERS,
                 text, cvt_len) != HPDF_OK)
             return 0;
-        
-        tmp_len = MeasureTextEx (font, width, font_size, char_space, word_space,
-                options, real_width, numtatweels);
-        
-        if (numchars)
-            *numchars = attr->tw_cache.numchars;
-        if (numspaces)
-            *numspaces = attr->tw_cache.numspace;
-
-        tmp_len = GetUncovertedBytes (font, text, tmp_len, numbytes);
-
-        if (8 < tmp_len)        /* ignore too short sample */
-            attr->width_per_byte = *real_width / font_size * 1000 / tmp_len;
+
+        for (begin = 0, cache_begin = 0, line = 0;
+                line < max_lines &&
+                begin < cvt_len &&
+                !(line && (width[line - 1].flags & HPDF_TLW_PAGE_BREAK));
+                line++) {
+            MeasureTextCache (font, line_width, font_size, char_space,
+                    word_space, options, cache_begin, width + line);
+            w += width[line].width;
+            if (line_width < width[line].width)
+                width[line].flags |= HPDF_TLW_SHORTEN;
+
+            cache_end = cache_begin + width[line].linebytes;
+            GetUncovertedBytes (font, text + begin, cache_begin, width + line);
+
+            begin += width[line].linebytes;
+            cache_begin = cache_end;
+        }
+
+        if (8 < begin)          /* ignore too short sample */
+            attr->width_per_byte = w / font_size * 1000 / begin;
         margin += 0.25F;        /* margin +25% */
-    } while (cvt_len <= tmp_len + 4 && cvt_len < len); /* while misestimate */
+    } while (cvt_len <= begin + 4 && cvt_len < len); /* while misestimate */
 
-    return tmp_len;
+    return line;
 }
 
 
 static HPDF_UINT
-MeasureTextEx  (HPDF_Font          font,
-                HPDF_REAL          width,
-                HPDF_REAL          font_size,
-                HPDF_REAL          char_space,
-                HPDF_REAL          word_space,
-                HPDF_INT           options,
-                HPDF_REAL         *real_width,
-                HPDF_UINT         *numtatweels)
+MeasureTextCache  (HPDF_Font           font,
+                   HPDF_REAL           line_width,
+                   HPDF_REAL           font_size,
+                   HPDF_REAL           char_space,
+                   HPDF_REAL           word_space,
+                   HPDF_INT            options,
+                   HPDF_UINT           cache_begin,
+                   HPDF_TextLineWidth *width)
 {
     HPDF_FontAttr attr;
     HPDF_REAL w;
@@ -293,39 +315,46 @@ MeasureTextEx  (HPDF_Font          font,
 
     attr = (HPDF_FontAttr)font->attr;
 
-    text = attr->text_cache;
-    pirf = attr->text_cache + (attr->text_cache_allocated / 2);
-    len  = attr->text_cache_len;
-    attr->text_cache_len = 0;
-    HPDF_MemSet (&attr->tw_cache, 0, sizeof attr->tw_cache);
-    *real_width = 0;
+    text = attr->text_cache + cache_begin;
+    pirf = attr->text_cache + cache_begin + (attr->text_cache_allocated / 2);
+    len  = attr->text_cache_len - cache_begin;
+    HPDF_MemSet (width, 0, sizeof *width);
     tmp_len = 0;
     nch = nsp = ntt = 0;
     tw = 0;
     w = v = 0;
 
     for (i = 0; i < len; i += bytes) {
-        HPDF_UCS4 b;
         HPDF_REAL tmp_w;
+        HPDF_UCS4 b;
+        HPDF_BYTE irf;
         HPDF_INT cw;
 
-        cw = attr->char_width_fn (font, HPDF_TRUE, pirf[i], text + i, &bytes, &b);
-
-        if (HPDF_IS_WHITE_SPACE(b)) {
-            tmp_len = i + bytes;
-            attr->text_cache_len = i;
-            *real_width = w;
-            attr->tw_cache.width = tw;
-            attr->tw_cache.numchars = nch;
-            attr->tw_cache.numspace = attr->tw_cache.numwords = nsp;
-            *numtatweels = ntt;
+        irf = pirf[i] & HPDF_RELIEF_FONT_INDEX_MASK;
+        cw = attr->char_width_fn (font, HPDF_TRUE, irf, text+i, &bytes, &b);
 
-            if (width < w || b == 0x0A || b == 0x0C || b == 0x0D)
-                return tmp_len;
+        if (pirf[i] & HPDF_INTERLINEAR_ANNOTATION)
+            continue;
 
-            if (b != 0x20) {
+        if (HPDF_IS_WHITE_SPACE(b) || b == 0x200B /* ZWSP */) {
+            width->linebytes = i + bytes;
+            width->numbytes = i;
+            width->numchars = nch;
+            width->numspaces = nsp;
+            width->numtatweels = ntt;
+            width->charswidth = tw;
+            width->width = w;
+
+            if (b == 0x0A || b == 0x0D)
+                return (width->flags |= HPDF_TLW_PRAGRAPH_BREAK);
+            if (b == 0x0C)
+                return (width->flags |= HPDF_TLW_PAGE_BREAK);
+            if (line_width < w)
+                return (width->flags |= HPDF_TLW_WORD_WRAP);
+
+            if (b != 0x20) {    /* TAB, ZWSP */
                 continue;
-            } else if (bytes == 1 && !IsCIDText (font, pirf[i])) {
+            } else if (bytes == 1 && !IsCIDText (font, irf)) {
                 nsp++;
                 w += word_space;
             }
@@ -341,35 +370,23 @@ MeasureTextEx  (HPDF_Font          font,
                     hyphen_w += char_space;
                 }
                 tmp_w = hyphen_w;
-                if (width < v + tmp_w ||
+                if (line_width < v + tmp_w ||
                     (!(options & HPDF_MEASURE_CAN_SHORTEN) &&
-                     width < w + tmp_w))
-                    return tmp_len;
+                     line_width < w + tmp_w))
+                    return (width->flags |= HPDF_TLW_WORD_WRAP);
             }
 
-            tmp_len = i + bytes;
-            attr->text_cache_len = i + bytes;
-            *real_width = w + tmp_w;
-            attr->tw_cache.width = tw + cw;
-            attr->tw_cache.numchars = nch;
-            attr->tw_cache.numspace = attr->tw_cache.numwords = nsp;
-            *numtatweels = ntt;
-
-            if (width < w + tmp_w)
-                return tmp_len;
+            width->linebytes = i + bytes;
+            width->numbytes = i + bytes;
+            width->numchars = nch;
+            width->numspaces = nsp;
+            width->numtatweels = ntt;
+            width->charswidth = tw + cw;
+            width->width = w + tmp_w;
 
-            continue;
-        } else if (b == 0x200B) { /* ZWSP */
-            tmp_len = i + bytes;
-            attr->text_cache_len = i;
-            *real_width = w;
-            attr->tw_cache.width = tw;
-            attr->tw_cache.numchars = nch;
-            attr->tw_cache.numspace = attr->tw_cache.numwords = nsp;
-            *numtatweels = ntt;
-
-            if (width < w)
-                return tmp_len;
+            if (line_width < w + tmp_w)
+                return (width->flags |=
+                        (HPDF_TLW_WORD_WRAP | HPDF_TLW_HYPHENATION));
 
             continue;
         } else if ((b <= 0x001F) ||
@@ -381,59 +398,62 @@ MeasureTextEx  (HPDF_Font          font,
                    (0xFFF0 <= b && b <= 0xFFFF)) { /* control codes */
             continue;
         } else if (!(options & HPDF_MEASURE_WORD_WRAP) ||
-                    (can_break && CanBreakBefore (b))) {
-            tmp_len = i;
-            attr->text_cache_len = i;
-            *real_width = w;
-            attr->tw_cache.width = tw;
-            attr->tw_cache.numchars = nch;
-            attr->tw_cache.numspace = attr->tw_cache.numwords = nsp;
-            *numtatweels = ntt;
-
-            if (width < w)
-                return tmp_len;
+                   (!(pirf[i] & HPDF_INTERLINEAR_ANNOTATED) &&
+                    can_break && CanBreakBefore (b))) {
+            width->linebytes = i;
+            width->numbytes = i;
+            width->numchars = nch;
+            width->numspaces = nsp;
+            width->numtatweels = ntt;
+            width->charswidth = tw;
+            width->width = w;
+
+            if (line_width < w)
+                return width->flags;
         }
 
         if ((options & HPDF_MEASURE_WORD_WRAP) &&
-            (attr->type == HPDF_FONT_TYPE0_CID ||
-             attr->type == HPDF_FONT_TYPE0_TT))
+                (attr->type == HPDF_FONT_TYPE0_CID ||
+                 attr->type == HPDF_FONT_TYPE0_TT))
             can_break = CanBreakAfter (b);
 
-        nch++;
-
-        tw += cw;
         tmp_w = (HPDF_REAL)cw * font_size / 1000;
 
         if (b == 0x0640) {      /* Arabic tatweel */
             ntt++;
-            if (!(options & HPDF_MEASURE_IGNORE_TATWEEL)) {
+            if (options & HPDF_MEASURE_IGNORE_TATWEEL) {
+                width->flags |= HPDF_TLW_IGNORE_TATWEEL;
+            } else {
+                nch++;
+                tw += cw;
                 w += tmp_w;
                 if (0 < i)
                     w += char_space;
             }
         } else {
+            nch++;
+            tw += cw;
             w += tmp_w;
             v += tmp_w;
-            if (0 < i) {
+            if (0 < i)
                 w += char_space;
-                v += char_space;
-            }
         }
 
-        if (width < v || (!(options & HPDF_MEASURE_CAN_SHORTEN) && width < w))
-            return tmp_len;
+        if (line_width < v ||
+                (!(options & HPDF_MEASURE_CAN_SHORTEN) && line_width < w))
+            return (width->flags |= HPDF_TLW_WORD_WRAP);
     }
 
     /* all of text can be put in the specified width */
-    tmp_len = i;
-    attr->text_cache_len = i;
-    *real_width = w;
-    attr->tw_cache.width = tw;
-    attr->tw_cache.numchars = nch;
-    attr->tw_cache.numspace = attr->tw_cache.numwords = nsp;
-    *numtatweels = ntt;
-
-    return tmp_len;
+    width->linebytes = i;
+    width->numbytes = i;
+    width->numchars = nch;
+    width->numspaces = nsp;
+    width->numtatweels = ntt;
+    width->charswidth = tw;
+    width->width = w;
+
+    return width->flags;
 }
 
 
@@ -747,7 +767,7 @@ BiDi_FreeArrays  (HPDF_ConverterBiDi bidi)
 }
 
 
-static HPDF_UINT HPDF_STDCALL 
+static HPDF_UINT HPDF_STDCALL
 BiDi  (HPDF_Converter   converter,
        HPDF_UINT32      flags,
        const HPDF_BYTE *src,
@@ -915,7 +935,7 @@ BiDi_New   (HPDF_Alloc_Func alloc_fn,
 #endif /* LIBHPDF_ENABLE_BIDI */
 
 
-static HPDF_UINT HPDF_STDCALL 
+static HPDF_UINT HPDF_STDCALL
 EncConv  (HPDF_Converter   converter,
           HPDF_UINT32      flags,
           const HPDF_BYTE *src,
@@ -946,7 +966,7 @@ EncConv  (HPDF_Converter   converter,
 }
 
 
-static HPDF_UINT HPDF_STDCALL 
+static HPDF_UINT HPDF_STDCALL
 Swap16  (HPDF_Converter   converter,
          HPDF_UINT32      flags,
          const HPDF_BYTE *src,
@@ -967,7 +987,7 @@ Swap16  (HPDF_Converter   converter,
 }
 
 
-static HPDF_UINT HPDF_STDCALL 
+static HPDF_UINT HPDF_STDCALL
 Swap32  (HPDF_Converter   converter,
          HPDF_UINT32      flags,
          const HPDF_BYTE *src,
@@ -1239,6 +1259,9 @@ HPDF_Font_ConvertText  (HPDF_Font        font,
     if (!text)
         return HPDF_OK;
 
+    if (!len)
+        len = HPDF_Font_StrLen(font, text, HPDF_LIMIT_MAX_STRING_LEN + 1);
+
     if (!attr->text_cache)
         HPDF_NormalizeCharEnc (&attr->encoder->charenc);
 
@@ -1276,6 +1299,7 @@ HPDF_Font_ConvertText  (HPDF_Font        font,
             return HPDF_CheckError (font->error);
     }
 
+    /* do convert */
     if (!list || list->count <= 0) {
         HPDF_MemCpy (attr->text_cache, text, attr->text_cache_len);
         text = (char *)(dst = attr->text_cache);
@@ -1291,13 +1315,21 @@ HPDF_Font_ConvertText  (HPDF_Font        font,
         }
     }
 
+    /* set relief font index */
+    if (attr->relief_font)
+        SetReliefFontIndex (font);
+
+    /* remove control character */
     if (!(flags & HPDF_CONVERT_HOLD_CHARACTERS)) {
         HPDF_UINT bytes;
         HPDF_UCS4 b = 0;
+        HPDF_UINT irfofs = attr->text_cache_allocated / 2;
 
         for (i = 0; i < attr->text_cache_len;) {
             b = HPDF_Encoder_GetUcs4 (attr->encoder, (const HPDF_BYTE *)text,
                     &bytes);
+            if (!bytes)
+                bytes = 1;
             i += bytes;
             if ((b <= 0x001F) ||
                 (0x007F <= b && b <= 0x009F) ||
@@ -1309,63 +1341,59 @@ HPDF_Font_ConvertText  (HPDF_Font        font,
                 (0xFFF0 <= b && b <= 0xFFFF)) /* control codes */
                 text += bytes;
             else
-                while (bytes--)
+                while (bytes--) {
+                    dst[irfofs] = ((const HPDF_BYTE *)text)[irfofs];
                     *dst++ = *(const HPDF_BYTE *)text++;
+                }
         }
         if (b == 0x00AD) {
+            HPDF_BYTE irf;
+            HPDF_Font_GetReliefFont (font, '-', &irf);
+            bytes = 1;
             if (attr->encoder->charenc == HPDF_CHARENC_UNSUPPORTED ||
                 attr->encoder->charenc == HPDF_CHARENC_UTF8)
-                *dst++ = '-';
+                *dst = '-';
             else
-                dst += UCS4TO_FNS[attr->encoder->charenc] (dst, '-');
+                bytes = UCS4TO_FNS[attr->encoder->charenc] (dst, '-');
+            while (bytes--)
+                (dst++)[irfofs] = irf;
         }
         attr->text_cache_len = (HPDF_UINT)(dst - attr->text_cache);
     }
 
-    /* set relief font index */
-    HPDF_MemSet (attr->text_cache + (attr->text_cache_allocated / 2),
-                 0,                  attr->text_cache_allocated / 2);
-    if (attr->relief_font)
-        SetReliefFontIndex (font);
-
     return HPDF_OK;
 }
 
 
 static HPDF_UINT
-GetUncovertedBytes  (HPDF_Font   font,
-                     const char *text,
-                     HPDF_UINT   len,
-                     HPDF_UINT  *numbytes)
+GetUncovertedBytes  (HPDF_Font           font,
+                     const char         *text,
+                     HPDF_UINT           cache_begin,
+                     HPDF_TextLineWidth *width)
 {
     HPDF_FontAttr attr;
     HPDF_CharEnc src_charenc;
     HPDF_CharEnc dst_charenc;
-    HPDF_UINT i, j, tmp_len;
+    HPDF_UINT i, j, numbytes;
 
     attr = (HPDF_FontAttr)font->attr;
     dst_charenc = attr->encoder->charenc;
 
-    if (dst_charenc == HPDF_CHARENC_UNSUPPORTED) {
-        if (numbytes)
-            *numbytes = attr->text_cache_len;
-        return len;
-    }
+    if (dst_charenc == HPDF_CHARENC_UNSUPPORTED)
+        return width->linebytes;
 
     src_charenc = GetSourceCharEnc (font);
 
-    i = 0;
-    j = 0;
-    tmp_len = 0;
-    while (i < len) {
-        i += BYTES_FNS[dst_charenc] (attr->text_cache + i);
+    i = j = numbytes = 0;
+    while (i < width->linebytes) {
+        i += BYTES_FNS[dst_charenc] (attr->text_cache + cache_begin + i);
         j += BYTES_FNS[src_charenc] ((const HPDF_BYTE *)text + j);
-        if (attr->text_cache_len == i)
-            tmp_len = j;
+        if (width->numbytes == i)
+            numbytes = j;
     }
 
-    if (numbytes)
-        *numbytes = tmp_len;
+    width->numbytes = numbytes;
+    width->linebytes = j;
 
     return j;
 }
@@ -1589,8 +1617,7 @@ HPDF_Font_SetReliefFont  (HPDF_Font   font,
 
     if (rf_attr->encoder != attr->encoder &&
         (rf_attr->encoder->charenc == HPDF_CHARENC_UNSUPPORTED ||
-         rf_attr->encoder->charenc != attr->encoder->charenc ||
-         rf_attr->writing_mode     != attr->writing_mode))
+         rf_attr->encoder->charenc != attr->encoder->charenc))
         return HPDF_RaiseError (font->error,
             HPDF_UNMATCHED_RELIEF_FONT, 0);
 
@@ -1616,7 +1643,8 @@ HPDF_Font_GetReliefFont  (HPDF_Font  font,
     HPDF_FontAttr rfattr = (HPDF_FontAttr)rf->attr;
 
     if (rfattr->fontdef->type != HPDF_FONT_TYPE1) {
-        for (; rf; rf = rfattr->relief_font, irf++) {
+        for (; rf && irf <= HPDF_RELIEF_FONT_INDEX_MASK;
+                    rf = rfattr->relief_font, irf++) {
             rfattr = (HPDF_FontAttr)rf->attr;
             if (rfattr->fontdef->type == HPDF_FONTDEF_TYPE_CID) {
                 /* cid-based font */
@@ -1634,8 +1662,11 @@ HPDF_Font_GetReliefFont  (HPDF_Font  font,
         }
     }
 
-    if (rf && index)
-        *index = irf;
+    if (HPDF_RELIEF_FONT_INDEX_MASK < irf)
+        rf = NULL;
+
+    if (index)
+        *index = (rf? irf: 0);
 
     return rf;
 }
@@ -1647,6 +1678,7 @@ SetReliefFontIndex  (HPDF_Font font)
     HPDF_FontAttr attr = (HPDF_FontAttr)font->attr;
     HPDF_Encoder encoder = attr->encoder;
     HPDF_BYTE irf = 0;
+    HPDF_BYTE irff = 0;
     HPDF_ParseText_Rec parse_state;
     HPDF_UINT i;
     HPDF_BYTE *pirf = attr->text_cache + (attr->text_cache_allocated / 2);
@@ -1665,10 +1697,26 @@ SetReliefFontIndex  (HPDF_Font font)
             HPDF_UCS4 b = HPDF_Encoder_ToUcs4 (encoder,
                     attr->text_cache + i, bytes);
 
-            if (!HPDF_Font_GetReliefFont (font, b, &irf))
-                irf = 0xFF;
+            HPDF_Font_GetReliefFont (font, b, &irf);
+
+            switch (b) {
+                case 0xFFF9:    /* IAA */
+                    irff &= ~(HPDF_INTERLINEAR_ANNOTATED |
+                              HPDF_INTERLINEAR_ANNOTATION);
+                    irff |= HPDF_INTERLINEAR_ANNOTATED;
+                    break;
+                case 0xFFFA:    /* IAS */
+                    irff &= ~(HPDF_INTERLINEAR_ANNOTATED |
+                              HPDF_INTERLINEAR_ANNOTATION);
+                    irff |= HPDF_INTERLINEAR_ANNOTATION;
+                    break;
+                case 0xFFFB:    /* IAT */
+                    irff &= ~(HPDF_INTERLINEAR_ANNOTATED |
+                              HPDF_INTERLINEAR_ANNOTATION);
+                    break;
+            }
         }
-        pirf[i] = irf;
+        pirf[i] = irff | irf;
     }
 }
 
@@ -1679,14 +1727,13 @@ IsCIDText  (HPDF_Font font,
 {
     HPDF_FontAttr rfattr = (HPDF_FontAttr)font->attr;
 
-    if (index != 0xFF)
-        while (index-- && rfattr) {
-            if (!(font = rfattr->relief_font))
-                break;
-            rfattr = (HPDF_FontAttr)font->attr;
-        }
+    while (index-- && rfattr) {
+        if (!(font = rfattr->relief_font))
+            break;
+        rfattr = (HPDF_FontAttr)font->attr;
+    }
 
     return (rfattr->type == HPDF_FONT_TYPE0_TT &&
-            !(((HPDF_TTFontDefAttr)rfattr->fontdef->attr)->options &
-             HPDF_FONTOPT_WITH_CID_MAP));
+            (((HPDF_TTFontDefAttr)rfattr->fontdef->attr)->options &
+             HPDF_FONTOPT_WITHOUT_CID_MAP));
 }
diff --git a/src/hpdf_font_cid.c b/src/hpdf_font_cid.c
index da3b402..9ff2cc2 100644
--- a/src/hpdf_font_cid.c
+++ b/src/hpdf_font_cid.c
@@ -134,7 +134,7 @@ HPDF_Type0Font_New  (HPDF_MMgr        mmgr,
         ret += HPDF_Dict_AddName (font, "Encoding", encoder->name);
     } else {
         ttfontdef_attr = (HPDF_TTFontDefAttr)fontdef->attr;
-        if (!(ttfontdef_attr->options & HPDF_FONTOPT_WITH_CID_MAP)) {
+        if (ttfontdef_attr->options & HPDF_FONTOPT_WITHOUT_CID_MAP) {
             ret += HPDF_Dict_AddName (font, "Encoding",
                     ((attr->writing_mode == HPDF_WMODE_HORIZONTAL)?
                      "Identity-H": "Identity-V"));
@@ -151,7 +151,7 @@ HPDF_Type0Font_New  (HPDF_MMgr        mmgr,
 
     if (ttfontdef_attr &&
         !(ttfontdef_attr->options & HPDF_FONTOPT_WITHOUT_TOUNICODE_MAP)) {
-        if (!(ttfontdef_attr->options & HPDF_FONTOPT_WITH_CID_MAP))
+        if (ttfontdef_attr->options & HPDF_FONTOPT_WITHOUT_CID_MAP)
             attr->to_unicode_stream =
                     CreateCMap (encoder, xref, HPDF_CMapType_CidToUnicode);
         else
@@ -388,7 +388,7 @@ CIDFontType2_New (HPDF_Font parent, HPDF_Xref xref)
     if (HPDF_Dict_Add (font, "DW2", array) != HPDF_OK)
         return NULL;
 
-    ret += HPDF_Array_AddNumber (array, (HPDF_INT32)(fontdef->font_bbox.bottom));
+    ret += HPDF_Array_AddNumber (array, (HPDF_INT32)(fontdef->font_bbox.top));
     ret += HPDF_Array_AddNumber (array, (HPDF_INT32)(fontdef->font_bbox.bottom -
                 fontdef->font_bbox.top));
 
@@ -548,6 +548,7 @@ CIDFontType2_BeforeWrite_Func  (HPDF_Dict obj)
         ret += HPDF_Dict_AddName (descriptor, "Type", "FontDescriptor");
         ret += HPDF_Dict_AddNumber (descriptor, "Ascent", def->ascent);
         ret += HPDF_Dict_AddNumber (descriptor, "Descent", def->descent);
+        ret += HPDF_Dict_AddNumber (descriptor, "CapHeight", def->cap_height);
         ret += HPDF_Dict_AddNumber (descriptor, "Flags", def->flags);
 
         array = HPDF_Box_Array_New (obj->mmgr, def->font_bbox);
@@ -592,11 +593,8 @@ CharWidth  (HPDF_Font        font,
 
     if (converted) {
         code = HPDF_Encoder_GetUcs4 (attr->encoder, text, bytes);
-        if (irf != 0xFF)
-            while (irf-- && font)
-                font = ((HPDF_FontAttr)font->attr)->relief_font;
-        else
-            font = NULL;
+        while (irf-- && font)
+            font = ((HPDF_FontAttr)font->attr)->relief_font;
     } else {
         code = HPDF_Font_GetUcs4 (font, (const char *)text, bytes);
         font = HPDF_Font_GetReliefFont (font, code, NULL);
diff --git a/src/hpdf_font_tt.c b/src/hpdf_font_tt.c
index c2ae0b4..797bd41 100644
--- a/src/hpdf_font_tt.c
+++ b/src/hpdf_font_tt.c
@@ -240,11 +240,8 @@ CharWidth  (HPDF_Font        font,
         *bytes = 1;
 
     if (converted) {
-        if (irf != 0xFF)
-            while (irf-- && font)
-                font = ((HPDF_FontAttr)font->attr)->relief_font;
-        else
-            font = NULL;
+        while (irf-- && font)
+            font = ((HPDF_FontAttr)font->attr)->relief_font;
     } else {
         font = HPDF_Font_GetReliefFont (font, *ucs4, NULL);
     }
diff --git a/src/hpdf_font_type1.c b/src/hpdf_font_type1.c
index 606ea8b..c5b6dae 100644
--- a/src/hpdf_font_type1.c
+++ b/src/hpdf_font_type1.c
@@ -164,6 +164,7 @@ Type1Font_CreateDescriptor  (HPDF_MMgr  mmgr,
         ret += HPDF_Dict_AddName (descriptor, "Type", "FontDescriptor");
         ret += HPDF_Dict_AddNumber (descriptor, "Ascent", def->ascent);
         ret += HPDF_Dict_AddNumber (descriptor, "Descent", def->descent);
+        ret += HPDF_Dict_AddNumber (descriptor, "CapHeight", def->cap_height);
         ret += HPDF_Dict_AddNumber (descriptor, "Flags", def->flags);
 
         array = HPDF_Box_Array_New (mmgr, def->font_bbox);
diff --git a/src/hpdf_gstate.c b/src/hpdf_gstate.c
index 4e758ba..fec051d 100644
--- a/src/hpdf_gstate.c
+++ b/src/hpdf_gstate.c
@@ -65,8 +65,10 @@ HPDF_GState_New  (HPDF_MMgr    mmgr,
         gstate->gray_stroke = current->gray_stroke;
 
         gstate->font = current->font;
-        gstate->font_size = current->font_size;
         gstate->actual_font = current->actual_font;
+        gstate->font_size = current->font_size;
+        gstate->actual_font_size = current->actual_font_size;
+        gstate->ia_font_size_ratio = current->ia_font_size_ratio;
         gstate->writing_mode = current->writing_mode;
 
         gstate->prev = current;
@@ -106,8 +108,10 @@ HPDF_GState_New  (HPDF_MMgr    mmgr,
         gstate->gray_stroke = 0;
 
         gstate->font = NULL;
-        gstate->font_size = 0;
         gstate->actual_font = NULL;
+        gstate->font_size = 0;
+        gstate->actual_font_size = 0;
+        gstate->ia_font_size_ratio = 0.5F;
         gstate->writing_mode = HPDF_WMODE_HORIZONTAL;
 
         gstate->prev = NULL;
diff --git a/src/hpdf_page_operator.c b/src/hpdf_page_operator.c
index b366879..e900b82 100644
--- a/src/hpdf_page_operator.c
+++ b/src/hpdf_page_operator.c
@@ -25,11 +25,37 @@ static const HPDF_DashMode INIT_MODE = {{0, 0, 0, 0, 0, 0, 0, 0}, 0, 0};
 
 
 static HPDF_STATUS
-InternalWriteText  (HPDF_Page        page,
-                    HPDF_REAL        tw,
-                    const char      *prefix,
-                    const char      *operator);
+SetCharSpace  (HPDF_Page  page,
+               HPDF_REAL  value);
 
+static HPDF_STATUS
+SetWordSpace  (HPDF_Page  page,
+               HPDF_REAL  value);
+
+static HPDF_STATUS
+SetFontAndSize  (HPDF_Page  page,
+                 HPDF_Font  font,
+                 HPDF_BYTE  flags,
+                 HPDF_BOOL  set_word_char_space,
+                 HPDF_BOOL  move_to_text_pos);
+
+static HPDF_Font
+GetActualFont  (HPDF_Page  page,
+                HPDF_UINT  index);
+
+static HPDF_STATUS
+SetTextRise  (HPDF_Page  page);
+
+static HPDF_STATUS
+SetTextMatrix  (HPDF_Page page);
+
+static HPDF_TransMatrix
+GetActualTextMatrix  (HPDF_Page page);
+
+static HPDF_STATUS
+InternalWriteText  (HPDF_Page page,
+                    HPDF_BOOL fake_matrix_pos,
+                    char      oper);
 
 static HPDF_STATUS
 InternalArc  (HPDF_Page    page,
@@ -40,6 +66,13 @@ InternalArc  (HPDF_Page    page,
               HPDF_REAL    ang2,
               HPDF_BOOL    cont_flg);
 
+static HPDF_STATUS
+MoveTextPosAbs  (HPDF_Page page,
+                 HPDF_REAL xAbs,
+                 HPDF_REAL yAbs,
+                 HPDF_BOOL sideways,
+                 HPDF_BOOL keep_line);
+
 
 /*--- General graphics state ---------------------------------------------*/
 
@@ -1027,15 +1060,33 @@ HPDF_Page_SetCharSpace  (HPDF_Page  page,
     if (value < HPDF_MIN_CHARSPACE || value > HPDF_MAX_CHARSPACE)
         return HPDF_RaiseError (page->error, HPDF_PAGE_OUT_OF_RANGE, 0);
 
+    attr->gstate->char_space = value;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED ||
+        attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS) {
+        attr->gstate->actual_font = NULL;
+        return HPDF_OK;
+    }
+
+    return SetCharSpace (page, attr->gstate->char_space);
+}
+
+static HPDF_STATUS
+SetCharSpace  (HPDF_Page  page,
+               HPDF_REAL  value)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED)
+        value = -value;
+
     if (HPDF_Stream_WriteReal (attr->stream, value) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
     if (HPDF_Stream_WriteStr (attr->stream, " Tc\012") != HPDF_OK)
         return HPDF_CheckError (page->error);
 
-    attr->gstate->char_space = value;
-
-    return ret;
+    return HPDF_OK;
 }
 
 /* Tw */
@@ -1057,15 +1108,33 @@ HPDF_Page_SetWordSpace  (HPDF_Page  page,
     if (value < HPDF_MIN_WORDSPACE || value > HPDF_MAX_WORDSPACE)
         return HPDF_RaiseError (page->error, HPDF_PAGE_OUT_OF_RANGE, 0);
 
+    attr->gstate->word_space = value;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED ||
+        attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS) {
+        attr->gstate->actual_font = NULL;
+        return HPDF_OK;
+    }
+
+    return SetWordSpace (page, attr->gstate->word_space);
+}
+
+static HPDF_STATUS
+SetWordSpace  (HPDF_Page  page,
+               HPDF_REAL  value)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED)
+        value = -value;
+
     if (HPDF_Stream_WriteReal (attr->stream, value) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
     if (HPDF_Stream_WriteStr (attr->stream, " Tw\012") != HPDF_OK)
         return HPDF_CheckError (page->error);
 
-    attr->gstate->word_space = value;
-
-    return ret;
+    return HPDF_OK;
 }
 
 /* Tz */
@@ -1135,6 +1204,8 @@ HPDF_Page_SetFontAndSize  (HPDF_Page  page,
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_PAGE_DESCRIPTION |
                     HPDF_GMODE_TEXT_OBJECT);
     HPDF_PageAttr attr;
+    HPDF_Font oldfont;
+    HPDF_WritingMode oldwmode;
 
     HPDF_PTRACE ((" HPDF_Page_SetFontAndSize\n"));
 
@@ -1152,70 +1223,146 @@ HPDF_Page_SetFontAndSize  (HPDF_Page  page,
 
     attr = (HPDF_PageAttr)page->attr;
 
+    oldfont  = attr->gstate->actual_font;
+    oldwmode = attr->gstate->writing_mode;
+
     attr->gstate->font = font;
     attr->gstate->font_size = size;
     attr->gstate->actual_font = NULL;
-    attr->gstate->writing_mode = ((HPDF_FontAttr)font->attr)->writing_mode;
+
+    if (!((HPDF_FontAttr)font->attr)->relief_font) {
+        attr->gstate->writing_mode = ((HPDF_FontAttr)font->attr)->writing_mode;
+        if ((ret = SetFontAndSize (page, font, 0, HPDF_FALSE, HPDF_FALSE))
+                != HPDF_OK)
+            return ret;
+    } else {
+        HPDF_Font rf;
+        attr->gstate->writing_mode = HPDF_WMODE_HORIZONTAL;
+        for (rf = font; rf; rf = ((HPDF_FontAttr)rf->attr)->relief_font) {
+            if (((HPDF_FontAttr)rf->attr)->writing_mode ==
+                    HPDF_WMODE_VERTICAL) {
+                attr->gstate->writing_mode = HPDF_WMODE_MIXED;
+                break;
+            }
+        }
+    }
+
+    if ((attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL ||
+         attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) &&
+        (oldwmode == HPDF_WMODE_MIXED ||
+         oldwmode == HPDF_WMODE_SIDEWAYS)) {
+        if (!oldfont || oldwmode == HPDF_WMODE_SIDEWAYS)
+            if ((ret = SetTextMatrix (page)) != HPDF_OK)
+                return ret;
+        if (!oldfont || (oldwmode == HPDF_WMODE_MIXED &&
+                attr->gstate->word_space))
+            if ((ret = SetWordSpace (page, attr->gstate->word_space))
+                    != HPDF_OK)
+                return ret;
+        if (!oldfont || (oldwmode == HPDF_WMODE_MIXED &&
+                attr->gstate->char_space))
+            if ((ret = SetCharSpace (page, attr->gstate->char_space))
+                    != HPDF_OK)
+                return ret;
+        if ((ret = SetTextRise (page)) != HPDF_OK)
+            return ret;
+    }
 
     return ret;
 }
 
+static HPDF_STATUS
+SetFontAndSize  (HPDF_Page  page,
+                 HPDF_Font  font,
+                 HPDF_BYTE  flags,
+                 HPDF_BOOL  set_word_char_space,
+                 HPDF_BOOL  move_to_text_pos)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+    HPDF_Font oldfont = attr->gstate->actual_font;
+    HPDF_REAL oldsize = attr->gstate->actual_font_size;
+    HPDF_REAL size = attr->gstate->font_size;
+    HPDF_WritingMode oldwmode = attr->gstate->writing_mode;
+    HPDF_STATUS ret = HPDF_OK;
 
-static HPDF_Font
-GetActualFont  (HPDF_Page  page,
-                HPDF_UINT  index)
-{
-    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr; 
-    HPDF_Font  font;
+    if (flags & HPDF_INTERLINEAR_ANNOTATION)
+        size *= attr->gstate->ia_font_size_ratio;
 
-    if (index == 0xFF)
-        return attr->gstate->actual_font;
+    if (font != oldfont || size != oldsize) {
+        char buf[HPDF_TMP_BUF_SIZ];
+        char *pbuf = buf;
+        char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
+        const char *local_name;
 
-    for (font = attr->gstate->font; index && font; index--)
-        font = ((HPDF_FontAttr)font->attr)->relief_font;
+        local_name = HPDF_Page_GetLocalFontName (page, font);
 
-    return font;
-}
+        if (!local_name)
+            return HPDF_RaiseError (page->error, HPDF_PAGE_INVALID_FONT, 0);
 
+        if (HPDF_Stream_WriteEscapeName (attr->stream, local_name) != HPDF_OK)
+            return HPDF_CheckError (page->error);
 
-static HPDF_STATUS
-SetActualFont  (HPDF_Page  page,
-                HPDF_Font  font)
-{
-    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr; 
-    char buf[HPDF_TMP_BUF_SIZ];
-    char *pbuf = buf;
-    char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
-    const char *local_name;
+        HPDF_MemSet (buf, 0, HPDF_TMP_BUF_SIZ);
+        *pbuf++ = ' ';
+        pbuf = HPDF_FToA (pbuf, size, eptr);
+        HPDF_StrCpy (pbuf, " Tf\012", eptr);
 
-    if (!HPDF_Font_Validate(font))
-        return HPDF_RaiseError (page->error, HPDF_PAGE_INVALID_FONT, 0);
+        if (HPDF_Stream_WriteStr (attr->stream, buf) != HPDF_OK)
+            return HPDF_CheckError (page->error);
 
-    if (font == attr->gstate->actual_font)
-        return HPDF_OK;
+        attr->gstate->actual_font = font;
+        attr->gstate->actual_font_size = size;
+    }
 
-    attr->gstate->actual_font = font;
+    if (oldwmode == HPDF_WMODE_MIXED || oldwmode == HPDF_WMODE_SIDEWAYS) {
+        HPDF_FontAttr font_attr = (HPDF_FontAttr)font->attr;
 
-    local_name = HPDF_Page_GetLocalFontName (page, font);
+        attr->gstate->writing_mode =
+                ((font_attr->writing_mode == HPDF_WMODE_HORIZONTAL)?
+                 HPDF_WMODE_SIDEWAYS: HPDF_WMODE_MIXED);
 
-    if (!local_name)
-        return HPDF_RaiseError (page->error, HPDF_PAGE_INVALID_FONT, 0);
+        if (!oldfont || attr->gstate->writing_mode != oldwmode) {
+            if (move_to_text_pos) {
+                attr->text_matrix.x = attr->text_pos.x;
+                attr->text_matrix.y = attr->text_pos.y;
+            }
+            if ((ret = SetTextMatrix (page)) != HPDF_OK)
+                return ret;
+        }
+        if (!oldfont || attr->gstate->writing_mode != oldwmode ||
+                attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS)
+            if ((ret = SetTextRise (page)) != HPDF_OK)
+                return ret;
+        if (set_word_char_space?
+                (!oldfont || attr->gstate->writing_mode != oldwmode):
+                (attr->gstate->writing_mode == HPDF_WMODE_MIXED)) {
+            if (!oldfont || !set_word_char_space || attr->gstate->word_space)
+                if ((ret = SetWordSpace (page, attr->gstate->word_space))
+                        != HPDF_OK)
+                    return ret;
+            if (!oldfont || !set_word_char_space || attr->gstate->char_space)
+                if ((ret = SetCharSpace (page, attr->gstate->char_space))
+                        != HPDF_OK)
+                    return ret;
+        }
+    }
 
-    if (HPDF_Stream_WriteEscapeName (attr->stream, local_name) != HPDF_OK)
-        return HPDF_CheckError (page->error);
+    return HPDF_OK;
+}
 
-    HPDF_MemSet (buf, 0, HPDF_TMP_BUF_SIZ);
-    *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, attr->gstate->font_size, eptr);
-    HPDF_StrCpy (pbuf, " Tf\012", eptr);
+static HPDF_Font
+GetActualFont  (HPDF_Page  page,
+                HPDF_UINT  index)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+    HPDF_Font  font;
 
-    if (HPDF_Stream_WriteStr (attr->stream, buf) != HPDF_OK)
-        return HPDF_CheckError (page->error);
+    for (font = attr->gstate->font; index && font; index--)
+        font = ((HPDF_FontAttr)font->attr)->relief_font;
 
-    return HPDF_OK;
+    return font;
 }
 
-
 /* Tr */
 HPDF_EXPORT(HPDF_STATUS)
 HPDF_Page_SetTextRenderingMode  (HPDF_Page               page,
@@ -1255,7 +1402,6 @@ HPDF_Page_SetTextRaise  (HPDF_Page  page,
     return HPDF_Page_SetTextRise (page, value);
 }
 
-
 HPDF_EXPORT(HPDF_STATUS)
 HPDF_Page_SetTextRise  (HPDF_Page  page,
                         HPDF_REAL  value)
@@ -1271,17 +1417,53 @@ HPDF_Page_SetTextRise  (HPDF_Page  page,
 
     attr = (HPDF_PageAttr)page->attr;
 
+    attr->gstate->text_rise = value;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED ||
+        attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS) {
+        attr->gstate->actual_font = NULL;
+        return HPDF_OK;
+    }
+
+    return SetTextRise (page);
+}
+
+static HPDF_STATUS
+SetTextRise  (HPDF_Page  page)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+    HPDF_REAL value;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED) {
+        value = 0;
+    } else {
+        value = attr->gstate->text_rise;
+
+        if (attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS &&
+                attr->gstate->actual_font_size == attr->gstate->font_size) {
+            HPDF_Font font = attr->gstate->actual_font;
+            HPDF_FontAttr font_attr;
+
+            if (!font)
+                return HPDF_OK;
+
+            font_attr = (HPDF_FontAttr)font->attr;
+            value -= ((font_attr->fontdef->font_bbox.top +
+                       font_attr->fontdef->font_bbox.bottom) / 2 *
+                      attr->gstate->font_size / 1000);
+        }
+    }
+
     if (HPDF_Stream_WriteReal (attr->stream, value) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
     if (HPDF_Stream_WriteStr (attr->stream, " Ts\012") != HPDF_OK)
         return HPDF_CheckError (page->error);
 
-    attr->gstate->text_rise = value;
-
-    return ret;
+    return HPDF_OK;
 }
 
+
 /*--- Text positioning ---------------------------------------------------*/
 
 /* Td */
@@ -1296,6 +1478,7 @@ HPDF_Page_MoveTextPos  (HPDF_Page  page,
     char *pbuf = buf;
     char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
     HPDF_PageAttr attr;
+    HPDF_TransMatrix mat;
 
     HPDF_PTRACE ((" HPDF_Page_MoveTextPos\n"));
 
@@ -1314,11 +1497,15 @@ HPDF_Page_MoveTextPos  (HPDF_Page  page,
     if (HPDF_Stream_WriteStr (attr->stream, buf) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
-    attr->text_matrix.x += x * attr->text_matrix.a + y * attr->text_matrix.c;
-    attr->text_matrix.y += y * attr->text_matrix.d + x * attr->text_matrix.b;
+    mat = GetActualTextMatrix (page);
+
+    attr->text_matrix.x += x * mat.a + y * mat.c;
+    attr->text_matrix.y += x * mat.b + y * mat.d;
     attr->text_pos.x = attr->text_matrix.x;
     attr->text_pos.y = attr->text_matrix.y;
 
+    attr->fake_text_pos = HPDF_FALSE;
+
     return ret;
 }
 
@@ -1333,6 +1520,7 @@ HPDF_Page_MoveTextPos2  (HPDF_Page  page,
     char *pbuf = buf;
     char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
     HPDF_PageAttr attr;
+    HPDF_TransMatrix mat;
 
     HPDF_PTRACE ((" HPDF_Page_MoveTextPos2\n"));
 
@@ -1351,12 +1539,16 @@ HPDF_Page_MoveTextPos2  (HPDF_Page  page,
     if (HPDF_Stream_WriteStr (attr->stream, buf) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
-    attr->text_matrix.x += x * attr->text_matrix.a + y * attr->text_matrix.c;
-    attr->text_matrix.y += y * attr->text_matrix.d + x * attr->text_matrix.b;
+    mat = GetActualTextMatrix (page);
+
+    attr->text_matrix.x += x * mat.a + y * mat.c;
+    attr->text_matrix.y += x * mat.b + y * mat.d;
     attr->text_pos.x = attr->text_matrix.x;
     attr->text_pos.y = attr->text_matrix.y;
     attr->gstate->text_leading = -y;
 
+    attr->fake_text_pos = HPDF_FALSE;
+
     return ret;
 }
 
@@ -1371,9 +1563,6 @@ HPDF_Page_SetTextMatrix  (HPDF_Page         page,
                           HPDF_REAL    y)
 {
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
-    char buf[HPDF_TMP_BUF_SIZ];
-    char *pbuf = buf;
-    char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
     HPDF_PageAttr attr;
 
     HPDF_PTRACE ((" HPDF_Page_SetTextMatrix\n"));
@@ -1386,36 +1575,76 @@ HPDF_Page_SetTextMatrix  (HPDF_Page         page,
     if ((a == 0 || d == 0) && (b == 0 || c == 0))
         return HPDF_RaiseError (page->error, HPDF_INVALID_PARAMETER, 0);
 
-    HPDF_MemSet (buf, 0, HPDF_TMP_BUF_SIZ);
+    attr->text_matrix.a = a;
+    attr->text_matrix.b = b;
+    attr->text_matrix.c = c;
+    attr->text_matrix.d = d;
+    attr->text_matrix.x = x;
+    attr->text_matrix.y = y;
+    attr->text_pos.x = attr->text_matrix.x;
+    attr->text_pos.y = attr->text_matrix.y;
 
-    pbuf = HPDF_FToA (pbuf, a, eptr);
+    attr->fake_text_pos = HPDF_FALSE;
+
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED ||
+        attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS) {
+        attr->gstate->actual_font = NULL;
+        return HPDF_OK;
+    }
+
+    return SetTextMatrix (page);
+}
+
+static HPDF_STATUS
+SetTextMatrix  (HPDF_Page page)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+    HPDF_TransMatrix mat = GetActualTextMatrix (page);
+    char buf[HPDF_TMP_BUF_SIZ];
+    char *pbuf = buf;
+    char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
+
+    pbuf = HPDF_FToA (pbuf, mat.a, eptr);
     *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, b, eptr);
+    pbuf = HPDF_FToA (pbuf, mat.b, eptr);
     *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, c, eptr);
+    pbuf = HPDF_FToA (pbuf, mat.c, eptr);
     *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, d, eptr);
+    pbuf = HPDF_FToA (pbuf, mat.d, eptr);
     *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, x, eptr);
+    pbuf = HPDF_FToA (pbuf, mat.x, eptr);
     *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, y, eptr);
+    pbuf = HPDF_FToA (pbuf, mat.y, eptr);
     HPDF_StrCpy (pbuf, " Tm\012", eptr);
 
     if (HPDF_Stream_WriteStr (attr->stream, buf) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
-    attr->text_matrix.a = a;
-    attr->text_matrix.b = b;
-    attr->text_matrix.c = c;
-    attr->text_matrix.d = d;
-    attr->text_matrix.x = x;
-    attr->text_matrix.y = y;
-    attr->text_pos.x = attr->text_matrix.x;
-    attr->text_pos.y = attr->text_matrix.y;
-
-    return ret;
+    return HPDF_OK;
 }
 
+static HPDF_TransMatrix
+GetActualTextMatrix  (HPDF_Page page)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+    HPDF_TransMatrix mat;
+
+    if (attr->gstate->writing_mode != HPDF_WMODE_SIDEWAYS) {
+        mat.a = attr->text_matrix.a;
+        mat.b = attr->text_matrix.b;
+        mat.c = attr->text_matrix.c;
+        mat.d = attr->text_matrix.d;
+    } else {
+        mat.a =  attr->text_matrix.b;
+        mat.b = -attr->text_matrix.a;
+        mat.c =  attr->text_matrix.d;
+        mat.d = -attr->text_matrix.c;
+    }
+    mat.x = attr->text_matrix.x;
+    mat.y = attr->text_matrix.y;
+
+    return mat;
+}
 
 /* T* */
 HPDF_EXPORT(HPDF_STATUS)
@@ -1423,6 +1652,7 @@ HPDF_Page_MoveToNextLine  (HPDF_Page  page)
 {
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
     HPDF_PageAttr attr;
+    HPDF_TransMatrix mat;
 
     HPDF_PTRACE ((" HPDF_Page_MoveToNextLine\n"));
 
@@ -1431,16 +1661,23 @@ HPDF_Page_MoveToNextLine  (HPDF_Page  page)
 
     attr = (HPDF_PageAttr)page->attr;
 
+    if (attr->gstate->writing_mode == HPDF_WMODE_MIXED)
+        return HPDF_Page_MoveTextPos (page, -attr->gstate->text_leading, 0);
+
     if (HPDF_Stream_WriteStr (attr->stream, "T*\012") != HPDF_OK)
         return HPDF_CheckError (page->error);
 
+    mat = GetActualTextMatrix (page);
+
     /* calculate the reference point of text */
-    attr->text_matrix.x -= attr->gstate->text_leading * attr->text_matrix.c;
-    attr->text_matrix.y -= attr->gstate->text_leading * attr->text_matrix.d;
+    attr->text_matrix.x -= attr->gstate->text_leading * mat.c;
+    attr->text_matrix.y -= attr->gstate->text_leading * mat.d;
 
     attr->text_pos.x = attr->text_matrix.x;
     attr->text_pos.y = attr->text_matrix.y;
 
+    attr->fake_text_pos = HPDF_FALSE;
+
     return ret;
 }
 
@@ -1453,7 +1690,8 @@ HPDF_Page_ShowText  (HPDF_Page    page,
 {
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
     HPDF_PageAttr attr;
-    HPDF_REAL tw;
+    HPDF_Font font;
+    HPDF_BOOL fake_matrix_pos;
 
     HPDF_PTRACE ((" HPDF_Page_ShowText\n"));
 
@@ -1461,22 +1699,36 @@ HPDF_Page_ShowText  (HPDF_Page    page,
         return ret;
 
     attr = (HPDF_PageAttr)page->attr;
+    font = attr->gstate->font;
 
     /* no font exists */
-    if (!attr->gstate->font)
+    if (!font)
         return HPDF_RaiseError (page->error, HPDF_PAGE_FONT_NOT_FOUND, 0);
 
-    tw = HPDF_Page_TextWidth (page, text);
-    if (!tw)
+    fake_matrix_pos = HPDF_FALSE;
+    if (attr->fake_text_pos) {
+        HPDF_REAL x = attr->text_matrix.x;
+        HPDF_REAL y = attr->text_matrix.y;
+        if ((ret = MoveTextPosAbs (page, attr->text_pos.x, attr->text_pos.y,
+                HPDF_FALSE, HPDF_FALSE)) != HPDF_OK)
+            return ret;
+        attr->text_matrix.x = x;
+        attr->text_matrix.y = y;
+        fake_matrix_pos = HPDF_TRUE;
+    }
+
+    HPDF_Font_CheckBiDi (font, HPDF_FALSE);
+    if ((ret = HPDF_Font_ConvertText (font, 0, text, 0)) != HPDF_OK)
         return ret;
 
-    if (InternalWriteText (page, tw, NULL, NULL) != HPDF_OK)
+    if (InternalWriteText (page, fake_matrix_pos, 0) != HPDF_OK)
         return HPDF_CheckError (page->error);
 
     return ret;
 }
 
-/* TJ */
+/* TJ --not implemented yet */
+
 /* ' */
 HPDF_EXPORT(HPDF_STATUS)
 HPDF_Page_ShowTextNextLine  (HPDF_Page    page,
@@ -1484,7 +1736,7 @@ HPDF_Page_ShowTextNextLine  (HPDF_Page    page,
 {
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
     HPDF_PageAttr attr;
-    HPDF_REAL tw;
+    HPDF_Font font;
 
     HPDF_PTRACE ((" HPDF_Page_ShowTextNextLine\n"));
 
@@ -1492,19 +1744,20 @@ HPDF_Page_ShowTextNextLine  (HPDF_Page    page,
         return ret;
 
     attr = (HPDF_PageAttr)page->attr;
+    font = attr->gstate->font;
 
     /* no font exists */
-    if (!attr->gstate->font)
+    if (!font)
         return HPDF_RaiseError (page->error, HPDF_PAGE_FONT_NOT_FOUND, 0);
 
-    if (text && !HPDF_Font_StrLen ((HPDF_Font)attr->gstate->font, text, 4))
+    if (text && !HPDF_Font_StrLen (font, text, 4))
         return HPDF_Page_MoveToNextLine(page);
 
-    tw = HPDF_Page_TextWidth (page, text);
-    if (!tw)
-        return HPDF_Page_MoveToNextLine(page);
+    HPDF_Font_CheckBiDi (font, HPDF_FALSE);
+    if ((ret = HPDF_Font_ConvertText (font, 0, text, 0)) != HPDF_OK)
+        return ret;
 
-    if (InternalWriteText (page, tw, NULL, " \'\012") != HPDF_OK)
+    if (InternalWriteText (page, HPDF_FALSE, '\'') != HPDF_OK)
         return HPDF_CheckError (page->error);
 
     return ret;
@@ -1519,10 +1772,7 @@ HPDF_Page_ShowTextNextLineEx  (HPDF_Page    page,
 {
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
     HPDF_PageAttr attr;
-    HPDF_REAL tw;
-    char buf[HPDF_TMP_BUF_SIZ];
-    char *pbuf = buf;
-    char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
+    HPDF_Font font;
 
     HPDF_PTRACE ((" HPDF_Page_ShowTextNextLineEX\n"));
 
@@ -1536,28 +1786,23 @@ HPDF_Page_ShowTextNextLineEx  (HPDF_Page    page,
         return HPDF_RaiseError (page->error, HPDF_PAGE_OUT_OF_RANGE, 0);
 
     attr = (HPDF_PageAttr)page->attr;
+    font = attr->gstate->font;
 
     /* no font exists */
-    if (!attr->gstate->font)
+    if (!font)
         return HPDF_RaiseError (page->error, HPDF_PAGE_FONT_NOT_FOUND, 0);
 
-    if (text && !HPDF_Font_StrLen ((HPDF_Font)attr->gstate->font, text, 4))
+    if (text && !HPDF_Font_StrLen (font, text, 4))
         return HPDF_Page_MoveToNextLine(page);
 
-    pbuf = HPDF_FToA (pbuf, word_space, eptr);
-    *pbuf++ = ' ';
-    pbuf = HPDF_FToA (pbuf, char_space, eptr);
-    *pbuf++ = ' ';
-    *pbuf = 0;
-
     attr->gstate->word_space = word_space;
     attr->gstate->char_space = char_space;
 
-    tw = HPDF_Page_TextWidth (page, text);
-    if (!tw)
-        return HPDF_Page_MoveToNextLine(page);
+    HPDF_Font_CheckBiDi (font, HPDF_FALSE);
+    if ((ret = HPDF_Font_ConvertText (font, 0, text, 0)) != HPDF_OK)
+        return ret;
 
-    if (InternalWriteText (page, tw, buf, " \"\012") != HPDF_OK)
+    if (InternalWriteText (page, HPDF_FALSE, '\"') != HPDF_OK)
         return HPDF_CheckError (page->error);
 
     return ret;
@@ -1574,7 +1819,6 @@ HPDF_Page_ShowTextNextLineEx  (HPDF_Page    page,
 /* SCN --not implemented yet */
 
 /* g */
-
 HPDF_EXPORT(HPDF_STATUS)
 HPDF_Page_SetGrayFill  (HPDF_Page  page,
                         HPDF_REAL  gray)
@@ -2312,39 +2556,194 @@ HPDF_Page_DrawImage  (HPDF_Page    page,
 
 
 static HPDF_STATUS
-InternalWriteText  (HPDF_Page        page,
-                    HPDF_REAL        tw,
-                    const char      *prefix,
-                    const char      *operator)
+InternalWriteText  (HPDF_Page page,
+                    HPDF_BOOL fake_matrix_pos,
+                    char      oper)
 {
-    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr; 
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
     HPDF_FontAttr font_attr = (HPDF_FontAttr)attr->gstate->font->attr;
+    HPDF_Point line_start_pos, text_start_pos;
     HPDF_STATUS ret;
     HPDF_UINT i, n;
-    HPDF_BYTE *pirf;
+    HPDF_BYTE *pirf, flags, nflags;
+    HPDF_REAL tw, tw_ia, rise_ia;
+    char op_buf[] = " ?\012";
+    const char *op_Tj = " Tj\012";
+    const char *op = op_Tj;
 
     HPDF_PTRACE ((" InternalWriteText\n"));
 
+    flags = 0;
+    tw_ia = tw = 0;
+    rise_ia = 0;
+
+    line_start_pos.x = attr->text_matrix.x;
+    line_start_pos.y = attr->text_matrix.y;
+    text_start_pos = attr->text_pos;
+    if (fake_matrix_pos) {
+        attr->text_matrix.x = text_start_pos.x;
+        attr->text_matrix.y = text_start_pos.y;
+    }
+
+    if (oper) {
+        op_buf[1] = oper;
+        op = op_buf;
+    }
+
     pirf = font_attr->text_cache +
             (font_attr->text_cache_allocated / 2);
 
-    for (i = 0, n = 1; n <= font_attr->text_cache_len; n++) {
+    for (i = 0, n = 0; n <= font_attr->text_cache_len; n++) {
         HPDF_Font rf;
         HPDF_FontAttr rf_attr;
+        HPDF_REAL rw;
 
-        if (n < font_attr->text_cache_len &&
-                (pirf[n] == 0xFF || pirf[n] == pirf[i]))
+        if (n < font_attr->text_cache_len && pirf[n] == pirf[i])
             continue;
 
-        rf = GetActualFont (page, pirf[i]);
-        rf_attr = (HPDF_FontAttr)rf->attr;
+        rf = GetActualFont (page, pirf[i] & HPDF_RELIEF_FONT_INDEX_MASK);
+        nflags = pirf[i] & ~HPDF_RELIEF_FONT_INDEX_MASK;
 
-        if ((ret = SetActualFont (page, rf)) != HPDF_OK)
+        if ((ret = SetFontAndSize (page, rf, nflags,
+                (op[1] != '\"'),
+                (op[1] != '\"' && op[1] != '\''))) != HPDF_OK)
             return ret;
 
-        if (!i && prefix)
-            if ((ret = HPDF_Stream_WriteStr (attr->stream, prefix)) != HPDF_OK)
+        if (nflags != flags) {
+            if (!(flags & HPDF_INTERLINEAR_ANNOTATED) &&
+                (nflags & HPDF_INTERLINEAR_ANNOTATED)) {
+                HPDF_Box bbox = HPDF_Font_GetBBox (rf);
+                if (attr->gstate->writing_mode == HPDF_WMODE_MIXED)
+                    rise_ia = (bbox.right - bbox.left) * 0.5F;
+                else if (attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS)
+                    rise_ia = (bbox.top - bbox.bottom) * 0.5F;
+                else
+                    rise_ia = bbox.top;
+                rise_ia *= attr->gstate->font_size / 1000;
+                tw_ia = tw;
+            }
+            if (!(flags & HPDF_INTERLINEAR_ANNOTATION) &&
+                (nflags & HPDF_INTERLINEAR_ANNOTATION)) {
+                HPDF_REAL aw, rise, dx, dy, x, y;
+                HPDF_Box bbox = HPDF_Font_GetBBox (rf);
+                HPDF_TextWidth w = HPDF_Font_TextCacheWidth (attr->gstate->font,
+                        HPDF_TRUE, i, n);
+                aw = w.width * attr->gstate->actual_font_size / 1000;
+                tw_ia += ((tw - tw_ia) / 2) - (aw / 2);
+                if (attr->gstate->writing_mode == HPDF_WMODE_MIXED)
+                    rise = (bbox.right - bbox.left) * 0.5F;
+                else
+                    rise = -bbox.bottom;
+                rise_ia += rise * attr->gstate->actual_font_size / 1000;
+                if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
+                    dx = tw_ia;
+                    dy = rise_ia;
+                } else {
+                    dx = rise_ia;
+                    dy = -tw_ia;
+                }
+                x = text_start_pos.x;
+                y = text_start_pos.y;
+                x += (dx * attr->text_matrix.a) + (dy * attr->text_matrix.c);
+                y += (dx * attr->text_matrix.b) + (dy * attr->text_matrix.d);
+                if ((ret = MoveTextPosAbs (page, x, y, HPDF_FALSE, HPDF_FALSE))
+                        != HPDF_OK)
+                    return ret;
+                if (attr->gstate->word_space &&
+                        (ret = SetWordSpace (page, 0)) != HPDF_OK)
+                    return ret;
+                if (attr->gstate->char_space &&
+                        (ret = SetCharSpace (page, 0)) != HPDF_OK)
+                    return ret;
+                tw_ia = tw;
+            }
+            if (  (flags & HPDF_INTERLINEAR_ANNOTATION) &&
+                !(nflags & HPDF_INTERLINEAR_ANNOTATION)) {
+                HPDF_REAL dx, dy, x, y;
+                if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
+                    dx = tw_ia;
+                    dy = 0;
+                } else {
+                    dx = 0;
+                    dy = -tw_ia;
+                }
+                x = text_start_pos.x;
+                y = text_start_pos.y;
+                x += (dx * attr->text_matrix.a) + (dy * attr->text_matrix.c);
+                y += (dx * attr->text_matrix.b) + (dy * attr->text_matrix.d);
+                if ((ret = MoveTextPosAbs (page, x, y, HPDF_FALSE, HPDF_FALSE))
+                        != HPDF_OK)
+                    return ret;
+                if (attr->gstate->word_space &&
+                        (ret = SetWordSpace (page, attr->gstate->word_space))
+                        != HPDF_OK)
+                    return ret;
+                if (attr->gstate->char_space &&
+                        (ret = SetCharSpace (page, attr->gstate->char_space))
+                        != HPDF_OK)
+                    return ret;
+            }
+            flags = nflags;
+        }
+
+        rw = 0;
+        if (!(flags & HPDF_INTERLINEAR_ANNOTATION)) {
+            HPDF_TextWidth w = HPDF_Font_TextCacheWidth (attr->gstate->font,
+                    HPDF_FALSE, i, n);
+            rw = ((w.width * attr->gstate->font_size / 1000) +
+                    (w.numspace * attr->gstate->word_space) +
+                    (w.numchars * attr->gstate->char_space));
+            tw += rw;
+        }
+
+        if (op[1] == '\'' || op[1] == '\"') {
+            if (attr->gstate->writing_mode == HPDF_WMODE_MIXED) {
+                op = op_Tj;
+                if ((ret = HPDF_Page_MoveTextPos (page,
+                        -attr->gstate->text_leading, 0)) != HPDF_OK)
+                    return ret;
+            } else {
+                if (attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS) {
+                    attr->text_matrix.x -=
+                            attr->gstate->text_leading * attr->text_matrix.a;
+                    attr->text_matrix.y -=
+                            attr->gstate->text_leading * attr->text_matrix.b;
+                } else {
+                    attr->text_matrix.x -=
+                            attr->gstate->text_leading * attr->text_matrix.c;
+                    attr->text_matrix.y -=
+                            attr->gstate->text_leading * attr->text_matrix.d;
+                }
+                attr->text_pos.x = attr->text_matrix.x;
+                attr->text_pos.y = attr->text_matrix.y;
+            }
+            text_start_pos = line_start_pos = attr->text_pos;
+        }
+        if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
+            attr->text_pos.x += rw * attr->text_matrix.a;
+            attr->text_pos.y += rw * attr->text_matrix.b;
+        } else {
+            attr->text_pos.x -= rw * attr->text_matrix.c;
+            attr->text_pos.y -= rw * attr->text_matrix.d;
+        }
+
+        if (op[1] == '\"') {
+            char buf[HPDF_TMP_BUF_SIZ];
+            char *pbuf;
+            char *eptr = buf + HPDF_TMP_BUF_SIZ - 1;
+
+            pbuf = buf;
+            pbuf = HPDF_FToA (pbuf, attr->gstate->word_space, eptr);
+            *pbuf++ = ' ';
+            pbuf = HPDF_FToA (pbuf, attr->gstate->char_space, eptr);
+            *pbuf++ = ' ';
+            *pbuf = 0;
+
+            if ((ret = HPDF_Stream_WriteStr (attr->stream, buf)) != HPDF_OK)
                 return ret;
+        }
+
+        rf_attr = (HPDF_FontAttr)rf->attr;
 
         if (rf_attr->type == HPDF_FONT_TYPE0_TT ||
             rf_attr->type == HPDF_FONT_TYPE0_CID) {
@@ -2353,18 +2752,18 @@ InternalWriteText  (HPDF_Page        page,
 
             if ((ret = HPDF_Stream_WriteStr (attr->stream, "<")) != HPDF_OK)
                 return ret;
-        
+
             if (rf_attr->type == HPDF_FONT_TYPE0_TT)
                 ttfontdef_attr = (HPDF_TTFontDefAttr)rf_attr->fontdef->attr;
             if (ttfontdef_attr &&
-                !(ttfontdef_attr->options & HPDF_FONTOPT_WITH_CID_MAP))
+                (ttfontdef_attr->options & HPDF_FONTOPT_WITHOUT_CID_MAP))
                 encoder = rf_attr->encoder;
 
             if ((ret = HPDF_Stream_WriteBinary (attr->stream,
                     font_attr->text_cache + i, n - i, NULL, encoder))
                     != HPDF_OK)
                 return ret;
-        
+
             if ((ret = HPDF_Stream_WriteStr (attr->stream, ">")) != HPDF_OK)
                 return ret;
         } else {
@@ -2373,28 +2772,29 @@ InternalWriteText  (HPDF_Page        page,
                 return ret;
         }
 
-        if ((ret = HPDF_Stream_WriteStr (attr->stream,
-                ((i || !operator)? " Tj\012": operator))) != HPDF_OK)
+        if ((ret = HPDF_Stream_WriteStr (attr->stream, op)) != HPDF_OK)
             return ret;
 
+        op = op_Tj;
         i = n;
     }
 
-    /* calculate the reference point of text */
-    if (operator) {
-        attr->text_matrix.x -= attr->gstate->text_leading * attr->text_matrix.c;
-        attr->text_matrix.y -= attr->gstate->text_leading * attr->text_matrix.d;
-    
-        attr->text_pos.x = attr->text_matrix.x;
-        attr->text_pos.y = attr->text_matrix.y;
-    }
-
-    if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-        attr->text_pos.x += tw * attr->text_matrix.a;
-        attr->text_pos.y += tw * attr->text_matrix.b;
-    } else {
-        attr->text_pos.x -= tw * attr->text_matrix.b;
-        attr->text_pos.y -= tw * attr->text_matrix.a;
+    attr->fake_text_pos = HPDF_FALSE;
+    if (fake_matrix_pos ||
+            attr->text_matrix.x != line_start_pos.x ||
+            attr->text_matrix.y != line_start_pos.y) {
+        if ((ret = MoveTextPosAbs (page, line_start_pos.x, line_start_pos.y,
+                HPDF_FALSE, HPDF_FALSE)) != HPDF_OK)
+            return ret;
+        attr->text_pos = text_start_pos;
+        if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
+            attr->text_pos.x += tw * attr->text_matrix.a;
+            attr->text_pos.y += tw * attr->text_matrix.b;
+        } else {
+            attr->text_pos.x -= tw * attr->text_matrix.c;
+            attr->text_pos.y -= tw * attr->text_matrix.d;
+        }
+        attr->fake_text_pos = HPDF_TRUE;
     }
 
     return HPDF_OK;
@@ -2402,29 +2802,46 @@ InternalWriteText  (HPDF_Page        page,
 
 
 /*
- * Convert a user space text position from absolute to relative coordinates.
- * Absolute values are passed in xAbs and yAbs, relative values are returned
- * to xRel and yRel. The latter two must not be NULL.
+ * Convert a user space text position from absolute to relative coordinates,
+ * and move text position.
+ * Absolute values are passed in xAbs and yAbs.
  */
-static void
-TextPos_AbsToRel (HPDF_TransMatrix text_matrix,
-                  HPDF_REAL xAbs,
-                  HPDF_REAL yAbs,
-                  HPDF_REAL *xRel,
-                  HPDF_REAL *yRel)
-{
-    if (text_matrix.a == 0) {
-        *xRel = (yAbs - text_matrix.y - (xAbs - text_matrix.x) *
-            text_matrix.d / text_matrix.c) / text_matrix.b;
-        *yRel  = (xAbs - text_matrix.x) / text_matrix.c;
+static HPDF_STATUS
+MoveTextPosAbs  (HPDF_Page page,
+                 HPDF_REAL xAbs,
+                 HPDF_REAL yAbs,
+                 HPDF_BOOL sideways,
+                 HPDF_BOOL keep_line)
+{
+    HPDF_PageAttr attr = (HPDF_PageAttr)page->attr;
+    HPDF_TransMatrix mat = GetActualTextMatrix (page);
+    HPDF_REAL x, y;
+
+    if (sideways &&
+            (attr->gstate->writing_mode == HPDF_WMODE_MIXED ||
+             attr->gstate->writing_mode == HPDF_WMODE_SIDEWAYS)) {
+        HPDF_REAL tmp = -xAbs;
+        xAbs = yAbs;
+        yAbs = tmp;
+    }
+
+    if (mat.a == 0) {
+        x = (yAbs - mat.y - (xAbs - mat.x) * mat.d / mat.c) / mat.b;
+        y = (xAbs - mat.x) / mat.c;
     } else {
-        HPDF_REAL y = (yAbs - text_matrix.y - (xAbs - text_matrix.x) *
-            text_matrix.b / text_matrix.a) / (text_matrix.d -
-            text_matrix.c * text_matrix.b / text_matrix.a);
-        *xRel = (xAbs - text_matrix.x - y * text_matrix.c) /
-            text_matrix.a;
-        *yRel = y;
+        y = ((yAbs - mat.y - (xAbs - mat.x) * mat.b / mat.a) /
+                (mat.d - mat.c * mat.b / mat.a));
+        x = (xAbs - mat.x - y * mat.c) / mat.a;
+    }
+
+    if (keep_line) {
+        if (sideways && attr->gstate->writing_mode == HPDF_WMODE_MIXED)
+            x = 0;
+        else
+            y = 0;
     }
+
+    return HPDF_Page_MoveTextPos (page, x, y);
 }
 
 
@@ -2435,8 +2852,6 @@ HPDF_Page_TextOut  (HPDF_Page    page,
                     const char  *text)
 {
     HPDF_STATUS ret = HPDF_Page_CheckState (page, HPDF_GMODE_TEXT_OBJECT);
-    HPDF_REAL x;
-    HPDF_REAL y;
     HPDF_PageAttr attr;
 
     HPDF_PTRACE ((" HPDF_Page_TextOut\n"));
@@ -2445,8 +2860,8 @@ HPDF_Page_TextOut  (HPDF_Page    page,
         return ret;
 
     attr = (HPDF_PageAttr)page->attr;
-    TextPos_AbsToRel (attr->text_matrix, xpos, ypos, &x, &y);
-    if ((ret = HPDF_Page_MoveTextPos (page, x, y)) != HPDF_OK)
+    if ((ret = MoveTextPosAbs (page, xpos, ypos, HPDF_FALSE, HPDF_FALSE))
+            != HPDF_OK)
         return ret;
 
     return  HPDF_Page_ShowText (page, text);
@@ -2469,19 +2884,18 @@ HPDF_Page_TextRect  (HPDF_Page            page,
     const char *ptr = text;
     HPDF_BOOL pos_initialized = HPDF_FALSE;
     HPDF_BOOL pos_for_rtl = HPDF_FALSE;
-    HPDF_BOOL is_insufficient_space = HPDF_FALSE;
     HPDF_UINT num_rest;
     HPDF_Box bbox;
     HPDF_BOOL bidi_each_paragraph = HPDF_FALSE;
     HPDF_BOOL remove_tatweel = HPDF_FALSE;
     HPDF_INT meas_opt;
-    HPDF_REAL word_space;
-    HPDF_REAL char_space;
-    const char *operator;
-    char buf[HPDF_TMP_BUF_SIZ];
-    char *pbuf = NULL;
-    char *eptr = buf + sizeof buf - 1;
-    HPDF_REAL save_text_leading, text_leading;
+    HPDF_REAL save_word_space, save_char_space;
+    HPDF_REAL save_leading, text_leading, min_leading;
+    HPDF_REAL except_bottom_line;
+    HPDF_UINT max_lines, lines, line;
+    HPDF_TextLineWidth *text_line_width, *tlw;
+    HPDF_TextAlignment page_align;
+    char oper;
 
     HPDF_PTRACE ((" HPDF_Page_TextRect\n"));
 
@@ -2496,26 +2910,42 @@ HPDF_Page_TextRect  (HPDF_Page            page,
         return HPDF_RaiseError (page->error, HPDF_PAGE_FONT_NOT_FOUND, 0);
     }
 
-    if (align & HPDF_TALIGNOPT_BIDI_EACH_PARAGRAPH)
+    if (align & HPDF_ALIGNOPT_BIDI_EACH_PARAGRAPH)
         bidi_each_paragraph = HPDF_TRUE;
-    if (align & HPDF_TALIGNOPT_REMOVE_TATWEEL)
+    if (align & HPDF_ALIGNOPT_REMOVE_TATWEEL)
         remove_tatweel = HPDF_TRUE;
-    align &= HPDF_TALIGN_MASK;
+    page_align = align;
+    if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL ||
+        attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) {
+        page_align >>= 8;
+    } else {
+        HPDF_REAL tmp;
+        tmp = top;
+        top = right;
+        right = -bottom;
+        bottom = left;
+        left = -tmp;
+        align >>= 8;
+    }
+    align      &= HPDF_TALIGN_MASK;
+    page_align &= HPDF_TALIGN_MASK;
 
-    operator = " \'\012";
     meas_opt = HPDF_MEASURE_WORD_WRAP;
-    if (align == HPDF_TALIGN_JUSTIFY ||
-        align == HPDF_TALIGN_JUSTIFY_ALL ||
-        align == HPDF_TALIGN_STRETCH) {
-        operator = " \"\012";
-        if (align != HPDF_TALIGN_STRETCH)
+    if (remove_tatweel)
+        meas_opt |= HPDF_MEASURE_IGNORE_TATWEEL;
+
+    oper = '\'';
+    switch (align) {
+        case HPDF_TALIGN_JUSTIFY:
+        case HPDF_TALIGN_JUSTIFY_ALL:
             meas_opt |= HPDF_MEASURE_CAN_SHORTEN;
-        if (remove_tatweel)
-            meas_opt |= HPDF_MEASURE_IGNORE_TATWEEL;
+            /* not break */
+        case HPDF_TALIGN_STRETCH:
+        case HPDF_TALIGN_STRETCH_ALL:
+            oper = '\"';
+            break;
     }
 
-    bbox = HPDF_Font_GetBBox (font);
-
     if (len)
         *len = 0;
     num_rest = HPDF_Font_StrLen (font, text, HPDF_LIMIT_MAX_STRING_LEN + 1);
@@ -2525,323 +2955,260 @@ HPDF_Page_TextRect  (HPDF_Page            page,
     } else if (!num_rest)
         return HPDF_OK;
 
-    save_text_leading = text_leading = attr->gstate->text_leading;
-
-    if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-        if (text_leading == 0) {
-            text_leading = (bbox.top - bbox.bottom) / 1000 *
-                    attr->gstate->font_size;
-            HPDF_Page_SetTextLeading (page, text_leading);
-        }
+    save_leading    = attr->gstate->text_leading;
+    save_word_space = attr->gstate->word_space;
+    save_char_space = attr->gstate->char_space;
 
-        top    -= bbox.top    / 1000 * attr->gstate->font_size - text_leading;
-        bottom -= bbox.bottom / 1000 * attr->gstate->font_size;
-    } else {
-        HPDF_REAL cw;
-        HPDF_REAL tmp = top;
-        top = right;
-        right = -bottom;
-        bottom = left;
-        left = -tmp;
+    bbox = HPDF_Font_GetBBox (font);
 
-        if (text_leading == 0)
-            text_leading = (bbox.right - bbox.left) / 1000 *
-                    attr->gstate->font_size;
+    min_leading = (bbox.top - bbox.bottom) / 1000 * attr->gstate->font_size;
+    except_bottom_line = top - bottom - min_leading;
+    if (except_bottom_line < 0)
+        return HPDF_PAGE_INSUFFICIENT_SPACE;
+    if (save_leading == 0)
+        save_leading = min_leading; /* for backward compatibility */
+    text_leading = ((save_leading < 0)? -save_leading: save_leading);
+    if (min_leading < text_leading &&
+            (page_align == HPDF_TALIGN_JUSTIFY ||
+             page_align == HPDF_TALIGN_JUSTIFY_ALL))
+        text_leading = min_leading;
+    max_lines = (HPDF_UINT)(except_bottom_line / text_leading) + 1;
+    if (1 < max_lines &&
+            (page_align == HPDF_TALIGN_JUSTIFY ||
+             page_align == HPDF_TALIGN_STRETCH))
+        text_leading = except_bottom_line / (max_lines - 1);
+
+    if (!(text_line_width = HPDF_GetMem (page->mmgr, max_lines * sizeof *tlw)))
+        return page->mmgr->error->error_no;
+    lines = HPDF_Page_MeasureTextLines (page, ptr, right - left, meas_opt,
+            text_line_width, max_lines);
+    if (!lines)
+        goto END;
+
+    if (1 < lines &&
+            (page_align == HPDF_TALIGN_JUSTIFY_ALL ||
+             page_align == HPDF_TALIGN_STRETCH_ALL))
+        text_leading = except_bottom_line / (lines - 1);
+    if (save_leading < 0) {
+        except_bottom_line = -except_bottom_line;
+        text_leading = -text_leading;
+        min_leading = -min_leading;
+        top = bottom;
+    }
+    if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL ||
+        attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) {
+        if (0 < text_leading)
+            top -= (bbox.top    / 1000 * attr->gstate->font_size);
         else
-            HPDF_Page_SetTextLeading (page, 0);
-
-        cw = (bbox.right - bbox.left) / 1000 * attr->gstate->font_size;
-        top    -= cw / 2;
-        bottom -= cw / 2;
-        if (text_leading < 0) {
-            tmp = top;
-            top = bottom;
-            bottom = tmp;
-            top += cw;
-        }
+            top -= (bbox.bottom / 1000 * attr->gstate->font_size);
+    } else {
+        top -= (min_leading / 2);
     }
+    if (page_align == HPDF_TALIGN_RIGHT)
+        top -= except_bottom_line - (text_leading * (lines - 1));
+    else if (page_align == HPDF_TALIGN_CENTER)
+        top -= (except_bottom_line - (text_leading * (lines - 1))) / 2;
+    top += text_leading;
 
-    word_space = attr->gstate->word_space;
-    char_space = attr->gstate->char_space;
+    if (text_leading != attr->gstate->text_leading)
+        HPDF_Page_SetTextLeading (page, text_leading);
 
     HPDF_Font_CheckBiDi (font, bidi_each_paragraph);
 
-    for (;;) {
-        HPDF_REAL x, y;
-        HPDF_UINT line_len, tmp_len;
-        HPDF_UINT numchars, numspaces, numtatweels;
-        HPDF_REAL rw;
-        HPDF_BOOL line_break, justify;
-        HPDF_UCS4 ucs4 = 0;
-
-        line_len = HPDF_Page_MeasureTextEx (page, ptr, right - left, meas_opt,
-                &rw, &tmp_len, &numchars, &numspaces, &numtatweels);
-
-        if (line_len == 0) {
-            is_insufficient_space = HPDF_TRUE;
-            break;
-        }
+    for (line = 0, tlw = text_line_width; line < lines; line++, tlw++) {
+        HPDF_REAL drw;
+        HPDF_BOOL line_break = HPDF_FALSE;
+        HPDF_BOOL justify = HPDF_FALSE;
 
         if (len)
-            *len += line_len;
-        num_rest -= line_len;
-
-        /* Shorten tmp_len by trailing whitespace and control characters. */
-        line_break = HPDF_FALSE;
-        if (tmp_len < line_len) {
-            ucs4 = HPDF_Font_GetUcs4 (font, ptr + tmp_len, NULL);
-            if (ucs4 == 0x0A || ucs4 == 0x0C || ucs4 == 0x0D)
-                line_break = HPDF_TRUE;
-        }
+            *len += tlw->linebytes;
+        num_rest -= tlw->linebytes;
 
-        if (!tmp_len) {
-            if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL)
-                ret = HPDF_Page_MoveToNextLine(page);
-            else
-                ret = HPDF_Page_MoveTextPos (page, -text_leading, 0);
-            if (ret != HPDF_OK)
-                return ret;
+        if (tlw->flags & HPDF_TLW_PRAGRAPH_BREAK)
+            line_break = HPDF_TRUE;
+        if (tlw->flags & HPDF_TLW_PAGE_BREAK)
+            num_rest = 0;
 
-            if (num_rest <= 0 || ucs4 == 0x0C)
-                break;
+        if (!tlw->numbytes) {
+            if ((ret = HPDF_Page_MoveToNextLine(page)) != HPDF_OK)
+                goto END;
 
-            ptr += line_len;
+            ptr += tlw->linebytes;
             continue;
         }
 
-        switch (align) {
+        attr->gstate->word_space = save_word_space;
+        attr->gstate->char_space = save_char_space;
 
-            case HPDF_TALIGN_RIGHT:
-                if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-                    TextPos_AbsToRel (attr->text_matrix,
-                            right - rw, top, &x, &y);
-                    if (pos_initialized)
-                        y = 0;
-                } else {
-                    TextPos_AbsToRel (attr->text_matrix,
-                            top, -(right - rw), &x, &y);
-                    if (pos_initialized)
-                        x = -text_leading;
-                }
-                if ((ret = HPDF_Page_MoveTextPos (page, x, y)) != HPDF_OK)
-                    return ret;
-                pos_initialized = HPDF_TRUE;
-                break;
+        drw = right - left - tlw->width;
 
-            case HPDF_TALIGN_CENTER:
-                if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-                    TextPos_AbsToRel (attr->text_matrix,
-                            left + (right - left - rw) / 2, top, &x, &y);
-                    if (pos_initialized)
-                        y = 0;
-                } else {
-                    TextPos_AbsToRel (attr->text_matrix,
-                             top, -(left + (right - left - rw) / 2), &x, &y);
-                    if (pos_initialized)
-                        x = -text_leading;
-                }
-                if ((ret = HPDF_Page_MoveTextPos (page, x, y)) != HPDF_OK)
-                    return ret;
-                pos_initialized = HPDF_TRUE;
-                break;
-
-            case HPDF_TALIGN_JUSTIFY:
+        switch (align) {
             case HPDF_TALIGN_JUSTIFY_ALL:
+            case HPDF_TALIGN_STRETCH_ALL:
+                justify = HPDF_TRUE;
+                /* not break */
+            case HPDF_TALIGN_JUSTIFY:
             case HPDF_TALIGN_STRETCH:
-                word_space = attr->gstate->word_space;
-                char_space = attr->gstate->char_space;
-
                 /* Do not justify last line of paragraph or text. */
-                justify = (align == HPDF_TALIGN_JUSTIFY_ALL ||
-                        !((line_break || num_rest <= 0) && rw < right - left));
-                if (justify) {
-                    HPDF_REAL ch, sp, tt, all, ttw;
-    
-                    if (attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) {
-                        char_space *= -1;
-                        word_space *= -1;
-                    }
+                if ((!line_break && num_rest) || drw < 0)
+                    justify = HPDF_TRUE;
 
-                    if (numchars <= 1)
-                        numchars = 0;
-                    else
-                        numchars--;
-    
-                    ch = numchars    * attr->gstate->justify_char_space;
-                    sp = numspaces   * attr->gstate->justify_word_space;
-                    tt = numtatweels * attr->gstate->justify_kashida;
-                    if (tt) {
-                        ttw = ((HPDF_REAL)HPDF_Font_GetUcs4Width (font, 0x0640)
-                                * attr->gstate->font_size / 1000) + char_space;
-                        if (remove_tatweel) {
-                            tt *= ttw;
-                            rw += ttw * numtatweels;
-                        }
-                    }
-                    if (!ch && !sp && !tt)
+                if (justify) {
+                    HPDF_REAL ch, sp, tt, all, dch, dsp, dtt;
+                    HPDF_UINT numchars = ((tlw->numchars <= 1)? 0:
+                                          (tlw->numchars - 1));
+
+                    ch = numchars         * attr->gstate->justify_char_space;
+                    sp = tlw->numspaces   * attr->gstate->justify_word_space;
+                    tt = tlw->numtatweels * attr->gstate->justify_kashida;
+                    all = ch + sp + tt;
+                    if (!all) {
                         all = ch = 1;
-                    else
-                        all = ch + sp + tt;
-
-                    all = (right - left - rw) / all;
-                    ch *= all;
-                    sp *= all;
-                    tt *= all;
+                        sp = tt = 0;
+                    }
+                    dch = drw * ch / all;
+                    dsp = drw * sp / all;
+                    dtt = drw * tt / all;
 
                     if (tt) {
+                        HPDF_REAL ttw;
                         HPDF_INT tatweels;
                         HPDF_UINT dst_tatweels;
-                        tatweels = (HPDF_INT)((tt / ttw) + numtatweels);
+                        ttw = ((HPDF_REAL)HPDF_Font_GetUcs4Width (font, 0x0640)
+                                * attr->gstate->font_size / 1000)
+                                + attr->gstate->char_space;
+                        if (remove_tatweel)
+                            tatweels = (HPDF_INT)(dtt / ttw);
+                        else
+                            tatweels =
+                                    (HPDF_INT)((dtt / ttw) + tlw->numtatweels);
                         if (tatweels < 0)
                             tatweels = 0;
                         dst_tatweels = (HPDF_UINT)tatweels;
-                        if (dst_tatweels != numtatweels)
+                        if (dst_tatweels != tlw->numtatweels)
                             HPDF_Font_SetTatweelCount (font, dst_tatweels,
-                                    numtatweels, numchars);
-                        tatweels -= (HPDF_INT)numtatweels;
-                        ttw = tt - (tatweels * ttw);
-                        if (sp)
-                            sp += ttw;
-                        else
-                            ch += ttw;
+                                    tlw->numtatweels, tlw->numchars);
+                        if (!remove_tatweel)
+                            tatweels -= (HPDF_INT)tlw->numtatweels;
+                        dtt -= tatweels * ttw;
+                        if (!sp) {
+                            dch += dtt;
+                        } else {
+                            dch += dtt * ch / (ch + sp);
+                            dsp += dtt * sp / (ch + sp);
+                        }
                         numchars += tatweels;
+                    } else if (remove_tatweel && tlw->numtatweels) {
+                        HPDF_Font_SetTatweelCount (font, 0,
+                                tlw->numtatweels, tlw->numchars);
                     }
 
-                    if (ch < 0 && (char_space * numchars) + ch < 0 && sp) {
-                        if (0 < char_space) {
-                            sp += (char_space * numchars) + ch;
-                            char_space = 0;
+                    if (dsp && tlw->numspaces && dch < 0 &&
+                            (attr->gstate->char_space * numchars) + dch < 0) {
+                        if (0 < attr->gstate->char_space) {
+                            dsp += (attr->gstate->char_space * numchars) + dch;
+                            attr->gstate->char_space = 0;
                         } else {
-                            sp += ch;
+                            dsp += dch;
                         }
-                    } else if (ch && numchars)
-                        char_space += ch / numchars;
-
-                    if (sp && numspaces)
-                        word_space += sp / numspaces;
-    
-                    if (attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) {
-                        char_space *= -1;
-                        word_space *= -1;
+                    } else if (dch && numchars) {
+                        attr->gstate->char_space += dch / numchars;
                     }
 
-                    rw = right - left;
-                } else if (remove_tatweel && numtatweels) {
-                    HPDF_Font_SetTatweelCount (font, 0, numtatweels, numchars);
-                }
-
-                if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-                    if (!justify && HPDF_Font_IsRtL(font)) { /* align right. */
-                        TextPos_AbsToRel (attr->text_matrix,
-                                right - rw, top, &x, &y);
-                        if (pos_initialized)
-                            y = 0;
-                        if ((ret = HPDF_Page_MoveTextPos (page, x, y))
-                                != HPDF_OK)
-                            return ret;
-                        pos_for_rtl = HPDF_TRUE;
-                        pos_initialized = HPDF_TRUE;
-                    } else {        /* align left */
-                        if (!pos_initialized || pos_for_rtl) {
-                            TextPos_AbsToRel (attr->text_matrix,
-                                    left, top, &x, &y);
-                            if (pos_for_rtl)
-                                y = 0;
-                            if ((ret = HPDF_Page_MoveTextPos (page, x, y))
-                                    != HPDF_OK)
-                                return ret;
-                            pos_for_rtl = HPDF_FALSE;
-                            pos_initialized = HPDF_TRUE;
-                        }
+                    if (dsp && tlw->numspaces) {
+                        attr->gstate->word_space += dsp / tlw->numspaces;
                     }
-                } else {     /* ignore RtL in vertical writing mode */
-                    TextPos_AbsToRel (attr->text_matrix, top, -left, &x, &y);
-                    if (pos_initialized)
-                        x = -text_leading;
-                    if ((ret = HPDF_Page_MoveTextPos (page, x, y)) != HPDF_OK)
-                        return ret;
-                    pos_initialized = HPDF_TRUE;
                 }
 
-                pbuf = buf;
-                pbuf = HPDF_FToA (pbuf, word_space, eptr);
-                *pbuf++ = ' ';
-                pbuf = HPDF_FToA (pbuf, char_space, eptr);
-                *pbuf++ = ' ';
-                *pbuf = 0;
-                pbuf = buf;
-
-                break;
-
-            default:
-                if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-                    if (!pos_initialized) {
-                        TextPos_AbsToRel (attr->text_matrix, left, top, &x, &y);
-                        if ((ret = HPDF_Page_MoveTextPos (page, x, y))
-                                != HPDF_OK)
-                            return ret;
-                        pos_initialized = HPDF_TRUE;
-                    }
-                } else {
-                    TextPos_AbsToRel (attr->text_matrix, top, -left, &x, &y);
-                    if (pos_initialized)
-                        x = -text_leading;
-                    if ((ret = HPDF_Page_MoveTextPos (page, x, y)) != HPDF_OK)
-                        return ret;
-                    pos_initialized = HPDF_TRUE;
-                }
                 break;
         }
+        if (!justify && remove_tatweel && tlw->numtatweels)
+            HPDF_Font_SetTatweelCount (font, 0,
+                    tlw->numtatweels, tlw->numchars);
 
-        if ((ret = HPDF_Font_ConvertText (font, 0, ptr, tmp_len))
+        if ((ret = HPDF_Font_ConvertText (font, 0, ptr, tlw->numbytes))
                 != HPDF_OK)
-            return ret;
+            goto END;
 
-        if (InternalWriteText (page, rw, pbuf, operator) != HPDF_OK)
-            return HPDF_CheckError (page->error);
-
-        if (num_rest <= 0 || ucs4 == 0x0C)
-            break;
+        switch (align) {
+            case HPDF_TALIGN_RIGHT:
+                if ((ret = MoveTextPosAbs (page, left + drw,
+                      top, HPDF_TRUE, pos_initialized)) != HPDF_OK)
+                    goto END;
+                pos_initialized = HPDF_TRUE;
+                break;
 
-        if (attr->gstate->writing_mode == HPDF_WMODE_HORIZONTAL) {
-            if (attr->text_pos.y - text_leading < bottom) {
-                is_insufficient_space = HPDF_TRUE;
+            case HPDF_TALIGN_CENTER:
+                if ((ret = MoveTextPosAbs (page, left + (drw / 2),
+                      top, HPDF_TRUE, pos_initialized)) != HPDF_OK)
+                    goto END;
+                pos_initialized = HPDF_TRUE;
                 break;
-            }
-        } else if (0 < text_leading) {
-            if (attr->text_pos.x - text_leading < bottom) {
-                is_insufficient_space = HPDF_TRUE;
+
+            case HPDF_TALIGN_JUSTIFY_ALL:
+            case HPDF_TALIGN_STRETCH_ALL:
+            case HPDF_TALIGN_JUSTIFY:
+            case HPDF_TALIGN_STRETCH:
+                if (!justify && HPDF_Font_IsRtL(font)) { /* align right. */
+                    if ((ret = MoveTextPosAbs (page, left + drw,
+                            top, HPDF_TRUE, pos_initialized)) != HPDF_OK)
+                        goto END;
+                    pos_for_rtl = HPDF_TRUE;
+                    pos_initialized = HPDF_TRUE;
+                } else {        /* align left */
+                    if (!pos_initialized || pos_for_rtl) {
+                        if ((ret = MoveTextPosAbs (page, left,
+                                top, HPDF_TRUE, pos_initialized)) != HPDF_OK)
+                            goto END;
+                        pos_for_rtl = HPDF_FALSE;
+                        pos_initialized = HPDF_TRUE;
+                    }
+                }
                 break;
-            }
-        } else {
-            if (bottom < attr->text_pos.x - text_leading) {
-                is_insufficient_space = HPDF_TRUE;
+
+            default:
+                if (!pos_initialized) {
+                    if ((ret = MoveTextPosAbs (page, left,
+                            top, HPDF_TRUE, HPDF_FALSE)) != HPDF_OK)
+                        goto END;
+                    pos_initialized = HPDF_TRUE;
+                }
                 break;
-            }
         }
 
-        if (line_break && bidi_each_paragraph)
+        if ((ret = InternalWriteText (page, HPDF_FALSE, oper)) != HPDF_OK)
+            goto END;
+
+        if (line_break && bidi_each_paragraph && line + 1 < lines)
             HPDF_Font_CheckBiDi (font, HPDF_TRUE);
 
-        ptr += line_len;
+        ptr += tlw->linebytes;
     }
 
-    if (word_space != attr->gstate->word_space)
-        if ((ret = HPDF_Page_SetWordSpace (page, attr->gstate->word_space))
-                != HPDF_OK)
+ END:
+    HPDF_FreeMem (page->mmgr, text_line_width);
+
+    if (ret != HPDF_OK)
+        return ret;
+
+    if (attr->gstate->word_space != save_word_space) {
+        attr->gstate->word_space = save_word_space;
+        if ((ret = SetWordSpace (page, attr->gstate->word_space)) != HPDF_OK)
             return ret;
+    }
 
-    if (char_space != attr->gstate->char_space)
-        if ((ret = HPDF_Page_SetCharSpace (page, attr->gstate->char_space))
-                != HPDF_OK)
+    if (attr->gstate->char_space != save_char_space) {
+        attr->gstate->char_space = save_char_space;
+        if ((ret = SetCharSpace (page, attr->gstate->char_space)) != HPDF_OK)
             return ret;
+    }
 
-    if (save_text_leading != attr->gstate->text_leading)
-        if ((ret = HPDF_Page_SetTextLeading (page, save_text_leading))
+    if (attr->gstate->text_leading != save_leading)
+        if ((ret = HPDF_Page_SetTextLeading (page, save_leading))
                 != HPDF_OK)
             return ret;
 
-    if (is_insufficient_space)
+    if (num_rest)
         return HPDF_PAGE_INSUFFICIENT_SPACE;
     else
         return HPDF_OK;
@@ -2856,7 +3223,7 @@ HPDF_Page_SetSlideShow  (HPDF_Page            page,
                          HPDF_TransitionStyle   type,
                          HPDF_REAL            disp_time,
                          HPDF_REAL            trans_time)
-    {
+{
     HPDF_STATUS ret = HPDF_OK;
     HPDF_Dict dict;
 
@@ -3002,7 +3369,7 @@ HPDF_Page_New_Content_Stream  (HPDF_Page page,
 
     /* check if there is already an array of contents */
     contents_array = (HPDF_Array) HPDF_Dict_GetItem(page,"Contents", HPDF_OCLASS_ARRAY);
-    if (!contents_array) {      
+    if (!contents_array) {
         HPDF_Error_Reset (page->error);
         /* no contents_array already -- create one
            and replace current single contents item */
@@ -3023,7 +3390,7 @@ HPDF_Page_New_Content_Stream  (HPDF_Page page,
 
     ret += HPDF_Array_Add (contents_array,attr->contents);
 
-    /* return the value of the new stream, so that 
+    /* return the value of the new stream, so that
        the application can use it as a shared contents stream */
     if (ret == HPDF_OK && new_stream != NULL)
         *new_stream = attr->contents;
@@ -3051,7 +3418,7 @@ HPDF_Page_Insert_Shared_Content_Stream  (HPDF_Page page,
 
     /* check if there is already an array of contents */
     contents_array = (HPDF_Array) HPDF_Dict_GetItem(page,"Contents", HPDF_OCLASS_ARRAY);
-    if (!contents_array) {      
+    if (!contents_array) {
         HPDF_PageAttr attr;
         HPDF_Error_Reset (page->error);
         /* no contents_array already -- create one
diff --git a/src/hpdf_pages.c b/src/hpdf_pages.c
index 9f833da..4641337 100644
--- a/src/hpdf_pages.c
+++ b/src/hpdf_pages.c
@@ -715,6 +715,7 @@ HPDF_Page_TextWidth  (HPDF_Page        page,
     HPDF_TextWidth tw;
     HPDF_REAL ret = 0;
     HPDF_UINT len = 0;
+    HPDF_REAL char_space, word_space;
 
     HPDF_PTRACE((" HPDF_Page_TextWidth\n"));
 
@@ -730,17 +731,20 @@ HPDF_Page_TextWidth  (HPDF_Page        page,
         return 0;
     }
 
-    if (text) {
+    if (text)
         len = HPDF_Font_StrLen(font, text, HPDF_LIMIT_MAX_STRING_LEN + 1);
-        if (len == 0)
-            return 0;
-    }
 
     tw = HPDF_Font_TextWidth (font, (const HPDF_BYTE *)text, len);
 
-    ret += attr->gstate->word_space * tw.numspace;
+    char_space = attr->gstate->char_space;
+    word_space = attr->gstate->word_space;
+    if (attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) {
+        char_space = -char_space;
+        word_space = -word_space;
+    }
+    ret += tw.numchars * char_space;
+    ret += tw.numspace * word_space;
     ret += tw.width * attr->gstate->font_size  / 1000;
-    ret += attr->gstate->char_space * tw.numchars;
 
     HPDF_CheckError (page->error);
 
@@ -755,23 +759,28 @@ HPDF_Page_MeasureText  (HPDF_Page          page,
                         HPDF_INT           options,
                         HPDF_REAL         *real_width)
 {
+    HPDF_TextLineWidth tlw;
+    HPDF_UINT lines;
+
     HPDF_PTRACE((" HPDF_Page_MeasureText\n"));
 
-    return HPDF_Page_MeasureTextEx (page, text, width, options, real_width,
-            NULL, NULL, NULL, NULL);
+    lines = HPDF_Page_MeasureTextLines (page, text, width, options, &tlw, 1);
+    if (!lines)
+        return 0;
+
+    if (real_width)
+        *real_width = tlw.width;
+    return tlw.linebytes;
 }
 
 
 HPDF_EXPORT(HPDF_UINT)
-HPDF_Page_MeasureTextEx  (HPDF_Page    page,
-                          const char  *text,
-                          HPDF_REAL    width,
-                          HPDF_INT     options,
-                          HPDF_REAL   *real_width,
-                          HPDF_UINT   *numbytes,
-                          HPDF_UINT   *numchars,
-                          HPDF_UINT   *numspaces,
-                          HPDF_UINT   *numtatweels)
+HPDF_Page_MeasureTextLines  (HPDF_Page           page,
+                             const char         *text,
+                             HPDF_REAL           line_width,
+                             HPDF_INT            options,
+                             HPDF_TextLineWidth *width,
+                             HPDF_UINT           max_lines)
 {
     HPDF_PageAttr attr;
     HPDF_Font font;
@@ -781,7 +790,7 @@ HPDF_Page_MeasureTextEx  (HPDF_Page    page,
 
     HPDF_PTRACE((" HPDF_Page_MeasureTextEx\n"));
 
-    if (!HPDF_Page_Validate (page) || !text)
+    if (!HPDF_Page_Validate (page) || !text || !width)
         return 0;
 
     attr = (HPDF_PageAttr )page->attr;
@@ -800,12 +809,12 @@ HPDF_Page_MeasureTextEx  (HPDF_Page    page,
     char_space = attr->gstate->char_space;
     word_space = attr->gstate->word_space;
     if (attr->gstate->writing_mode == HPDF_WMODE_VERTICAL) {
-        char_space *= -1;
-        word_space *= -1;
+        char_space = -char_space;
+        word_space = -word_space;
     }
-    ret = HPDF_Font_MeasureTextEx (font, (const HPDF_BYTE *)text, len, width,
-            attr->gstate->font_size, char_space, word_space, options,
-            real_width, numbytes, numchars, numspaces, numtatweels);
+    ret = HPDF_Font_MeasureTextLines (font, (const HPDF_BYTE *)text, len,
+            line_width, attr->gstate->font_size, char_space, word_space,
+            options, width, max_lines);
 
     HPDF_CheckError (page->error);
 
@@ -2037,3 +2046,25 @@ HPDF_Page_SetJustifyRatio  (HPDF_Page page,
 
     return HPDF_OK;
 }
+
+
+HPDF_EXPORT(HPDF_STATUS)
+HPDF_Page_InterlinearAnnotationRatio  (HPDF_Page page,
+                                       HPDF_REAL ratio)
+{
+    HPDF_PageAttr attr;
+
+    HPDF_PTRACE((" HPDF_Page_InterlinearAnnotationRatio\n"));
+
+    if (!HPDF_Page_Validate (page))
+        return HPDF_INVALID_PAGE;
+
+    attr = (HPDF_PageAttr)page->attr;
+
+    if (ratio <= 0)
+        return HPDF_RaiseError (page->error, HPDF_INVALID_PARAMETER, 0);
+
+    attr->gstate->ia_font_size_ratio = ratio;
+
+    return HPDF_OK;
+}