bug 253317 - part 4 - implement nsHyphenationManager and nsHyphenator classes. r=smontagu sr=roc
authorJonathan Kew <jfkthame@gmail.com>
Wed, 04 May 2011 12:29:45 +0100
changeset 68951 3f96f2d3dffe15bd7609b1af7223f7d6a71860db
parent 68950 a5877159c9a16be6ac6a034453b94b3788fb2096
child 68952 cf41ba95de8579facde9578c8e94c3041d1f0b68
push idunknown
push userunknown
push dateunknown
reviewerssmontagu, roc
bugs253317
milestone6.0a1
bug 253317 - part 4 - implement nsHyphenationManager and nsHyphenator classes. r=smontagu sr=roc
intl/Makefile.in
intl/build/Makefile.in
intl/hyphenation/Makefile.in
intl/hyphenation/public/Makefile.in
intl/hyphenation/public/nsHyphenationManager.h
intl/hyphenation/public/nsHyphenator.h
intl/hyphenation/src/Makefile.in
intl/hyphenation/src/hnjalloc.h
intl/hyphenation/src/nsHyphenationManager.cpp
intl/hyphenation/src/nsHyphenator.cpp
modules/libpref/src/init/all.js
--- a/intl/Makefile.in
+++ b/intl/Makefile.in
@@ -38,16 +38,17 @@
 DEPTH     = ..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 PARALLEL_DIRS = \
+  hyphenation \
   locale \
   locales \
   lwbrk \
   strres \
   unicharutil \
   $(NULL)
 
 DIRS = \
--- a/intl/build/Makefile.in
+++ b/intl/build/Makefile.in
@@ -74,16 +74,17 @@ LOCAL_INCLUDES = \
 			$(NULL)
 
 SHARED_LIBRARY_LIBS = \
 			../lwbrk/src/$(LIB_PREFIX)lwbrk_s.$(LIB_SUFFIX) \
 			../unicharutil/src/$(LIB_PREFIX)ucharucomp_s.$(LIB_SUFFIX) \
 			../strres/src/$(LIB_PREFIX)strres_s.$(LIB_SUFFIX) \
 			../locale/src/$(LIB_PREFIX)nslocale_s.$(LIB_SUFFIX) \
 			../locale/src/$(LOCALE_DIR)/$(LIB_PREFIX)platlocale_s.$(LIB_SUFFIX) \
