nsFontFaceUtils.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. // vim:cindent:ts=2:et:sw=2:
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #include "gfxUserFontSet.h"
  7. #include "nsFontFaceUtils.h"
  8. #include "nsFontMetrics.h"
  9. #include "nsIFrame.h"
  10. #include "nsLayoutUtils.h"
  11. #include "nsPlaceholderFrame.h"
  12. #include "nsTArray.h"
  13. #include "SVGTextFrame.h"
  14. static bool
  15. StyleContextContainsFont(nsStyleContext* aStyleContext,
  16. const gfxUserFontSet* aUserFontSet,
  17. const gfxUserFontEntry* aFont)
  18. {
  19. // if the font is null, simply check to see whether fontlist includes
  20. // downloadable fonts
  21. if (!aFont) {
  22. const mozilla::FontFamilyList& fontlist =
  23. aStyleContext->StyleFont()->mFont.fontlist;
  24. return aUserFontSet->ContainsUserFontSetFonts(fontlist);
  25. }
  26. // first, check if the family name is in the fontlist
  27. const nsString& familyName = aFont->FamilyName();
  28. if (!aStyleContext->StyleFont()->mFont.fontlist.Contains(familyName)) {
  29. return false;
  30. }
  31. // family name is in the fontlist, check to see if the font group
  32. // associated with the frame includes the specific userfont
  33. RefPtr<nsFontMetrics> fm =
  34. nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext, 1.0f);
  35. if (fm->GetThebesFontGroup()->ContainsUserFont(aFont)) {
  36. return true;
  37. }
  38. return false;
  39. }
  40. static bool
  41. FrameUsesFont(nsIFrame* aFrame, const gfxUserFontEntry* aFont)
  42. {
  43. // check the style context of the frame
  44. gfxUserFontSet* ufs = aFrame->PresContext()->GetUserFontSet();
  45. if (StyleContextContainsFont(aFrame->StyleContext(), ufs, aFont)) {
  46. return true;
  47. }
  48. // check additional style contexts
  49. int32_t contextIndex = 0;
  50. for (nsStyleContext* extraContext;
  51. (extraContext = aFrame->GetAdditionalStyleContext(contextIndex));
  52. ++contextIndex) {
  53. if (StyleContextContainsFont(extraContext, ufs, aFont)) {
  54. return true;
  55. }
  56. }
  57. return false;
  58. }
  59. static void
  60. ScheduleReflow(nsIPresShell* aShell, nsIFrame* aFrame)
  61. {
  62. nsIFrame* f = aFrame;
  63. if (f->IsFrameOfType(nsIFrame::eSVG) || f->IsSVGText()) {
  64. // SVG frames (and the non-SVG descendants of an SVGTextFrame) need special
  65. // reflow handling. We need to search upwards for the first displayed
  66. // nsSVGOuterSVGFrame or non-SVG frame, which is the frame we can call
  67. // FrameNeedsReflow on. (This logic is based on
  68. // nsSVGUtils::ScheduleReflowSVG and
  69. // SVGTextFrame::ScheduleReflowSVGNonDisplayText.)
  70. if (f->GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
  71. while (f) {
  72. if (!(f->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
  73. if (NS_SUBTREE_DIRTY(f)) {
  74. // This is a displayed frame, so if it is already dirty, we
  75. // will be reflowed soon anyway. No need to call
  76. // FrameNeedsReflow again, then.
  77. return;
  78. }
  79. if (f->GetStateBits() & NS_STATE_IS_OUTER_SVG ||
  80. !(f->IsFrameOfType(nsIFrame::eSVG) || f->IsSVGText())) {
  81. break;
  82. }
  83. f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
  84. }
  85. f = f->GetParent();
  86. }
  87. MOZ_ASSERT(f, "should have found an ancestor frame to reflow");
  88. }
  89. }
  90. aShell->FrameNeedsReflow(f, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  91. }
  92. /* static */ void
  93. nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
  94. const gfxUserFontEntry* aFont)
  95. {
  96. AutoTArray<nsIFrame*, 4> subtrees;
  97. subtrees.AppendElement(aSubtreeRoot);
  98. nsIPresShell* ps = aSubtreeRoot->PresContext()->PresShell();
  99. // check descendants, iterating over subtrees that may include
  100. // additional subtrees associated with placeholders
  101. do {
  102. nsIFrame* subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
  103. subtrees.RemoveElementAt(subtrees.Length() - 1);
  104. // Check all descendants to see if they use the font
  105. AutoTArray<nsIFrame*, 32> stack;
  106. stack.AppendElement(subtreeRoot);
  107. do {
  108. nsIFrame* f = stack.ElementAt(stack.Length() - 1);
  109. stack.RemoveElementAt(stack.Length() - 1);
  110. // if this frame uses the font, mark its descendants dirty
  111. // and skip checking its children
  112. if (FrameUsesFont(f, aFont)) {
  113. ScheduleReflow(ps, f);
  114. } else {
  115. if (f->GetType() == nsGkAtoms::placeholderFrame) {
  116. nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
  117. if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
  118. // We have another distinct subtree we need to mark.
  119. subtrees.AppendElement(oof);
  120. }
  121. }
  122. nsIFrame::ChildListIterator lists(f);
  123. for (; !lists.IsDone(); lists.Next()) {
  124. nsFrameList::Enumerator childFrames(lists.CurrentList());
  125. for (; !childFrames.AtEnd(); childFrames.Next()) {
  126. nsIFrame* kid = childFrames.get();
  127. stack.AppendElement(kid);
  128. }
  129. }
  130. }
  131. } while (!stack.IsEmpty());
  132. } while (!subtrees.IsEmpty());
  133. }