Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/gfxFontInfoLoader.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "gfxFontInfoLoader.h"
7
#include "nsCRT.h"
8
#include "nsIObserverService.h"
9
#include "nsThreadUtils.h"              // for nsRunnable
10
#include "gfxPlatformFontList.h"
11
12
#ifdef XP_WIN
13
#include <windows.h>
14
#endif
15
16
using namespace mozilla;
17
using services::GetObserverService;
18
19
0
#define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
20
0
                               LogLevel::Debug, args)
21
0
#define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \
22
0
                                   gfxPlatform::GetLog(eGfxLog_fontinit), \
23
0
                                   LogLevel::Debug)
24
25
void
26
FontInfoData::Load()
27
0
{
28
0
    TimeStamp start = TimeStamp::Now();
29
0
30
0
    uint32_t i, n = mFontFamiliesToLoad.Length();
31
0
    mLoadStats.families = n;
32
0
    for (i = 0; i < n && !mCanceled; i++) {
33
0
        // font file memory mapping sometimes causes exceptions - bug 1100949
34
0
        MOZ_SEH_TRY {
35
0
            LoadFontFamilyData(mFontFamiliesToLoad[i]);
36
0
        } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
37
0
            gfxCriticalError() <<
38
0
                "Exception occurred reading font data for " <<
39
0
                mFontFamiliesToLoad[i].get();
40
0
        }
41
0
    }
42
0
43
0
    mLoadTime = TimeStamp::Now() - start;
44
0
}
45
46
class FontInfoLoadCompleteEvent : public Runnable {
47
0
    virtual ~FontInfoLoadCompleteEvent() {}
48
49
public:
50
    NS_INLINE_DECL_REFCOUNTING_INHERITED(FontInfoLoadCompleteEvent, Runnable)
51
52
    explicit FontInfoLoadCompleteEvent(FontInfoData* aFontInfo)
53
      : mozilla::Runnable("FontInfoLoadCompleteEvent")
54
      , mFontInfo(aFontInfo)
55
0
    {}
56
57
    NS_IMETHOD Run() override;
58
59
private:
60
    RefPtr<FontInfoData> mFontInfo;
61
};
62
63
class AsyncFontInfoLoader : public Runnable {
64
0
    virtual ~AsyncFontInfoLoader() {}
65
66
public:
67
    NS_INLINE_DECL_REFCOUNTING_INHERITED(AsyncFontInfoLoader, Runnable)
68
69
    explicit AsyncFontInfoLoader(FontInfoData* aFontInfo)
70
      : mozilla::Runnable("AsyncFontInfoLoader")
71
      , mFontInfo(aFontInfo)
72
0
    {
73
0
        mCompleteEvent = new FontInfoLoadCompleteEvent(aFontInfo);
74
0
    }
75
76
    NS_IMETHOD Run() override;
77
78
private:
79
    RefPtr<FontInfoData> mFontInfo;
80
    RefPtr<FontInfoLoadCompleteEvent> mCompleteEvent;
81
};
82
83
class ShutdownThreadEvent : public Runnable {
84
0
    virtual ~ShutdownThreadEvent() {}
85
86
public:
87
    NS_INLINE_DECL_REFCOUNTING_INHERITED(ShutdownThreadEvent, Runnable)
88
89
    explicit ShutdownThreadEvent(nsIThread* aThread)
90
      : mozilla::Runnable("ShutdownThreadEvent")
91
      , mThread(aThread)
92
0
    {
93
0
    }
94
0
    NS_IMETHOD Run() override {
95
0
        mThread->Shutdown();
96
0
        return NS_OK;
97
0
    }
98
99
private:
100
    nsCOMPtr<nsIThread> mThread;
101
};
102
103
// runs on main thread after async font info loading is done
104
nsresult
105
FontInfoLoadCompleteEvent::Run()
106
0
{
107
0
    gfxFontInfoLoader *loader =
108
0
        static_cast<gfxFontInfoLoader*>(gfxPlatformFontList::PlatformFontList());
109
0
110
0
    loader->FinalizeLoader(mFontInfo);
111
0
112
0
    return NS_OK;
113
0
}
114
115
// runs on separate thread
116
nsresult
117
AsyncFontInfoLoader::Run()
118
0
{
119
0
    // load platform-specific font info
120
0
    mFontInfo->Load();
121
0
122
0
    // post a completion event that transfer the data to the fontlist
123
0
    NS_DispatchToMainThread(mCompleteEvent);
124
0
125
0
    return NS_OK;
126
0
}
127
128
NS_IMPL_ISUPPORTS(gfxFontInfoLoader::ShutdownObserver, nsIObserver)
129
130
NS_IMETHODIMP
131
gfxFontInfoLoader::ShutdownObserver::Observe(nsISupports *aSubject,
132
                                             const char *aTopic,
133
                                             const char16_t *someData)