+			../hyphenation/src/$(HYPHENATION_DIR)/$(LIB_PREFIX)hyphenation_s.$(LIB_SUFFIX) \
 			$(NULL)
 
 EXTRA_DSO_LDOPTS = \
 	$(MOZ_UNICHARUTIL_LIBS) \
 	$(MOZ_COMPONENT_LIBS) \
 	$(NULL)
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/Makefile.in
@@ -0,0 +1,48 @@
+# ***** 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 Hyphenation Service.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Jonathan Kew <jfkthame@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either 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 *****
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= hyphenation
+DIRS		= public src
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/public/Makefile.in
@@ -0,0 +1,53 @@
+# ***** 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 Hyphenation Service.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Jonathan Kew <jfkthame@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either 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 *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= hyphenation
+
+EXPORTS		= \
+		nsHyphenationManager.h \
+		nsHyphenator.h \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/public/nsHyphenationManager.h
@@ -0,0 +1,74 @@
+/* ***** 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 Hyphenation Service.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 nsHyphenationManager_h__
+#define nsHyphenationManager_h__
+
+#include "nsInterfaceHashtable.h"
+#include "nsRefPtrHashtable.h"
+#include "nsHashKeys.h"
+
+class nsHyphenator;
+class nsIAtom;
+
+class nsHyphenationManager
+{
+public:
+  nsHyphenationManager();
+
+  already_AddRefed<nsHyphenator> GetHyphenator(nsIAtom *aLocale);
+
+  static nsHyphenationManager *Instance();
+
+  static void Shutdown();
+
+private:
+  ~nsHyphenationManager();
+
+protected:
+  void LoadPatternList();
+  void LoadPatternListFromDir(nsIFile *aDir);
+  void LoadAliases();
+
+  nsInterfaceHashtable<nsISupportsHashKey,nsIAtom> mHyphAliases;
+  nsInterfaceHashtable<nsISupportsHashKey,nsIFile> mPatternFiles;
+  nsRefPtrHashtable<nsISupportsHashKey,nsHyphenator> mHyphenators;
+
+  static nsHyphenationManager *sInstance;
+};
+
+#endif // nsHyphenationManager_h__
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/public/nsHyphenator.h
@@ -0,0 +1,66 @@
+/* ***** 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 Hyphenation Service.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 nsHyphenator_h__
+#define nsHyphenator_h__
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+class nsIUGenCategory;
+
+class nsHyphenator
+{
+public:
+  nsHyphenator(nsIFile *aFile);
+
+  NS_INLINE_DECL_REFCOUNTING(nsHyphenator)
+
+  PRBool IsValid();
+
+  nsresult Hyphenate(const nsAString& aText, nsTArray<PRPackedBool>& aHyphens);
+
+private:
+  ~nsHyphenator();
+
+protected:
+  void                      *mDict;
+  nsCOMPtr<nsIUGenCategory>  mCategories;
+};
+
+#endif // nsHyphenator_h__
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/src/Makefile.in
@@ -0,0 +1,56 @@
+# ***** 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 Hyphenation Service.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Jonathan Kew <jfkthame@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either 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 *****
+
+DEPTH           = ../../..
+topsrcdir       = @top_srcdir@
+srcdir          = @srcdir@
+VPATH           = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE           = hyphenation
+LIBRARY_NAME     = hyphenation_s
+LIBXUL_LIBRARY   = 1
+
+CSRCS            = hyphen.c \
+                   $(NULL)
+
+CPPSRCS          = nsHyphenator.cpp \
+                   nsHyphenationManager.cpp \
+                   $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/src/hnjalloc.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** 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 Foundation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2005-2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 ***** */
+
+/*
+ * Simple replacement for hnjalloc.h from libhyphen-2.x, to use moz_x* memory
+ * allocation functions. Note that the hyphen.c code does *NOT* check for
+ * NULL from memory (re)allocation, so it is essential that we use the
+ * "infallible" moz_x* variants here.
+ */
+
+#include "mozilla/mozalloc.h"
+
+#define hnj_malloc(size)      moz_xmalloc(size)
+#define hnj_realloc(p, size)  moz_xrealloc(p, size)
+#define hnj_free(p)           moz_free(p)
+
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/src/nsHyphenationManager.cpp
@@ -0,0 +1,256 @@
+/* ***** 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 Hyphenation Service.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 "nsHyphenationManager.h"
+#include "nsHyphenator.h"
+#include "nsIAtom.h"
+#include "nsIFile.h"
+#include "nsIProperties.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIDirectoryEnumerator.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsUnicharUtils.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+
+#define INTL_HYPHENATIONALIAS_PREFIX "intl.hyphenation-alias."
+
+nsHyphenationManager *nsHyphenationManager::sInstance = nsnull;
+
+nsHyphenationManager*
+nsHyphenationManager::Instance()
+{
+  if (sInstance == nsnull) {
+    sInstance = new nsHyphenationManager();
+  }
+  return sInstance;
+}
+
+void
+nsHyphenationManager::Shutdown()
+{
+  delete sInstance;
+}
+
+nsHyphenationManager::nsHyphenationManager()
+{
+  mHyphAliases.Init();
+  mPatternFiles.Init();
+  mHyphenators.Init();
+  LoadPatternList();
+  LoadAliases();
+}
+
+nsHyphenationManager::~nsHyphenationManager()
+{
+  sInstance = nsnull;
+}
+
+already_AddRefed<nsHyphenator>
+nsHyphenationManager::GetHyphenator(nsIAtom *aLocale)
+{
+  nsRefPtr<nsHyphenator> hyph;
+  mHyphenators.Get(aLocale, getter_AddRefs(hyph));
+  if (hyph) {
+    return hyph.forget();
+  }
+  nsCOMPtr<nsIFile> file = mPatternFiles.Get(aLocale);
+  if (!file) {
+    nsCOMPtr<nsIAtom> alias = mHyphAliases.Get(aLocale);
+    if (alias) {
+      mHyphenators.Get(alias, getter_AddRefs(hyph));
+      if (hyph) {
+        return hyph.forget();
+      }
+      file = mPatternFiles.Get(alias);
+      if (file) {
+        aLocale = alias;
+      }
+    }
+    if (!file) {
+      // In the case of a locale such as "de-DE-1996", we try replacing
+      // successive trailing subtags with "-*" to find fallback patterns,
+      // so "de-DE-1996" -> "de-DE-*" (and then recursively -> "de-*")
+      nsAtomCString localeStr(aLocale);
+      if (StringEndsWith(localeStr, NS_LITERAL_CSTRING("-*"))) {
+        localeStr.Truncate(localeStr.Length() - 2);
+      }
+      PRInt32 i = localeStr.RFindChar('-');
+      if (i > 1) {
+        localeStr.Replace(i, localeStr.Length() - i, "-*");
+        nsCOMPtr<nsIAtom> fuzzyLocale = do_GetAtom(localeStr);
+        return GetHyphenator(fuzzyLocale);
+      } else {
+        return nsnull;
+      }
+    }
+  }
+  hyph = new nsHyphenator(file);
+  if (hyph->IsValid()) {
+    mHyphenators.Put(aLocale, hyph);
+    return hyph.forget();
+  }
+#ifdef DEBUG
+  nsCString msg;
+  file->GetNativePath(msg);
+  msg.Insert("failed to load patterns from ", 0);
+  NS_WARNING(msg.get());
+#endif
+  mPatternFiles.Remove(aLocale);
+  return nsnull;
+}
+
+void
+nsHyphenationManager::LoadPatternList()
+{
+  mPatternFiles.Clear();
+  mHyphenators.Clear();
+  
+  nsresult rv;
+  
+  nsCOMPtr<nsIProperties> dirSvc =
+    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+  if (!dirSvc) {
+    return;
+  }
+  
+  nsCOMPtr<nsIFile> greDir;
+  rv = dirSvc->Get(NS_GRE_DIR,
+                   NS_GET_IID(nsIFile), getter_AddRefs(greDir));
+  if (NS_SUCCEEDED(rv)) {
+    greDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
+    LoadPatternListFromDir(greDir);
+  }
+  
+  nsCOMPtr<nsIFile> appDir;
+  rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
+                   NS_GET_IID(nsIFile), getter_AddRefs(appDir));
+  if (NS_SUCCEEDED(rv)) {
+    appDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
+    PRBool equals;
+    if (NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) {
+      LoadPatternListFromDir(appDir);
+    }
+  }
+}
+
+void
+nsHyphenationManager::LoadPatternListFromDir(nsIFile *aDir)
+{
+  nsresult rv;
+  
+  PRBool check = PR_FALSE;
+  rv = aDir->Exists(&check);
+  if (NS_FAILED(rv) || !check) {
+    return;
+  }
+  
+  rv = aDir->IsDirectory(&check);
+  if (NS_FAILED(rv) || !check) {
+    return;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> e;
+  rv = aDir->GetDirectoryEntries(getter_AddRefs(e));
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  
+  nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e));
+  if (!files) {
+    return;
+  }
+  
+  nsCOMPtr<nsIFile> file;
+  while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file){
+    nsAutoString dictName;
+    file->GetLeafName(dictName);
+    NS_ConvertUTF16toUTF8 locale(dictName);
+    ToLowerCase(locale);
+    if (!StringEndsWith(locale, NS_LITERAL_CSTRING(".dic"))) {
+      continue;
+    }
+    if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
+      locale.Cut(0, 5);
+    }
+    locale.SetLength(locale.Length() - 4); // strip ".dic"
+    for (PRUint32 i = 0; i < locale.Length(); ++i) {
+      if (locale[i] == '_') {
+        locale.Replace(i, 1, '-');
+      }
+    }
+#ifdef DEBUG
+    printf("adding hyphenation patterns for %s: %s\n", locale.get(),
+           NS_ConvertUTF16toUTF8(dictName).get());
+#endif
+    nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
+    mPatternFiles.Put(localeAtom, file);
+  }
+}
+
+void
+nsHyphenationManager::LoadAliases()
+{
+  nsresult rv;
+  nsCOMPtr<nsIPrefBranch> prefBranch =
+    do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  PRUint32 prefCount;
+  char **prefNames;
+  rv = prefBranch->GetChildList(INTL_HYPHENATIONALIAS_PREFIX,
+                                &prefCount, &prefNames);
+  if (NS_SUCCEEDED(rv) && prefCount > 0) {
+    for (PRUint32 i = 0; i < prefCount; ++i) {
+      char *prefValue;
+      rv = prefBranch->GetCharPref(prefNames[i], &prefValue);
+      if (NS_SUCCEEDED(rv)) {
+        nsCAutoString alias(prefNames[i]);
+        alias.Cut(0, strlen(INTL_HYPHENATIONALIAS_PREFIX));
+        ToLowerCase(alias);
+        nsCAutoString value(prefValue);
+        ToLowerCase(value);
+        nsCOMPtr<nsIAtom> aliasAtom = do_GetAtom(alias);
+        nsCOMPtr<nsIAtom> valueAtom = do_GetAtom(value);
+        mHyphAliases.Put(aliasAtom, valueAtom);
+        NS_Free(prefValue);
+      }
+    }
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/src/nsHyphenator.cpp
@@ -0,0 +1,147 @@
+/* ***** 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 Hyphenation Service.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 "nsHyphenator.h"
+#include "nsIFile.h"
+#include "nsUTF8Utils.h"
+#include "nsIUGenCategory.h"
+#include "nsUnicharUtilCIID.h"
+
+#include "hyphen.h"
+
+nsHyphenator::nsHyphenator(nsIFile *aFile)
+  : mDict(nsnull)
+{
+  nsCString path;
+  aFile->GetNativePath(path);
+  mDict = hnj_hyphen_load(path.get());
+#ifdef DEBUG
+  if (mDict) {
+    printf("loaded hyphenation patterns from %s\n", path.get());
+  }
+#endif
+  nsresult rv;
+  mCategories =
+    do_GetService(NS_UNICHARCATEGORY_CONTRACTID, &rv);
+  NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get category service");
+}
+
+nsHyphenator::~nsHyphenator()
+{
+  if (mDict != nsnull) {
+    hnj_hyphen_free((HyphenDict*)mDict);
+    mDict = nsnull;
+  }
+}
+
+PRBool
+nsHyphenator::IsValid()
+{
+  return (mDict != nsnull) && (mCategories != nsnull);
+}
+
+nsresult
+nsHyphenator::Hyphenate(const nsAString& aString,
+                        nsTArray<PRPackedBool>& aHyphens)
+{
+  if (!aHyphens.SetLength(aString.Length())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  memset(aHyphens.Elements(), PR_FALSE, aHyphens.Length());
+
+  PRBool inWord = PR_FALSE;
+  PRUint32 wordStart = 0, wordLimit = 0;
+  for (PRUint32 i = 0; i < aString.Length(); i++) {
+    PRUnichar ch = aString[i];
+
+    nsIUGenCategory::nsUGenCategory cat = mCategories->Get(ch);
+    if (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kMark) {
+      if (!inWord) {
+        inWord = PR_TRUE;
+        wordStart = i;
+      }
+      wordLimit = i + 1;
+      if (i < aString.Length() - 1) {
+        continue;
+      }
+    }
+
+    if (inWord) {
+      NS_ConvertUTF16toUTF8 utf8(aString.BeginReading() + wordStart,
+                                 wordLimit - wordStart);
+      nsAutoTArray<char,200> utf8hyphens;
+      utf8hyphens.SetLength(utf8.Length() + 5);
+      char **rep = nsnull;
+      int *pos = nsnull;
+      int *cut = nsnull;
+      int err = hnj_hyphen_hyphenate2((HyphenDict*)mDict,
+                                      utf8.BeginReading(), utf8.Length(),
+                                      utf8hyphens.Elements(), nsnull,
+                                      &rep, &pos, &cut);
+      if (!err) {
+        PRUint32 utf16offset = wordStart;
+        const char *cp = utf8.BeginReading();
+        while (cp < utf8.EndReading()) {
+          if (UTF8traits::isASCII(*cp)) { // single-byte utf8 char
+            cp++;
+            utf16offset++;
+          } else if (UTF8traits::is2byte(*cp)) { // 2-byte sequence
+            cp += 2;
+            utf16offset++;
+          } else if (UTF8traits::is3byte(*cp)) { // 3-byte sequence
+            cp += 3;
+            utf16offset++;
+          } else { // must be a 4-byte sequence (no need to check validity,
+                   // as this was just created with NS_ConvertUTF16toUTF8)
+            NS_ASSERTION(UTF8traits::is4byte(*cp), "unexpected utf8 byte");
+            cp += 4;
+            utf16offset += 2;
+          }
+          NS_ASSERTION(cp <= utf8.EndReading(), "incomplete utf8 string?");
+          NS_ASSERTION(utf16offset <= aString.Length(), "length mismatch?");
+          if (utf8hyphens[cp - utf8.BeginReading() - 1] & 0x01) {
+            aHyphens[utf16offset - 1] = PR_TRUE;
+          }
+        }
+      }
+    }
+    
+    inWord = PR_FALSE;
+  }
+
+  return NS_OK;
+}
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1043,16 +1043,21 @@ pref("intl.locale.matchOS",             
 pref("intl.fallbackCharsetList.ISO-8859-1", "windows-1252");
 pref("font.language.group",                 "chrome://global/locale/intl.properties");
 
 // these locales have right-to-left UI
 pref("intl.uidirection.ar", "rtl");
 pref("intl.uidirection.he", "rtl");
 pref("intl.uidirection.fa", "rtl");
 
+// use en-US hyphenation by default for content tagged with plain lang="en"
+pref("intl.hyphenation-alias.en", "en-us");
+// and for other subtags of en-*, if no specific patterns are available
+pref("intl.hyphenation-alias.en-*", "en-us");
+
 pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Standard Symbols L, DejaVu Sans, Cambria Math");
 
 // Some CJK fonts have bad underline offset, their CJK character glyphs are overlapped (or adjoined)  to its underline.
 // These fonts are ignored the underline offset, instead of it, the underline is lowered to bottom of its em descent.
 pref("font.blacklist.underline_offset", "FangSong,Gulim,GulimChe,MingLiU,MingLiU-ExtB,MingLiU_HKSCS,MingLiU-HKSCS-ExtB,MS Gothic,MS Mincho,MS PGothic,MS PMincho,MS UI Gothic,PMingLiU,PMingLiU-ExtB,SimHei,SimSun,SimSun-ExtB,Hei,Kai,Apple LiGothic,Apple LiSung,Osaka");
 
 pref("images.dither", "auto");
 pref("security.directory",              "");