#! /bin/sh /usr/share/dpatch/dpatch-run
## 15_pango_break.dpatch by Theppitak Karoonboonyanan <thep@linux.thai.net>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Back-ported patch for line breaking using Pango from bz#336959

@DPATCH@
diff -urNad xulrunner-1.8.1.5~/intl/build/Makefile.in xulrunner-1.8.1.5/intl/build/Makefile.in
--- xulrunner-1.8.1.5~/intl/build/Makefile.in	2007-07-23 18:32:27.000000000 +0700
+++ xulrunner-1.8.1.5/intl/build/Makefile.in	2007-07-23 18:33:41.000000000 +0700
@@ -113,3 +113,13 @@
 
 include $(topsrcdir)/config/rules.mk
 
+ifdef MOZ_ENABLE_PANGO
+CXXFLAGS       += \
+               $(MOZ_PANGO_CFLAGS) \
+               $(NULL)
+
+EXTRA_DSO_LDOPTS += \
+               $(MOZ_PANGO_LIBS) \
+               $(NULL)
+endif
+
diff -urNad xulrunner-1.8.1.5~/intl/lwbrk/src/Makefile.in xulrunner-1.8.1.5/intl/lwbrk/src/Makefile.in
--- xulrunner-1.8.1.5~/intl/lwbrk/src/Makefile.in	2007-07-23 18:32:27.000000000 +0700
+++ xulrunner-1.8.1.5/intl/lwbrk/src/Makefile.in	2007-07-23 18:33:41.000000000 +0700
@@ -61,4 +61,27 @@
 		nsSemanticUnitScanner.cpp \
 		$(NULL)
 
+ifdef MOZ_ENABLE_PANGO
+CPPSRCS                += \
+               nsPangoBreaker.cpp \
+               $(NULL)
+else
+CPPSRCS                += \
+               nsRuleBreaker.cpp \
+               $(NULL)
+
+CSRCS          = rulebrk.c
+endif
+
 include $(topsrcdir)/config/rules.mk
+
+ifdef MOZ_ENABLE_PANGO
+CXXFLAGS       += \
+               $(MOZ_PANGO_CFLAGS) \
+               $(NULL)
+
+EXTRA_DSO_LDOPTS += \
+               $(MOZ_PANGO_LIBS) \
+               $(NULL)
+endif
+
diff -urNad xulrunner-1.8.1.5~/intl/lwbrk/src/nsComplexBreaker.h xulrunner-1.8.1.5/intl/lwbrk/src/nsComplexBreaker.h
--- xulrunner-1.8.1.5~/intl/lwbrk/src/nsComplexBreaker.h	1970-01-01 07:00:00.000000000 +0700
+++ xulrunner-1.8.1.5/intl/lwbrk/src/nsComplexBreaker.h	2007-07-23 18:33:41.000000000 +0700
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Theppitak Karoonboonyanan <thep@linux.thai.net>.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Theppitak Karoonboonyanan <thep@linux.thai.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef nsComplexBreaker_h__
+#define nsComplexBreaker_h__
+
+#include "nsString.h"
+
+/**
+ * Find line break opportunities in aText[] of aLength characters,
+ * filling boolean values indicating line break opportunities for
+ * corresponding charactersin aBreakBefore[] on return.
+ */
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+                        PRPackedBool* aBreakBefore);
+
+#endif  /* nsComplexBreaker_h__ */
diff -urNad xulrunner-1.8.1.5~/intl/lwbrk/src/nsJISx4501LineBreaker.cpp xulrunner-1.8.1.5/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
--- xulrunner-1.8.1.5~/intl/lwbrk/src/nsJISx4501LineBreaker.cpp	2007-07-23 18:32:27.000000000 +0700
+++ xulrunner-1.8.1.5/intl/lwbrk/src/nsJISx4501LineBreaker.cpp	2007-07-23 18:33:41.000000000 +0700
@@ -44,9 +44,8 @@
 #include "pratom.h"
 #include "nsLWBRKDll.h"
 #include "jisx4501class.h"
-#define TH_UNICODE
-#include "th_char.h"
-#include "rulebrk.h"
+#include "nsComplexBreaker.h"
+#include "nsTArray.h"
 #include "nsUnicharUtils.h"
 
 
@@ -238,6 +237,12 @@
 }
 
 static inline int
+IS_THAI(PRUnichar u)
+{
+  return (0x0e01 <= (u) && (u) <= 0x0e5b);
+}
+
+static inline int
 IS_SPACE(PRUnichar u)
 {
   return ((u) == 0x0020 || (u) == 0x0009 || (u) == 0x000a || (u) == 0x000d || (u)==0x200b);
@@ -254,7 +259,7 @@
    {
      c = GETCLASSFROMTABLE(gLBClass00, l);
    } 
-   else if(th_isthai(u))
+   else if(IS_THAI(u))
    {
      c = CLASS_THAI;
    }
@@ -419,15 +424,17 @@
      return NS_OK;
   }
 
