Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/nsFontFaceUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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
7
#include "nsFontFaceUtils.h"
8
9
#include "gfxUserFontSet.h"
10
#include "nsFontMetrics.h"
11
#include "nsIFrame.h"
12
#include "nsLayoutUtils.h"
13
#include "nsPlaceholderFrame.h"
14
#include "nsTArray.h"
15
#include "SVGTextFrame.h"
16
17
using namespace mozilla;
18
19
static bool
20
ComputedStyleContainsFont(ComputedStyle* aComputedStyle,
21
                          nsPresContext* aPresContext,
22
                          const gfxUserFontSet* aUserFontSet,
23
                          const gfxUserFontEntry* aFont)
24
0
{
25
0
  // if the font is null, simply check to see whether fontlist includes
26
0
  // downloadable fonts
27
0
  if (!aFont) {
28
0
    const mozilla::FontFamilyList& fontlist =
29
0
      aComputedStyle->StyleFont()->mFont.fontlist;
30
0
    return aUserFontSet->ContainsUserFontSetFonts(fontlist);
31
0
  }
32
0
33
0
  // first, check if the family name is in the fontlist
34
0
  if (!aComputedStyle->StyleFont()->mFont.fontlist.Contains(aFont->FamilyName())) {
35
0
    return false;
36
0
  }
37
0
38
0
  // family name is in the fontlist, check to see if the font group
39
0
  // associated with the frame includes the specific userfont
40
0
  RefPtr<nsFontMetrics> fm =
41
0
    nsLayoutUtils::GetFontMetricsForComputedStyle(aComputedStyle,
42
0
                                                  aPresContext,
43
0
                                                  1.0f);
44
0
45
0
  if (fm->GetThebesFontGroup()->ContainsUserFont(aFont)) {
46
0
    return true;
47
0
  }
48
0
49
0
  return false;
50
0
}
51
52
static bool
53
FrameUsesFont(nsIFrame* aFrame, const gfxUserFontEntry* aFont)
54
0
{
55
0
  // check the style of the frame
56
0
  nsPresContext* pc = aFrame->PresContext();
57
0
  gfxUserFontSet* ufs = pc->GetUserFontSet();
58
0
  if (ComputedStyleContainsFont(aFrame->Style(), pc, ufs, aFont)) {
59
0
    return true;
60
0
  }
61
0
62
0
  // check additional styles
63
0
  int32_t contextIndex = 0;
64
0
  for (ComputedStyle* extraContext;
65
0
       (extraContext = aFrame->GetAdditionalComputedStyle(contextIndex));
66
0
       ++contextIndex) {
67
0
    if (ComputedStyleContainsFont(extraContext, pc, ufs, aFont)) {
68
0
      return true;
69
0
    }
70
0
  }
71
0
72
0
  return false;
73
0
}
74
75
static void
76
ScheduleReflow(nsIPresShell* aShell, nsIFrame* aFrame)
77
0
{
78
0
  nsIFrame* f = aFrame;
79
0
  if (f->IsFrameOfType(nsIFrame::eSVG) || nsSVGUtils::IsInSVGTextSubtree(f)) {
80
0
    // SVG frames (and the non-SVG descendants of an SVGTextFrame) need special
81
0
    // reflow handling.  We need to search upwards for the first displayed
82
0
    // nsSVGOuterSVGFrame or non-SVG frame, which is the frame we can call
83
0
    // FrameNeedsReflow on.  (This logic is based on
84
0
    // nsSVGUtils::ScheduleReflowSVG and
85
0
    // SVGTextFrame::ScheduleReflowSVGNonDisplayText.)
86
0
    if (f->GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
87
0
      while (f) {
88
0
        if (!(f->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
89
0
          if (NS_SUBTREE_DIRTY(f)) {
90
0
            // This is a displayed frame, so if it is already dirty, we
91
0
            // will be reflowed soon anyway.  No need to call
92
0
            // FrameNeedsReflow again, then.
93
0
            return;
94
0
          }
95
0
          if (f->GetStateBits() & NS_STATE_IS_OUTER_SVG ||
96
0
              !(f->IsFrameOfType(nsIFrame::eSVG) ||
97
0
                nsSVGUtils::IsInSVGTextSubtree(f))) {
98
0
            break;
99
0
          }
100
0
          f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
101
0
        }
102
0
        f = f->GetParent();
103
0
      }
104
0
      MOZ_ASSERT(f, "should have found an ancestor frame to reflow");
105
0
    }
106
0
  }
107
0
108
0
  aShell->FrameNeedsReflow(f, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
109
0
}
110
111
/* static */ void
112
nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
113
                                        const gfxUserFontEntry* aFont)
114
0
{
115
0
  AutoTArray<nsIFrame*, 4> subtrees;
116
0
  subtrees.AppendElement(aSubtreeRoot);
117
0
118
0
  nsIPresShell* ps = aSubtreeRoot->PresShell();
119
0
120
0
  // check descendants, iterating over subtrees that may include
121
0
  // additional subtrees associated with placeholders
122
0
  do {
123
0
    nsIFrame* subtreeRoot = subtrees.PopLastElement();
124
0
125
0
    // Check all descendants to see if they use the font
126
0
    AutoTArray<nsIFrame*, 32> stack;
127
0
    stack.AppendElement(subtreeRoot);
128
0
129
0
    do {
130
0
      nsIFrame* f = stack.PopLastElement();
131
0
132
0
      // if this frame uses the font, mark its descendants dirty
133
0
      // and skip checking its children
134
0
      if (FrameUsesFont(f, aFont)) {
135
0
        ScheduleReflow(ps, f);
136
0
      } else {
137
0
        if (f->IsPlaceholderFrame()) {
138
0
          nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
139
0
          if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
140
0
            // We have another distinct subtree we need to mark.
141
0
            subtrees.AppendElement(oof);
142
0
          }
143
0
        }
144
0
145
0
        nsIFrame::ChildListIterator lists(f);
146
0
        for (; !lists.IsDone(); lists.Next()) {
147
0
          nsFrameList::Enumerator childFrames(lists.CurrentList());
148
0
          for (; !childFrames.AtEnd(); childFrames.Next()) {
149
0
            nsIFrame* kid = childFrames.get();
150
0
            stack.AppendElement(kid);
151
0
          }
152
0
        }
153
0
      }
154
0
    } while (!stack.IsEmpty());
155
0
  } while (!subtrees.IsEmpty());
156
0
}