Merge central to inbound
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 16 Feb 2012 11:47:36 +0100
changeset 89880 534b476701be72e3f2ec9ea1b5f38ba2d13b224b
parent 89879 69cb70c3a1e90a257d85a8db7701edc2584e4500 (current diff)
parent 89848 31fa580e684ca3c1e7e4a1969bc49b6a25b46024 (diff)
child 89881 79e5d61b3d594f17368aa2619da6a9a7b9417713
push idunknown
push userunknown
push dateunknown
milestone13.0a1
Merge central to inbound
browser/base/content/tabbrowser.xml
browser/locales/en-US/searchplugins/google-params.inc
content/base/public/nsIMessageWakeupService.idl
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -352,16 +352,19 @@ pref("browser.search.log", false);
 // Ordering of Search Engines in the Engine list. 
 pref("browser.search.order.1",                "chrome://browser-region/locale/region.properties");
 pref("browser.search.order.2",                "chrome://browser-region/locale/region.properties");
 pref("browser.search.order.3",                "chrome://browser-region/locale/region.properties");
 
 // search bar results always open in a new tab
 pref("browser.search.openintab", false);
 
+// context menu searches open in the foreground
+pref("browser.search.context.loadInBackground", false);
+
 // send ping to the server to update
 pref("browser.search.update", true);
 
 // disable logging for the search service update system by default
 pref("browser.search.update.log", false);
 
 // Check whether we need to perform engine updates every 6 hours
 pref("browser.search.update.interval", 21600);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3550,20 +3550,21 @@ const BrowserSearch = {
 
     // getSubmission can return null if the engine doesn't have a URL
     // with a text/html response type.  This is unlikely (since
     // SearchService._addEngineToStore() should fail for such an engine),
     // but let's be on the safe side.
     if (!submission)
       return;
 
+    let inBackground = Services.prefs.getBoolPref("browser.search.context.loadInBackground");
     openLinkIn(submission.uri.spec,
                useNewTab ? "tab" : "current",
                { postData: submission.postData,
-                 inBackground: false,
+                 inBackground: inBackground,
                  relatedToCurrent: true });
   },
 
   /**
    * Returns the search bar element if it is present in the toolbar, null otherwise.
    */
   get searchBar() {
     return document.getElementById("searchbar");
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3566,18 +3566,20 @@
             } catch(ex) {
               // Just ignore invalid urls
             }
           }
         }
 
         // these offsets are only used in dragend, but we need to free them here
         // as well
-        delete draggedTab._dragOffsetX;
-        delete draggedTab._dragOffsetY;
+        if (draggedTab) {
+          delete draggedTab._dragOffsetX;
+          delete draggedTab._dragOffsetY;
+        }
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
         // Note: while this case is correctly handled here, this event
         // isn't dispatched when the tab is moved within the tabstrip,
         // see bug 460801.
 
         // * mozUserCancelled = the user pressed ESC to cancel the drag
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -396,16 +396,18 @@
 @BINPATH@/components/nsPrompter.manifest
 @BINPATH@/components/nsPrompter.js
 #ifdef MOZ_SERVICES_SYNC
 @BINPATH@/components/SyncComponents.manifest
 @BINPATH@/components/Weave.js
 #endif
 @BINPATH@/components/TelemetryPing.js
 @BINPATH@/components/TelemetryPing.manifest
+@BINPATH@/components/messageWakeupService.js
+@BINPATH@/components/messageWakeupService.manifest
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsSafebrowsingApplication.manifest
 @BINPATH@/components/nsSafebrowsingApplication.js
 @BINPATH@/components/nsURLClassifier.manifest
