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