134
0
{
135
0
    if (!nsCRT::strcmp(aTopic, "quit-application")) {
136
0
        mLoader->CancelLoader();
137
0
    } else {
138
0
        MOZ_ASSERT_UNREACHABLE("unexpected notification topic");
139
0
    }
140
0
    return NS_OK;
141
0
}
142
143
void
144
gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
145
0
{
146
0
    mInterval = aInterval;
147
0
148
0
    NS_ASSERTION(!mFontInfo,
149
0
                 "fontinfo should be null when starting font loader");
150
0
151
0
    // sanity check
152
0
    if (mState != stateInitial &&
153
0
        mState != stateTimerOff &&
154
0
        mState != stateTimerOnDelay) {
155
0
        CancelLoader();
156
0
    }
157
0
158
0
    // set up timer
159
0
    if (!mTimer) {
160
0
        mTimer = NS_NewTimer();
161
0
        if (!mTimer) {
162
0
            NS_WARNING("Failure to create font info loader timer");
163
0
            return;
164
0
        }
165
0
    }
166
0
167
0
    AddShutdownObserver();
168
0
169
0
    // delay? ==> start async thread after a delay
170
0
    if (aDelay) {
171
0
        mState = stateTimerOnDelay;
172
0
        mTimer->InitWithNamedFuncCallback(DelayedStartCallback,
173
0
                                          this,
174
0
                                          aDelay,
175
0
                                          nsITimer::TYPE_ONE_SHOT,
176
0
                                          "gfxFontInfoLoader::StartLoader");
177
0
        return;
178
0
    }
179
0
180
0
    mFontInfo = CreateFontInfoData();
181
0
182
0
    // initialize
183
0
    InitLoader();
184
0
185
0
    // start async load
186
0
    nsresult rv = NS_NewNamedThread("Font Loader",
187
0
                                    getter_AddRefs(mFontLoaderThread),
188
0
                                    nullptr);
189
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
190
0
        return;
191
0
    }
192
0
    mState = stateAsyncLoad;
193
0
194
0
    nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
195
0
196
0
    mFontLoaderThread->Dispatch(loadEvent.forget(), NS_DISPATCH_NORMAL);
197
0
198
0
    if (LOG_FONTINIT_ENABLED()) {
199
0
        LOG_FONTINIT(("(fontinit) fontloader started (fontinfo: %p)\n",
200
0
                      mFontInfo.get()));
201
0
    }
202
0
}
203
204
void
205
gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo)
206
0
{
207
0
    // Avoid loading data if loader has already been canceled.
208
0
    // This should mean that CancelLoader() ran and the Load
209
0
    // thread has already Shutdown(), and likely before processing
210
0
    // the Shutdown event it handled the load event and sent back
211
0
    // our Completion event, thus we end up here.
212
0
    if (mState != stateAsyncLoad || mFontInfo != aFontInfo) {
213
0
        return;
214
0
    }
215
0
216
0
    mLoadTime = mFontInfo->mLoadTime;
217
0
218
0
    // try to load all font data immediately
219
0
    if (LoadFontInfo()) {
220
0
        CancelLoader();
221
0
        return;
222
0
    }
223
0
224
0
    // not all work completed ==> run load on interval
225
0
    mState = stateTimerOnInterval;
226
0
    mTimer->InitWithNamedFuncCallback(LoadFontInfoCallback,
227
0
                                      this,
228
0
                                      mInterval,
229
0
                                      nsITimer::TYPE_REPEATING_SLACK,
230
0
                                      "gfxFontInfoLoader::FinalizeLoader");
231
0
}
232
233
void
234
gfxFontInfoLoader::CancelLoader()
235
0
{
236
0
    if (mState == stateInitial) {
237
0
        return;
238
0
    }
239
0
    mState = stateTimerOff;
240
0
    if (mTimer) {
241
0
        mTimer->Cancel();
242
0
        mTimer = nullptr;
243
0
    }
244
0
    if (mFontInfo) // null during any initial delay
245
0
        mFontInfo->mCanceled = true;
246
0
    if (mFontLoaderThread) {
247
0
        NS_DispatchToMainThread(new ShutdownThreadEvent(mFontLoaderThread));
248
0
        mFontLoaderThread = nullptr;
249
0
    }
250
0
    RemoveShutdownObserver();
251
0
    CleanupLoader();
252
0
}
253
254
void
255
gfxFontInfoLoader::LoadFontInfoTimerFire()
256
0
{
257
0
    if (mState == stateTimerOnDelay) {
258
0
        mState = stateTimerOnInterval;
259
0
        mTimer->SetDelay(mInterval);
260
0
    }
261
0
262
0
    bool done = LoadFontInfo();
263
0
    if (done) {
264
0
        CancelLoader();
265
0
    }
266
0
}
267
268
gfxFontInfoLoader::~gfxFontInfoLoader()
269
0
{
270
0
    RemoveShutdownObserver();
271
0
    MOZ_COUNT_DTOR(gfxFontInfoLoader);
272
0
}
273
274
void
275
gfxFontInfoLoader::AddShutdownObserver()
276
0
{
277
0
    if (mObserver) {
278
0
        return;
279
0
    }
280
0
281
0
    nsCOMPtr<nsIObserverService> obs = GetObserverService();
282
0
    if (obs) {
283
0
        mObserver = new ShutdownObserver(this);
284
0
        obs->AddObserver(mObserver, "quit-application", false);
285
0
    }
286
0
}
287
288
void
289
gfxFontInfoLoader::RemoveShutdownObserver()
290
0
{
291
0
    if (mObserver) {
292
0
        nsCOMPtr<nsIObserverService> obs = GetObserverService();
293
0
        if (obs) {
294
0
            obs->RemoveObserver(mObserver, "quit-application");
295
0
            mObserver = nullptr;
296
0
        }
297
0
    }
298
0
}