deleted file mode 100644
--- a/browser/locales/en-US/searchplugins/google-params.inc
+++ /dev/null
@@ -1,15 +0,0 @@
-  <Param name="q" value="{searchTerms}"/>
-  <Param name="ie" value="utf-8"/>
-  <Param name="oe" value="utf-8"/>
-  <Param name="aq" value="t"/>
-  <!-- Dynamic parameters -->
-  <Param name="rls" value="{moz:distributionID}:{moz:locale}:{moz:official}"/>
-#if MOZ_UPDATE_CHANNEL == beta
-  <MozParam name="client" condition="defaultEngine" trueValue="firefox-beta" falseValue="firefox"/>
-#elif MOZ_UPDATE_CHANNEL == aurora
-  <MozParam name="client" condition="defaultEngine" trueValue="firefox-aurora" falseValue="firefox"/>
-#elif MOZ_UPDATE_CHANNEL == nightly
-  <MozParam name="client" condition="defaultEngine" trueValue="firefox-nightly" falseValue="firefox"/>
-#else
-  <MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
-#endif
--- a/browser/locales/en-US/searchplugins/google.xml
+++ b/browser/locales/en-US/searchplugins/google.xml
@@ -1,21 +1,34 @@
+#define GOOGLE_PARAMS <Param name="q" value="{searchTerms}"/><Param name="ie" value="utf-8"/><Param name="oe" value="utf-8"/><Param name="aq" value="t"/><Param name="rls" value="{moz:distributionID}:{moz:locale}:{moz:official}"/>
+#if MOZ_UPDATE_CHANNEL == beta
+#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-beta" falseValue="firefox"/>
+#elif MOZ_UPDATE_CHANNEL == aurora
+#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-aurora" falseValue="firefox"/>
+#elif MOZ_UPDATE_CHANNEL == nightly
+#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-nightly" falseValue="firefox"/>
+#else
+#define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
+#endif
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Google</ShortName>
 <Description>Google Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
 <Url type="application/x-suggestions+json" method="GET" template="http://suggestqueries.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}"/>
 <Url type="text/html" method="GET" template="http://www.google.com/search">
-#include google-params.inc
+#expand   __GOOGLE_PARAMS__
+#expand   __GOOGLE_CLIENT_PARAM__
 </Url>
 <!-- Keyword search URL is the same as the default, but with an additional parameter -->
 <Url type="application/x-moz-keywordsearch" method="GET" template="http://www.google.com/search">
-#include google-params.inc
+#expand   __GOOGLE_PARAMS__
+#expand   __GOOGLE_CLIENT_PARAM__
   <Param name="channel" value="fflb"/>
 </Url>
 <!-- Context/Right-click search URL is the same as the default, but with an additional parameter -->
 <Url type="application/x-moz-contextsearch" method="GET" template="http://www.google.com/search">
-#include google-params.inc
+#expand   __GOOGLE_PARAMS__
+#expand   __GOOGLE_CLIENT_PARAM__
   <Param name="channel" value="rcs"/>
 </Url>
 <SearchForm>http://www.google.com/</SearchForm>
 </SearchPlugin>