-  //search for CJK characters until a space is found. 
-  //if CJK char is found before space, use 4051, otherwise western
+  //search for CJK/Thai characters until a space is found. 
+  //if CJK char is found before space, use 4051
+  //if Thai char is found, use complex linebreaker,
+  //otherwise western
   PRInt32 cur;
 
   for (cur= aTextLen1-1; cur>=0; cur--)
   {
     if (IS_SPACE(aText1[cur]))
       break;
-    if (IS_CJK_CHAR(aText1[cur]))
+    if (IS_CJK_CHAR(aText1[cur]) || IS_THAI(aText1[cur]))
       goto ROUTE_CJK_BETWEEN;
   }
 
@@ -435,7 +442,7 @@
   {
     if (IS_SPACE(aText2[cur]))
       break;
-    if (IS_CJK_CHAR(aText2[cur]))
+    if (IS_CJK_CHAR(aText2[cur]) || IS_THAI(aText2[cur]))
       goto ROUTE_CJK_BETWEEN;
   }
 
@@ -463,7 +470,18 @@
   /* Handle cases for THAI */
   if((CLASS_THAI == c1) && (CLASS_THAI == c2))
   {
-     *oCanBreak = (0 == TrbWordBreakPos(aText1, aTextLen1, aText2, aTextLen2));
+     nsAutoString concat(aText1, aTextLen1);
+     concat.Append(aText2, aTextLen2);
+
+     nsTArray<PRPackedBool> breakState;
+     for (PRUint32 i = 0; i < concat.Length(); ++i)
+       if (!breakState.AppendElement())
+         return NS_ERROR_OUT_OF_MEMORY;
+  
+     NS_GetComplexLineBreaks(concat.Data(), concat.Length(),
+                             breakState.Elements());
+   
+     *oCanBreak = breakState[aTextLen1];
   }
   else 
   {
@@ -483,7 +501,9 @@
   NS_ENSURE_TRUE(aPos <= aLen, NS_ERROR_ILLEGAL_VALUE);
 
   //forward check for CJK characters until a space is found. 
-  //if CJK char is found before space, use 4051, otherwise western
+  //if CJK char is found before space, use 4051,
+  //if Thai char is found, use complex linebreaker,
+  //otherwise western
   PRUint32 cur;
   for (cur = aPos; cur < aLen; ++cur)
   {
@@ -493,7 +513,7 @@
       *oNeedMoreText = PR_FALSE;
       return NS_OK;
     }
-    if (IS_CJK_CHAR(aText[cur]))
+    if (IS_CJK_CHAR(aText[cur]) || IS_THAI(aText[cur]))
       goto ROUTE_CJK_NEXT;
   }
   *oNext = aLen;
@@ -514,8 +534,25 @@
   
   if(CLASS_THAI == c1) 
   {
-     *oNext = PRUint32(TrbFollowing(aText, aLen, aPos));
-     *oNeedMoreText = PR_FALSE;
+     nsTArray<PRPackedBool> breakState;
+     for (PRUint32 i = 0; i < aLen; ++i)
+       if (!breakState.AppendElement())
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+     NS_GetComplexLineBreaks(aText, aLen, breakState.Elements());
+ 
+     while (++aPos < aLen)
+     {
+       if (breakState[aPos])
+       {
+         *oNext = aPos;
+         *oNeedMoreText = PR_FALSE;
+         return NS_OK;
+       }
+     }
+
+     *oNext = aLen;
+     *oNeedMoreText = PR_TRUE;
      return NS_OK;
   }
 
@@ -551,7 +588,9 @@
   NS_ENSURE_TRUE(oNeedMoreText, NS_ERROR_NULL_POINTER);
 
   //backward check for CJK characters until a space is found. 
-  //if CJK char is found before space, use 4051, otherwise western
+  //if CJK char is found before space, use 4051,
+  //if Thai char is found, use platform linebreaker,
+  //otherwise western
   PRUint32 cur;
   for (cur = aPos - 1; cur > 0; --cur)
   {
@@ -563,7 +602,7 @@
       *oNeedMoreText = PR_FALSE;
       return NS_OK;
     }
-    if (IS_CJK_CHAR(aText[cur]))
+    if (IS_CJK_CHAR(aText[cur]) || IS_THAI(aText[cur]))
       goto ROUTE_CJK_PREV;
   }
 
@@ -582,10 +621,31 @@
   } else  {
     c2 = this->GetClass(aText[cur-1]);
   }
