Bug 1514869 - patch 6 - Hook up SetupFamilyCharMap for shared font-list Family records, to accelerate last-ditch fallback searches. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Sat, 27 Apr 2019 15:39:26 +0000
changeset 530575 0bad995bae2250682807c86f9d9abc23b0f2313c
parent 530574 ba0672dcd82d09031cb5899716a5f90916438c42
child 530576 b3fbab6d325ae88011a9589d6398353f5f64377b
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1514869
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1514869 - patch 6 - Hook up SetupFamilyCharMap for shared font-list Family records, to accelerate last-ditch fallback searches. r=jwatt Differential Revision: https://phabricator.services.mozilla.com/D23355
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
gfx/thebes/SharedFontList.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5023,16 +5023,24 @@ mozilla::ipc::IPCResult ContentParent::R
 mozilla::ipc::IPCResult ContentParent::RecvInitOtherFamilyNames(
     const uint32_t& aGeneration, const bool& aDefer, bool* aLoaded) {
   gfxPlatformFontList::PlatformFontList()->InitOtherFamilyNames(aGeneration,
                                                                 aDefer);
   *aLoaded = true;
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult ContentParent::RecvSetupFamilyCharMap(
+    const uint32_t& aGeneration,
+    const mozilla::fontlist::Pointer& aFamilyPtr) {
+  gfxPlatformFontList::PlatformFontList()->SetupFamilyCharMap(aGeneration,
+                                                              aFamilyPtr);
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult ContentParent::RecvGraphicsError(
     const nsCString& aError) {
   gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder();
   if (lf) {
     std::stringstream message;
     message << "CP+" << aError.get();
     lf->UpdateStringsVector(message.str());
   }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1118,16 +1118,20 @@ class ContentParent final : public PCont
   mozilla::ipc::IPCResult RecvSetCharacterMap(
       const uint32_t& aGeneration, const mozilla::fontlist::Pointer& aFacePtr,
       const gfxSparseBitSet& aMap);
 
   mozilla::ipc::IPCResult RecvInitOtherFamilyNames(const uint32_t& aGeneration,
                                                    const bool& aDefer,
                                                    bool* aLoaded);
 
+  mozilla::ipc::IPCResult RecvSetupFamilyCharMap(
+      const uint32_t& aGeneration,
+      const mozilla::fontlist::Pointer& aFamilyPtr);
+
   mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsString& aCodecName,
                                                     const uint32_t& aDecodeFPS);
 
   mozilla::ipc::IPCResult RecvNotifyPushObservers(
       const nsCString& aScope, const IPC::Principal& aPrincipal,
       const nsString& aMessageId);
 
   mozilla::ipc::IPCResult RecvNotifyPushObserversWithData(
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1254,16 +1254,23 @@ parent:
      * Face record to be updated with its character-map reference before it can
      * proceed with its font-matching work.
      *
      * NOTE: a later patch in the series makes this async.
      */
     sync SetCharacterMap(uint32_t aGeneration, Pointer aFacePtr, gfxSparseBitSet aMap);
 
     /**
+     * Ask the parent to set up the merged charmap for a family, to accelerate
+     * future fallback searches.
+     * aFamilyPtr may refer to an element of either the Families() or AliasFamilies().
+     */
+    async SetupFamilyCharMap(uint32_t aGeneration, Pointer aFamilyPtr);
+
+    /**
      * Ask the parent to try and complete the InitOtherFamilyNames task, because
      * we're trying to look up a localized font name. This is a sync method so that
      * the update will be available before the child continues reflow; however, it
      * is possible the task will have timed-out in the parent and not actually
      * completed during this call.
      *
      * @param aGeneration
      *   Font-list generation, so requests relating to an obsolete list can be
--- a/gfx/thebes/SharedFontList.cpp
+++ b/gfx/thebes/SharedFontList.cpp
@@ -307,19 +307,54 @@ void Family::SetFacePtrs(FontList* aList
   // store them at the appropriate positions and set the mIsSimple flag to
   // accelerate font-matching.
   mFaces = aList->Alloc(size);
   memcpy(mFaces.ToPtr(aList), aFaces.Elements(), size);
   mFaceCount.store(aFaces.Length());
 }
 
 void Family::SetupFamilyCharMap(FontList* aList) {
-  // XXX TODO: [in patch 6]
   // Set the character map of the family to the union of all the face cmaps,
   // to allow font fallback searches to more rapidly reject the family.
+  if (!XRE_IsParentProcess()) {
+    // |this| could be a Family record in either the Families() or Aliases()
+    // arrays
+    dom::ContentChild::GetSingleton()->SendSetupFamilyCharMap(
+        aList->GetGeneration(), aList->ToSharedPointer(this));
+    return;
+  }
+  gfxSparseBitSet familyMap;
+  Pointer firstMapShmPointer;
+  SharedBitSet* firstMap = nullptr;
+  bool merged = false;
+  Pointer* faces = Faces(aList);
+  if (!faces) {
+    return;
+  }
+  for (size_t i = 0; i < NumFaces(); i++) {
+    auto f = static_cast<Face*>(faces[i].ToPtr(aList));
+    auto faceMap = static_cast<SharedBitSet*>(f->mCharacterMap.ToPtr(aList));
+    MOZ_ASSERT(faceMap);
+    if (!firstMap) {
+      firstMap = faceMap;
+      firstMapShmPointer = f->mCharacterMap;
+    } else if (faceMap != firstMap) {
+      if (!merged) {
+        familyMap.Union(*firstMap);
+        merged = true;
+      }
+      familyMap.Union(*faceMap);
+    }
+  }
+  if (merged) {
+    mCharacterMap =
+      gfxPlatformFontList::PlatformFontList()->GetShmemCharMap(&familyMap);
+  } else {
+    mCharacterMap = firstMapShmPointer;
+  }
 }
 
 FontList::FontList(uint32_t aGeneration) {
   if (XRE_IsParentProcess()) {
     // Create the initial shared block, and initialize Header
     if (AppendShmBlock()) {
       Header& header = GetHeader();
       header.mAllocated.store(sizeof(Header));
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -28,16 +28,18 @@
 #endif
 
 #undef ERROR /* defined by Windows.h, conflicts with some generated bindings \
                 code when this gets indirectly included via shared font list \
               */
 
 typedef struct hb_blob_t hb_blob_t;
 
+class SharedBitSet;
+
 class gfxSparseBitSet {
  private:
   friend class SharedBitSet;
 
   enum { BLOCK_SIZE = 32 };  // ==> 256 codepoints per block
   enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
   enum { NO_BLOCK = 0xffff };  // index value indicating missing (empty) block
 
@@ -293,16 +295,18 @@ class gfxSparseBitSet {
       const uint32_t* src = reinterpret_cast<const uint32_t*>(
           &aBitset.mBlocks[aBitset.mBlockIndex[i]].mBits);
       for (uint32_t j = 0; j < BLOCK_SIZE / 4; ++j) {
         dst[j] |= src[j];
       }
     }
   }
 
+  inline void Union(const SharedBitSet& aBitset);
+
   void Compact() {
     // TODO: Discard any empty blocks, and adjust index accordingly.
     // (May not be worth doing, though, because we so rarely clear bits
     // that were previously set.)
     mBlocks.Compact();
     mBlockIndex.Compact();
   }
 
@@ -439,16 +443,17 @@ class SharedBitSet {
       if (memcmp(&b1.mBits, &b2.mBits, BLOCK_SIZE) != 0) {
         return false;
       }
     }
     return true;
   }
 
  private:
+  friend class gfxSparseBitSet;
   SharedBitSet() = delete;
 
   explicit SharedBitSet(const gfxSparseBitSet& aBitset)
       : mBlockIndexCount(
             mozilla::AssertedCast<uint16_t>(aBitset.mBlockIndex.Length())),
         mBlockCount(0) {
     uint16_t* blockIndex = reinterpret_cast<uint16_t*>(this + 1);
     Block* blocks = reinterpret_cast<Block*>(blockIndex + mBlockIndexCount);
@@ -470,16 +475,47 @@ class SharedBitSet {
 
   uint16_t mBlockIndexCount;
   uint16_t mBlockCount;
 
   // After the two "header" fields above, we have a block index array
   // of uint16_t[mBlockIndexCount], followed by mBlockCount Block records.
 };
 
+// Union the contents of a SharedBitSet with the target gfxSparseBitSet
+inline void gfxSparseBitSet::Union(const SharedBitSet& aBitset) {
+  // ensure mBlockIndex is large enough
+  while (mBlockIndex.Length() < aBitset.mBlockIndexCount) {
+    mBlockIndex.AppendElement(NO_BLOCK);
+  }
+  auto blockIndex = reinterpret_cast<const uint16_t*>(&aBitset + 1);
+  auto blocks = reinterpret_cast<const Block*>(blockIndex + aBitset.mBlockIndexCount);
+  for (uint32_t i = 0; i < aBitset.mBlockIndexCount; ++i) {
+    // if it is missing (implicitly empty) in source, just skip
+    if (blockIndex[i] == NO_BLOCK) {
+      continue;
+    }
+    // if the block is missing, just copy from source bitset
+    if (mBlockIndex[i] == NO_BLOCK) {
+      mBlocks.AppendElement(blocks[blockIndex[i]]);
+      MOZ_ASSERT(mBlocks.Length() < 0xffff, "block index overflow");
+      mBlockIndex[i] = uint16_t(mBlocks.Length() - 1);
+      continue;
+    }
+    // else set existing target block to the union of both
+    uint32_t* dst = reinterpret_cast<uint32_t*>(
+        &mBlocks[mBlockIndex[i]].mBits);
+    const uint32_t* src = reinterpret_cast<const uint32_t*>(
+        &blocks[blockIndex[i]].mBits);
+    for (uint32_t j = 0; j < BLOCK_SIZE / 4; ++j) {
+      dst[j] |= src[j];
+    }
+  }
+}
+
 #define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
 
 namespace mozilla {
 
 // Byte-swapping types and name table structure definitions moved from
 // gfxFontUtils.cpp to .h file so that gfxFont.cpp can also refer to them
 #pragma pack(1)
 
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -2142,16 +2142,49 @@ void gfxPlatformFontList::SetCharacterMa
     return;
   }
   fontlist::Face* face = static_cast<fontlist::Face*>(aFacePtr.ToPtr(list));
   if (face) {
     face->SetCharacterMap(list, &aMap);
   }
 }
 
+void gfxPlatformFontList::SetupFamilyCharMap(
+    uint32_t aGeneration, const fontlist::Pointer& aFamilyPtr) {
+  auto list = SharedFontList();
+  MOZ_ASSERT(list);
+  if (!list) {
+    return;
+  }
+  if (list->GetGeneration() != aGeneration) {
+    return;
+  }
+  auto family = static_cast<fontlist::Family*>(aFamilyPtr.ToPtr(list));
+  // validate family pointer before trying to use it
+  if (family >= list->Families() &&
+      family < list->Families() + list->NumFamilies()) {
+    size_t offset = (char*)family - (char*)list->Families();
+    if (offset % sizeof(fontlist::Family) != 0) {
+      MOZ_DIAGNOSTIC_ASSERT(false, "misaligned Family pointer");
+      return;
+    }
+  } else if (family >= list->AliasFamilies() &&
+             family < list->AliasFamilies() + list->NumAliases()) {
+    size_t offset = (char*)family - (char*)list->AliasFamilies();
+    if (offset % sizeof(fontlist::Family) != 0) {
+      MOZ_DIAGNOSTIC_ASSERT(false, "misaligned Family pointer");
+      return;
+    }
+  } else {
+    MOZ_DIAGNOSTIC_ASSERT(false, "not a valid Family or AliasFamily pointer");
+    return;
+  }
+  family->SetupFamilyCharMap(list);
+}
+
 void gfxPlatformFontList::InitOtherFamilyNames(uint32_t aGeneration,
                                                bool aDefer) {
   auto list = SharedFontList();
   MOZ_ASSERT(list);
   if (!list) {
     return;
   }
   if (list->GetGeneration() != aGeneration) {
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -255,16 +255,19 @@ class gfxPlatformFontList : public gfxFo
   void ShareFontListShmBlockToProcess(
       uint32_t aGeneration, uint32_t aIndex, /*base::ProcessId*/ uint32_t aPid,
       /*mozilla::ipc::SharedMemoryBasic::Handle*/ void* aOut);
 
   void SetCharacterMap(uint32_t aGeneration,
                        const mozilla::fontlist::Pointer& aFacePtr,
                        const gfxSparseBitSet& aMap);
 
+  void SetupFamilyCharMap(uint32_t aGeneration,
+                          const mozilla::fontlist::Pointer& aFamilyPtr);
+
   MOZ_MUST_USE bool InitializeFamily(mozilla::fontlist::Family* aFamily);
   void InitializeFamily(uint32_t aGeneration, uint32_t aFamilyIndex);
 
   // name lookup table methods
 
   void AddOtherFamilyName(gfxFontFamily* aFamilyEntry,
                           nsCString& aOtherFamilyName);