deleted file mode 100644
--- a/content/base/public/nsIMessageWakeupService.idl
+++ /dev/null
@@ -1,74 +0,0 @@
-/* ***** 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 the Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alon Zakai <azakai@mozilla.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 "nsISupports.idl"
-
-/**
- * This service lets other components be woken up when particular
- * messageManager messages arrive. By using this wakeup service,
- * those components do not need to be started until they are
- * needed.
- *
- * The parentprocessmessagemanager is used for this, so messages
- * send from childprocessmessagemanagers will be heard.
- *
- * Components can request wakeups using the .manifest files, or
- * by someone else calling requestWakeup. For .manifest files,
- * the line should look something like
- *
- *   category wakeup-request nsComponent @mozilla.org/myservice;1,
- *            nsIMyInterface,getService,myMessage1,myMessage2[,..]
- *
- * Currently we require services to expose wrappedJSObject, but
- * that will be cleaned up in bug 593407, at which point the
- * service that will be woken up must implement
- * nsIFrameMessageListener.
- */
-[scriptable, uuid(968e31b6-b859-42f3-8140-014378fe1783)]
-interface nsIMessageWakeupService : nsISupports
-{
-  /**
-   * Requests that the wakeup service wake us up when a particular
-   * message arrives. At that time the service will be woken up
-   * and subscribed to receive further messages of that name as
-   * well.
-   */
-  boolean requestWakeup(in AString aMessageName,
-                        in AString aCid,
-                        in AString aIid,
-                        in AString aMethod);
-};
-
--- a/content/base/src/messageWakeupService.js
+++ b/content/base/src/messageWakeupService.js
@@ -41,17 +41,17 @@ const Ci = Components.interfaces;
 
 const CATEGORY_WAKEUP_REQUEST = "wakeup-request";
 
 function MessageWakeupService() { };
 
 MessageWakeupService.prototype =
 {
   classID:          Components.ID("{f9798742-4f7b-4188-86ba-48b116412b29}"),
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIMessageWakeupService, Ci.nsISupports, Ci.nsIObserver]),
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   messagesData: [],
 
   get messageManager() {
     if (!this._messageManager)
       this._messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"].
                              getService(Ci.nsIFrameMessageManager);
     return this._messageManager;
--- a/dom/workers/XMLHttpRequestPrivate.cpp
+++ b/dom/workers/XMLHttpRequestPrivate.cpp
@@ -1888,16 +1888,22 @@ XMLHttpRequestPrivate::MaybeDispatchPrem
   mWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(mProxy, "Must have a proxy here!");
 
   xhr::StateData state = {
     JSVAL_VOID, JSVAL_VOID, JSVAL_VOID, INT_TO_JSVAL(4), JSVAL_VOID,
     false, false, false, false, false
   };
 
+  // If we never saw loadstart, we must Unpin ourselves or we will hang at
+  // shutdown.  Do that here before any early returns.
+  if (!mProxy->mSeenLoadStart && mProxy->mWorkerPrivate) {
+    Unpin(aCx);
+  }
+
   if (mProxy->mSeenUploadLoadStart) {
     JSObject* target = mProxy->mXMLHttpRequestPrivate->GetUploadJSObject();
     NS_ASSERTION(target, "Must have a target!");
 
     if (!xhr::UpdateXHRState(aCx, target, true, state) ||
         !DispatchPrematureAbortEvent(aCx, target, STRING_abort, true) ||
         !DispatchPrematureAbortEvent(aCx, target, STRING_loadend, true)) {
       return false;
--- a/layout/base/tests/bug583889_inner1.html
+++ b/layout/base/tests/bug583889_inner1.html
@@ -15,43 +15,53 @@ function postPos() {
   parent.postMessage(JSON.stringify({ top: document.body.scrollTop,
                                       left: document.body.scrollLeft }),
                      "*");
 }
 
 function runTest() {
   var inner = document.getElementById("inner");
   window.onload = grabEventAndGo;
+  // Wait for onLoad event.
   yield;
 
   document.body.scrollTop = 300;
   document.body.scrollLeft = 300;
 
   postPos();
 
   inner.src = "bug583889_inner2.html#id1";
   inner.onload = grabEventAndGo;
+  // Let parent process sent message.
+  // Wait for onLoad event from 'inner' iframe.
   yield;
   
   postPos();
   
   inner.onload = null;
   dump("hi");
   inner.contentWindow.location = "bug583889_inner2.html#id2"
   waitAsync();
+  // Let parent process sent message.
+  // Let 'inner' iframe update itself.
   yield;
 
   postPos();
 
   inner.contentWindow.location.hash = "#id3"
   waitAsync();
+  // Let parent process sent message.
+  // Let 'inner' iframe update itself.
   yield;
 
   postPos();
 
   parent.postMessage("done", "*");
+  // Let parent process sent messages.
+  // "End" generator.
+  yield;
 }
 
 var gen = runTest();
 gen.next();
 </script>
 </body>
 </html>
--- a/layout/base/tests/test_bug583889.html
+++ b/layout/base/tests/test_bug583889.html
@@ -18,32 +18,37 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 
 function grabEventAndGo(event) {
   gen.send(event);
 }
 
 function runTest() {
   window.onload = grabEventAndGo;
+  // Wait for onLoad event.
   yield;
 
   var inner = $("inner");
   inner.src = "bug583889_inner1.html";
   window.onmessage = grabEventAndGo;
+  // Wait for message from 'inner' iframe.
   event = yield;
 
   while (event.data != "done") {
     data = JSON.parse(event.data);
     is(data.top, 300, "should remain at same top");
     is(data.left, 300, "should remain at same left");
 
+    // Wait for message from 'inner' iframe.
     event = yield;
   }
 
-  SimpleTest.finish();
+  // finish(), yet let the test actually end first, to be safe.
+  SimpleTest.executeSoon(SimpleTest.finish);
+  // "End" generator.
   yield;
 }
 
 var gen = runTest();
 gen.next();
 </script>
 </pre>
 </body>
--- a/media/libpng/pngrutil.c
+++ b/media/libpng/pngrutil.c
@@ -396,18 +396,25 @@ png_decompress_chunk(png_structp png_ptr
 #if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
     defined(PNG_USER_CHUNK_MALLOC_MAX)
       else
 #endif
       if (expanded_size > 0)
       {
          /* Success (maybe) - really uncompress the chunk. */
          png_size_t new_size = 0;
-         png_charp text = png_malloc_warn(png_ptr,
-                        prefix_size + expanded_size + 1);
+         png_charp text = NULL;
+         /* Need to check for both truncation (64-bit platforms) and integer
+          * overflow.
+          */
+         if (prefix_size + expanded_size > prefix_size &&
+             prefix_size + expanded_size < 0xffffffffU)
+         {
+            text = png_malloc_warn(png_ptr, prefix_size + expanded_size + 1);
+         }
 
          if (text != NULL)
          {
             png_memcpy(text, png_ptr->chunkdata, prefix_size);
             new_size = png_inflate(png_ptr,
                 (png_bytep)(png_ptr->chunkdata + prefix_size),
                 chunklength - prefix_size,
                 (png_bytep)(text + prefix_size), expanded_size);
--- a/xpcom/typelib/xpt/tools/xpt.py
+++ b/xpcom/typelib/xpt/tools/xpt.py
@@ -167,17 +167,17 @@ class Type(object):
 
         """
         flags = 0
         if self.pointer:
             flags |= 0x80
         if self.reference:
             flags |= 0x20
         return flags
-    
+
     @staticmethod
     def read(typelib, map, data_pool, offset):
         """
         Read a TypeDescriptor at |offset| from the mmaped file |map| with
         data pool offset |data_pool|. Returns (Type, next offset),
         where |next offset| is an offset suitable for reading the data
         following this TypeDescriptor.
         
@@ -434,37 +434,37 @@ class StringWithSizeType(Type):
         following this StringWithSizeTypeDescriptor.
         """
         if not flags['pointer']:
             return None, offset
         start = data_pool + offset - 1
         (size_is_arg_num, length_is_arg_num) = StringWithSizeType._descriptor.unpack(map[start:start + StringWithSizeType._descriptor.size])
         offset += StringWithSizeType._descriptor.size
         return StringWithSizeType(size_is_arg_num, length_is_arg_num, **flags), offset
-    
+
     def write(self, typelib, file):
         """
         Write a StringWithSizeTypeDescriptor to |file|, which is assumed
         to be seeked to the proper position.
 
         """
         Type.write(self, typelib, file)
         file.write(StringWithSizeType._descriptor.pack(self.size_is_arg_num,
                                                        self.length_is_arg_num))
-        
+
     def __str__(self):
         return "string_s"
 
 class WideStringWithSizeType(Type):
     """
     A type representing a UTF-16 encoded string whose size and length
     are passed as separate arguments to a method.
     (WideStringWithSizeTypeDescriptor from the typelib specification.)
 
-    """    
+    """
     _descriptor = struct.Struct(">BB")
 
     def __init__(self, size_is_arg_num, length_is_arg_num,
                  pointer=True, **kwargs):
         if not pointer:
             raise DataError, "WideStringWithSizeType is not valid with pointer=False"
         Type.__init__(self, pointer=pointer, **kwargs)
         self.size_is_arg_num = size_is_arg_num
@@ -609,29 +609,29 @@ class Param(object):
             s += "dipper "
         if self.retval:
             s += "retval "
         if self.shared:
             s += "shared "
         if self.optional:
             s += "optional "
         return s
-            
+
     def __str__(self):
         return self.prefix() + str(self.type)
 
 class Method(object):
     """
     A method of an interface, defining its associated parameters
     and return value.
     (MethodDescriptor from the typelib specification.)
     
     """
     _descriptorstart = struct.Struct(">BIB")
-    
+
     def __init__(self, name, result,
                  params=[], getter=False, setter=False, notxpcom=False,
                  constructor=False, hidden=False, optargc=False,
                  implicit_jscontext=False):
         self.name = name
         self._name_offset = 0
         self.getter = getter
         self.setter = setter
@@ -772,17 +772,17 @@ class Constant(object):
     # http://hg.mozilla.org/mozilla-central/annotate/9c85f9aaec8c/xpcom/typelib/xpt/src/xpt_struct.c#l689
     typemap = {Type.Tags.int16: '>h',
                Type.Tags.uint16: '>H',
                Type.Tags.int32: '>i',
                Type.Tags.uint32: '>I'}
 
     def __init__(self, name, type, value):
         self.name = name
-        self._name_offset = 0        
+        self._name_offset = 0
         self.type = type
         self.value = value
 
     @staticmethod
     def read(typelib, map, data_pool, offset):
         """
         Read a ConstDescriptor at |offset| from the mmaped file |map| with
         data pool offset |data_pool|. Returns (Constant, next offset),
@@ -834,21 +834,21 @@ class Constant(object):
 
 class Interface(object):
     """
     An Interface represents an object, with its associated methods
     and constant values.
     (InterfaceDescriptor from the typelib specification.)
     
     """
-    _direntry = struct.Struct(">16sIII")    
+    _direntry = struct.Struct(">16sIII")
     _descriptorstart = struct.Struct(">HH")
 
     UNRESOLVED_IID = "00000000-0000-0000-0000-000000000000"
-    
+
     def __init__(self, name, iid=UNRESOLVED_IID, namespace="",
                  resolved=False, parent=None, methods=[], constants=[],
                  scriptable=False, function=False, builtinclass=False):
         self.resolved = resolved
         #TODO: should validate IIDs!
         self.iid = iid
         self.name = name
         self.namespace = namespace
@@ -967,17 +967,17 @@ class Interface(object):
         flags = 0
         if self.scriptable:
             flags |= 0x80
         if self.function:
             flags |= 0x40
         if self.builtinclass:
             flags |= 0x20
         file.write(struct.pack(">B", flags))
-        
+
     def write_names(self, file, data_pool_offset):
         """
         Write this interface's name and namespace to |file|,
         as well as the names of all of its methods and constants.
         Assumes that |file| is currently seeked to an unused portion
         of the data pool.
 
         """
@@ -1011,61 +1011,64 @@ class Typelib(object):
     def __init__(self, version=TYPELIB_VERSION, interfaces=[], annotations=[]):
         """
         Instantiate a new Typelib.
 
         """
         self.version = version
         self.interfaces = list(interfaces)
         self.annotations = list(annotations)
+        self.filename = None
 
     @staticmethod
     def iid_to_string(iid):
         """
         Convert a 16-byte IID into a UUID string.
 
         """
         def hexify(s):
             return ''.join(["%02x" % ord(x) for x in s])
+
         return "%s-%s-%s-%s-%s" % (hexify(iid[:4]), hexify(iid[4:6]),
                                    hexify(iid[6:8]), hexify(iid[8:10]),
                                    hexify(iid[10:]))
 
     @staticmethod
     def string_to_iid(iid_str):
         """
         Convert a UUID string into a 16-byte IID.
 
         """
         s = iid_str.replace('-','')
         return ''.join([chr(int(s[i:i+2], 16)) for i in range(0, len(s), 2)])
-    
+
     @staticmethod
     def read_string(map, data_pool, offset):
         if offset == 0:
             return ""
         sz = map.find('\x00', data_pool + offset - 1)
         if sz == -1:
             return ""
         return map[data_pool + offset - 1:sz]
-    
+
     @staticmethod
     def read(filename):
         """
         Read a typelib from the file named |filename| and return
         the constructed Typelib object.
 
         """
         with open(filename, "r+b") as f:
             st = os.fstat(f.fileno())
             map = f.read(st.st_size)
             data = Typelib._header.unpack(map[:Typelib._header.size])
             if data[0] != XPT_MAGIC:
                 raise FileFormatError, "Bad magic: %s" % data[0]
             xpt = Typelib((data[1], data[2]))
+            xpt.filename = filename
             num_interfaces = data[3]
             file_length = data[4]
             if file_length != st.st_size:
                 raise FileFormatError, "File is of wrong length, got %d bytes, expected %d" % (st.st_size, file_length)
             #XXX: by spec this is a zero-based file offset. however,
             # the xpt_xdr code always subtracts 1 from data offsets
             # (because that's what you do in the data pool) so it
             # winds up accidentally treating this as 1-based.
@@ -1091,17 +1094,17 @@ class Typelib(object):
                 name = Typelib.read_string(map, data_pool_offset, ide[1])
                 namespace = Typelib.read_string(map, data_pool_offset, ide[2])
                 iface = Interface(name, iid, namespace)
                 iface._descriptor_offset = ide[3]
                 xpt.interfaces.append(iface)
             for iface in xpt.interfaces:
                 iface.read_descriptor(xpt, map, data_pool_offset)
         return xpt
-    
+
     def __repr__(self):
         return "<Typelib with %d interfaces>" % len(self.interfaces)
 
     def _sanityCheck(self):
         """
         Check certain assumptions about data contained in this typelib.
         Sort the interfaces array by IID, check that all interfaces
         referenced by methods exist in the array.
@@ -1203,39 +1206,44 @@ class Typelib(object):
                             merged = True
                             self.interfaces[self.interfaces.index(j)] = i
                         elif i.iid == Interface.UNRESOLVED_IID:
                             # keep j
                             merged_interfaces.append((i, j))
                             merged = True
                             # Fixup will happen after processing all interfaces.
                         else:
-                            # Same name, different IIDs, raise an exception
+                            # Same name but different IIDs: raise an exception.
+                            # self.* is the (target) Typelib being merged into,
+                            #   not the one which j.iid was from.
                             raise DataError, \
                                   "Typelibs contain definitions of interface %s" \
-                                    " with different IIDs (%s vs %s)!" % \
-                                    (i.name, i.iid, j.iid)
+                                    " with different IIDs (%s (%s) vs %s (%s))!" % \
+                                    (i.name, i.iid, other.filename, j.iid, self.filename)
                 elif i.iid == j.iid and i.iid != Interface.UNRESOLVED_IID:
-                    # Same IID, different names, raise an exception
+                    # Same IID but different names: raise an exception.
+                    # self.* is the (target) Typelib being merged into,
+                    #   not the one which j.name was from.
                     raise DataError, \
                           "Typelibs contain definitions of interface %s" \
-                            " with different names (%s vs %s)!" % \
-                            (i.iid, i.name, j.name)
+                            " with different names (%s (%s) vs %s (%s))!" % \
+                            (i.iid, i.name, other.filename, j.name, self.filename)
             if not merged:
                 # No partially matching interfaces, so just take this interface
                 self.interfaces.append(i)
+
         # Now fixup any merged interfaces
         def checkType(t, replaced_from, replaced_to):
             if isinstance(t, InterfaceType) and t.iface == replaced_from:
                 t.iface = replaced_to
             elif isinstance(t, ArrayType) and \
                  isinstance(t.element_type, InterfaceType) and \
                  t.element_type.iface == replaced_from:
                 t.element_type.iface = replaced_to
-        
+
         for replaced_from, replaced_to in merged_interfaces:
             for i in self.interfaces:
                 # Replace parent references
                 if i.parent is not None and i.parent == replaced_from:
                     i.parent = replaced_to
                 for m in i.methods:
                     # Replace InterfaceType params and return values
                     checkType(m.result.type, replaced_from, replaced_to)