Bug 1028497 - Part 23: Implement FontFaceSet.{add,clear,delete,has}. r=jdaggett
authorCameron McCormack <cam@mcc.id.au>
Thu, 02 Oct 2014 12:32:09 +1000
changeset 231551 d2eec43dc03556451c575ad60222cac37944d983
parent 231550 ec544f1e834910a37b2a7f913dc6a6b369e72193
child 231552 805c3767797b426a6382f3536d6cf66884724227
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1028497
milestone35.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 1028497 - Part 23: Implement FontFaceSet.{add,clear,delete,has}. r=jdaggett Implementing Add, Delete and Clear involves shuffling FontFace objects between mOtherFaces and mUnavailableFaces.
layout/style/FontFace.h
layout/style/FontFaceSet.cpp
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -84,16 +84,26 @@ public:
   void SetUserFontEntry(gfxUserFontEntry* aEntry);
 
   /**
    * Returns whether this object is in a FontFaceSet.
    */
   bool IsInFontFaceSet() { return mInFontFaceSet; }
 
   /**
+   * Sets whether this object is in a FontFaceSet.  This is called by the
+   * FontFaceSet when Add, Remove, etc. are called.
+   */
+  void SetIsInFontFaceSet(bool aInFontFaceSet) {
+    MOZ_ASSERT(!(!aInFontFaceSet && IsConnected()),
+               "use DisconnectFromRule instead");
+    mInFontFaceSet = aInFontFaceSet;
+  }
+
+  /**
    * Returns whether this FontFace is initialized.  A CSS-connected
    * FontFace is considered initialized at construction time.  For
    * FontFace objects created using the FontFace JS constructor, it
    * is once all the descriptors have been parsed.
    */
   bool IsInitialized() const { return mInitialized; }
 
   FontFaceSet* GetFontFaceSet() const { return mFontFaceSet; }
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -151,41 +151,118 @@ FontFaceSet::HasConnectedFontFace(FontFa
   }
   return false;
 }
 #endif
 
 FontFaceSet*
 FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv)
 {
+  mPresContext->FlushUserFontSet();
+
+  // We currently only support FontFace objects being in a single FontFaceSet,
+  // and we also restrict the FontFaceSet to contain only FontFaces created
+  // in the same window.
+
+  if (aFontFace.GetFontFaceSet() != this) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+
+  if (aFontFace.IsConnected()) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
+    return nullptr;
+  }
+
+  if (aFontFace.IsInFontFaceSet()) {
+    return this;
+  }
+
+  bool removed = mUnavailableFaces.RemoveElement(&aFontFace);
+  if (!removed) {
+    MOZ_ASSERT(false, "should have found aFontFace in mUnavailableFaces");
+    return this;
+  }
+
+  aFontFace.SetIsInFontFaceSet(true);
+
+  MOZ_ASSERT(!mOtherFaces.Contains(&aFontFace),
+             "FontFace should not occur in mOtherFaces twice");
+
+  mOtherFaces.AppendElement(&aFontFace);
+
+  mOtherFacesDirty = true;
+  mPresContext->RebuildUserFontSet();
   return this;
 }
 
 void
 FontFaceSet::Clear()
 {
+  mPresContext->FlushUserFontSet();
+
+  if (mOtherFaces.IsEmpty()) {
+    return;
+  }
+
+  for (size_t i = 0; i < mOtherFaces.Length(); i++) {
+    FontFace* f = mOtherFaces[i];
+    f->SetIsInFontFaceSet(false);
+
+    MOZ_ASSERT(!mUnavailableFaces.Contains(f),
+               "FontFace should not occur in mUnavailableFaces twice");
+
+    mUnavailableFaces.AppendElement(f);
+  }
+
+  mOtherFaces.Clear();
+
+  mOtherFacesDirty = true;
+  mPresContext->RebuildUserFontSet();
 }
 
 bool
 FontFaceSet::Delete(FontFace& aFontFace, ErrorResult& aRv)
 {
-  return false;
+  mPresContext->FlushUserFontSet();
+
+  if (aFontFace.IsConnected()) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
+    return nullptr;
+  }
+
+  if (!mOtherFaces.RemoveElement(&aFontFace)) {
+    return false;
+  }
+
+  aFontFace.SetIsInFontFaceSet(false);
+
+  MOZ_ASSERT(!mUnavailableFaces.Contains(&aFontFace),
+             "FontFace should not occur in mUnavailableFaces twice");
+
+  mUnavailableFaces.AppendElement(&aFontFace);
+
+  mOtherFacesDirty = true;
+  mPresContext->RebuildUserFontSet();
+  return true;
 }
 
 bool
 FontFaceSet::HasAvailableFontFace(FontFace* aFontFace)
 {
   return aFontFace->GetFontFaceSet() == this &&
          aFontFace->IsInFontFaceSet();
 }
 
 bool
 FontFaceSet::Has(FontFace& aFontFace)
 {
-  return false;
+  mPresContext->FlushUserFontSet();
+
+  return HasAvailableFontFace(&aFontFace);
 }
 
 FontFace*
 FontFaceSet::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   mPresContext->FlushUserFontSet();
 
   if (aIndex < mConnectedFaces.Length()) {