-  // To Do: 
-  //
-  // Should handle CLASS_THAI here
-  //
+
+  if (CLASS_THAI == c2)
+  {
+    nsTArray<PRPackedBool> breakState;
+    for (PRUint32 i = 0; i < aLen; ++i)
+      if (!breakState.AppendElement())
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_GetComplexLineBreaks(aText, aLen, breakState.Elements());
+
+    while (aPos > 0)
+    {
+      if (breakState[--aPos])
+      {
+        *oPrev = aPos;
+        *oNeedMoreText = PR_FALSE;
+        return NS_OK;
+      }
+    }
+
+    *oPrev = 0;
+    *oNeedMoreText = PR_TRUE;
+    return NS_OK;
+  }
+
   for(cur--; cur > 0; cur--)
   {
      if(NEED_CONTEXTUAL_ANALYSIS(aText[cur-1]))
diff -urNad xulrunner-1.8.1.5~/intl/lwbrk/src/nsPangoBreaker.cpp xulrunner-1.8.1.5/intl/lwbrk/src/nsPangoBreaker.cpp
--- xulrunner-1.8.1.5~/intl/lwbrk/src/nsPangoBreaker.cpp	1970-01-01 07:00:00.000000000 +0700
+++ xulrunner-1.8.1.5/intl/lwbrk/src/nsPangoBreaker.cpp	2007-07-23 18:35:35.000000000 +0700
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Theppitak Karoonboonyanan <thep@linux.thai.net>.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Theppitak Karoonboonyanan <thep@linux.thai.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsComplexBreaker.h"
+
+#include <pango/pango-break.h>
+#include "nsUTF8Utils.h"
+#include "nsString.h"
+#include "nsUnicharUtils.h"
+#include "nsTArray.h"
+
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+                        PRPackedBool* aBreakBefore)
+{
+  NS_ASSERTION(aText, "aText shouldn't be null");
+
+  nsTArray<PangoLogAttr> attrBuffer;
+  for (PRUint32 i = 0; i < aLength + 1; ++i)
+  {
+    if (!attrBuffer.AppendElement())
+    {
+      // out of memory, behave as if there were no complex line breaker
+      for (i = 0; i < aLength; ++i) {
+        aBreakBefore[i] = PR_FALSE;
+      }
+      return;
+    }
+  }
+
+  NS_ConvertUTF16toUTF8 aUTF8(aText, aLength);
+
+  const gchar* p = aUTF8.Data();
+  const gchar* end = p + aUTF8.Length();
+  PRUint32     u16Offset = 0;
+
+  static PangoLanguage* language = pango_language_from_string("en");
+
+  while (p < end)
+  {
+    PangoLogAttr* attr = attrBuffer.Elements();
+    pango_get_log_attrs(p, end - p, -1, language, attr, attrBuffer.Length());
+
+    while (p < end)
+    {
+      aBreakBefore[u16Offset] = attr->is_line_break;
+      if (IS_LOW_SURROGATE(aText[u16Offset]))
+        aBreakBefore[++u16Offset] = PR_FALSE; // Skip high surrogate
+      ++u16Offset;
+
+      PRUint32 ch = g_utf8_get_char(p);
+      p = g_utf8_next_char(p);
+      ++attr;
+
+      if (ch == 0) {
+        // pango_break (pango 1.16.2) only analyses text before the
+        // first NUL (but sets one extra attr). Workaround loop to call
+        // pango_break again to analyse after the NUL is done somewhere else
+        // (gfx/thebes/src/gfxPangoFonts.cpp: SetupClusterBoundaries()).
+        // So, we do the same here for pango_get_log_attrs.
+        break;
+      }
+    }
+  }
+}
+
diff -urNad xulrunner-1.8.1.5~/intl/lwbrk/src/nsRuleBreaker.cpp xulrunner-1.8.1.5/intl/lwbrk/src/nsRuleBreaker.cpp
--- xulrunner-1.8.1.5~/intl/lwbrk/src/nsRuleBreaker.cpp	1970-01-01 07:00:00.000000000 +0700
+++ xulrunner-1.8.1.5/intl/lwbrk/src/nsRuleBreaker.cpp	2007-07-23 18:33:41.000000000 +0700
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Theppitak Karoonboonyanan <thep@linux.thai.net>.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Theppitak Karoonboonyanan <thep@linux.thai.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsComplexBreaker.h"
+
+#define TH_UNICODE
+#include "rulebrk.h"
+
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+                        PRPackedBool* aBreakBefore)
+{
+  NS_ASSERTION(aText, "aText shouldn't be null");
+
+  for (PRUint32 i = 0; i < aLength; i++)
+    aBreakBefore[i] = (0 == TrbWordBreakPos(aText, i, aText + i, aLength - i));
+}
+
