~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpcom/ds/nsTimelineService.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 * Alternatively, the contents of this file may be used under the terms of
 
25
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 
26
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
27
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
28
 * of those above. If you wish to allow use of your version of this file only
 
29
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
30
 * use your version of this file under the terms of the NPL, indicate your
 
31
 * decision by deleting the provisions above and replace them with the notice
 
32
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
33
 * the provisions above, a recipient may use your version of this file under
 
34
 * the terms of any one of the NPL, the GPL or the LGPL.
 
35
 *
 
36
 * ***** END LICENSE BLOCK ***** */
 
37
 
 
38
#include "nsTimelineService.h"
 
39
#include "prlong.h"
 
40
#include "prprf.h"
 
41
#include "prenv.h"
 
42
#include "plhash.h"
 
43
#include "prlock.h"
 
44
#include "prinit.h"
 
45
#include "prinrval.h"
 
46
#include "prthread.h"
 
47
 
 
48
#ifdef MOZ_TIMELINE
 
49
 
 
50
#define MAXINDENT 20
 
51
 
 
52
#ifdef XP_MAC
 
53
static PRIntervalTime initInterval = 0;
 
54
#endif
 
55
 
 
56
static PRFileDesc *timelineFD = PR_STDERR;
 
57
static PRBool gTimelineDisabled = PR_TRUE;
 
58
 
 
59
// Notes about threading:
 
60
// We avoid locks as we always use thread-local-storage.
 
61
// This means every other thread has its own private copy of
 
62
// data, and this thread can't re-enter (as our implemenation
 
63
// doesn't call back out anywhere).  Thus, we can avoid locks!
 
64
// TLS index
 
65
static const PRUintn BAD_TLS_INDEX = (PRUintn) -1;
 
66
static PRUintn gTLSIndex = BAD_TLS_INDEX;
 
67
 
 
68
class TimelineThreadData {
 
69
public:
 
70
    TimelineThreadData() : initTime(0), indent(0),
 
71
                           disabled(PR_TRUE), timers(nsnull) {}
 
72
    ~TimelineThreadData() {if (timers) PL_HashTableDestroy(timers);}
 
73
    PRTime initTime;
 
74
    PRHashTable *timers;
 
75
    int indent;
 
76
    PRBool disabled;
 
77
};
 
78
 
 
79
/* Implementation file */
 
80
NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimelineService, nsITimelineService)
 
81
 
 
82
static PRTime Now(void);
 
83
 
 
84
/*
 
85
 * Timer structure stored in a hash table to keep track of named
 
86
 * timers.
 
87
 */
 
88
class nsTimelineServiceTimer {
 
89
  public:
 
90
    nsTimelineServiceTimer();
 
91
    ~nsTimelineServiceTimer();
 
92
    void start();
 
93
    
 
94
    /*
 
95
     * Caller passes in "now" rather than having us calculate it so
 
96
     * that we can avoid including timer overhead in the time being
 
97
     * measured.
 
98
     */
 
99
    void stop(PRTime now);
 
100
    void reset();
 
101
    PRTime getAccum();
 
102
    PRTime getAccum(PRTime now);
 
103
 
 
104
  private:
 
105
    PRTime mAccum;
 
106
    PRTime mStart;
 
107
    PRInt32 mRunning;
 
108
    PRThread *mOwnerThread; // only used for asserts - could be #if MOZ_DEBUG
 
109
};
 
110
 
 
111
#define TIMER_CHECK_OWNER() \
 
112
    NS_ABORT_IF_FALSE(PR_GetCurrentThread() == mOwnerThread, \
 
113
                      "Timer used by non-owning thread")
 
114
 
 
115
 
 
116
nsTimelineServiceTimer::nsTimelineServiceTimer()
 
117
: mAccum(LL_ZERO), mStart(LL_ZERO), mRunning(0),
 
118
  mOwnerThread(PR_GetCurrentThread())
 
119
{
 
120
}
 
121
 
 
122
nsTimelineServiceTimer::~nsTimelineServiceTimer()
 
123
{
 
124
}
 
125
 
 
126
void nsTimelineServiceTimer::start()
 
127
{
 
128
    TIMER_CHECK_OWNER();
 
129
    if (!mRunning) {
 
130
        mStart = Now();
 
131
    }
 
132
    mRunning++;
 
133
}
 
134
 
 
135
void nsTimelineServiceTimer::stop(PRTime now)
 
136
{
 
137
    TIMER_CHECK_OWNER();
 
138
    mRunning--;
 
139
    if (mRunning == 0) {
 
140
        PRTime delta, accum;
 
141
        LL_SUB(delta, now, mStart);
 
142
        LL_ADD(accum, mAccum, delta);
 
143
        mAccum = accum;
 
144
    }
 
145
}
 
146
 
 
147
void nsTimelineServiceTimer::reset()
 
148
{
 
149
  TIMER_CHECK_OWNER();
 
150
  mStart = 0;
 
151
  mAccum = 0;
 
152
}
 
153
 
 
154
PRTime nsTimelineServiceTimer::getAccum()
 
155
{
 
156
    TIMER_CHECK_OWNER();
 
157
    PRTime accum;
 
158
 
 
159
    if (!mRunning) {
 
160
        accum = mAccum;
 
161
    } else {
 
162
        PRTime delta;
 
163
        LL_SUB(delta, Now(), mStart);
 
164
        LL_ADD(accum, mAccum, delta);
 
165
    }
 
166
    return accum;
 
167
}
 
168
 
 
169
PRTime nsTimelineServiceTimer::getAccum(PRTime now)
 
170
{
 
171
    TIMER_CHECK_OWNER();
 
172
    PRTime accum;
 
173
 
 
174
    if (!mRunning) {
 
175
        accum = mAccum;
 
176
    } else {
 
177
        PRTime delta;
 
178
        LL_SUB(delta, now, mStart);
 
179
        LL_ADD(accum, mAccum, delta);
 
180
    }
 
181
    return accum;
 
182
}
 
183
 
 
184
#ifdef XP_MAC
 
185
/*
 
186
 * PR_Now() on the Mac only gives us a resolution of seconds.  Using
 
187
 * PR_IntervalNow() gives us better resolution. with the drawback that 
 
188
 * the timeline is only good for about six hours.
 
189
 *
 
190
 * PR_IntervalNow() occasionally exhibits discontinuities on Windows,
 
191
 * so we only use it on the Mac.  Bleah!
 
192
 */
 
193
static PRTime Now(void)
 
194
{
 
195
    PRIntervalTime numTicks = PR_IntervalNow() - initInterval;
 
196
    PRTime now;
 
197
    LL_ADD(now, initTime, PR_IntervalToMilliseconds(numTicks) * 1000);
 
198
    return now;
 
199
}
 
200
#else
 
201
static PRTime Now(void)
 
202
{
 
203
    return PR_Now();
 
204
}
 
205
#endif
 
206
 
 
207
static TimelineThreadData *GetThisThreadData()
 
208
{
 
209
    NS_ABORT_IF_FALSE(gTLSIndex!=BAD_TLS_INDEX, "Our TLS not initialized");
 
210
    TimelineThreadData *new_data = nsnull;
 
211
    TimelineThreadData *data = (TimelineThreadData *)PR_GetThreadPrivate(gTLSIndex);
 
212
    if (data == nsnull) {
 
213
        // First request for this thread - allocate it.
 
214
        new_data = new TimelineThreadData();
 
215
        if (!new_data)
 
216
            goto done;
 
217
 
 
218
        // Fill it
 
219
        new_data->timers = PL_NewHashTable(100, PL_HashString, PL_CompareStrings,
 
220
                                 PL_CompareValues, NULL, NULL);
 
221
        if (new_data->timers==NULL)
 
222
            goto done;
 
223
        new_data->initTime = PR_Now();
 
224
        NS_WARN_IF_FALSE(!gTimelineDisabled,
 
225
                         "Why are we creating new state when disabled?");
 
226
        new_data->disabled = PR_FALSE;
 
227
        data = new_data;
 
228
        new_data = nsnull;
 
229
        PR_SetThreadPrivate(gTLSIndex, data);
 
230
    }
 
231
done:
 
232
    if (new_data) // eeek - error during creation!
 
233
        delete new_data;
 
234
    NS_WARN_IF_FALSE(data, "TimelineService could not get thread-local data");
 
235
    return data;
 
236
}
 
237
 
 
238
extern "C" {
 
239
  static void ThreadDestruct (void *data);
 
240
  static PRStatus TimelineInit(void);
 
241
};
 
242
 
 
243
void ThreadDestruct( void *data )
 
244
{
 
245
    if (data)
 
246
        delete (TimelineThreadData *)data;
 
247
}
 
248
 
 
249
/*
 
250
* PRCallOnceFN that initializes stuff for the timing service.
 
251
*/
 
252
static PRCallOnceType initonce;
 
253
 
 
254
PRStatus TimelineInit(void)
 
255
{
 
256
    char *timeStr;
 
257
    char *fileName;
 
258
    PRInt32 secs, msecs;
 
259
    PRFileDesc *fd;
 
260
    PRInt64 tmp1, tmp2;
 
261
 
 
262
    PRStatus status = PR_NewThreadPrivateIndex( &gTLSIndex, ThreadDestruct );
 
263
    NS_WARN_IF_FALSE(status==0, "TimelineService could not allocate TLS storage.");
 
264
 
 
265
    timeStr = PR_GetEnv("NS_TIMELINE_INIT_TIME");
 
266
#ifdef XP_MAC    
 
267
    initInterval = PR_IntervalNow();
 
268
#endif
 
269
    // NS_TIMELINE_INIT_TIME only makes sense for the main thread, so if it
 
270
    // exists, set it there.  If not, let normal thread management code take
 
271
    // care of setting the init time.
 
272
    if (timeStr != NULL && 2 == PR_sscanf(timeStr, "%d.%d", &secs, &msecs)) {
 
273
        PRTime &initTime = GetThisThreadData()->initTime;
 
274
        LL_MUL(tmp1, (PRInt64)secs, 1000000);
 
275
        LL_MUL(tmp2, (PRInt64)msecs, 1000);
 
276
        LL_ADD(initTime, tmp1, tmp2);
 
277
#ifdef XP_MAC
 
278
        initInterval -= PR_MicrosecondsToInterval(
 
279
            (PRUint32)(PR_Now() - initTime));
 
280
#endif
 
281
    }
 
282
    // Get the log file.
 
283
#ifdef XP_MAC
 
284
    fileName = "timeline.txt";
 
285
#else
 
286
    fileName = PR_GetEnv("NS_TIMELINE_LOG_FILE");
 
287
#endif
 
288
    if (fileName != NULL
 
289
        && (fd = PR_Open(fileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
 
290
                         0666)) != NULL) {
 
291
        timelineFD = fd;
 
292
        PR_fprintf(fd,
 
293
                   "NOTE: due to asynchrony, the indentation that you see does"
 
294
                   " not necessarily correspond to nesting in the code.\n\n");
 
295
    }
 
296
 
 
297
    // Runtime disable of timeline
 
298
    if (PR_GetEnv("NS_TIMELINE_ENABLE"))
 
299
        gTimelineDisabled = PR_FALSE;
 
300
    return PR_SUCCESS;
 
301
}
 
302
 
 
303
static void ParseTime(PRTime tm, PRInt32& secs, PRInt32& msecs)
 
304
{
 
305
    PRTime llsecs, llmsecs, tmp;
 
306
 
 
307
    LL_DIV(llsecs, tm, 1000000);
 
308
    LL_MOD(tmp, tm, 1000000);
 
309
    LL_DIV(llmsecs, tmp, 1000);
 
310
 
 
311
    LL_L2I(secs, llsecs);
 
312
    LL_L2I(msecs, llmsecs);
 
313
}
 
314
 
 
315
static char *Indent(char *buf)
 
316
{
 
317
    int &indent = GetThisThreadData()->indent;
 
318
    int amount = indent;
 
319
    if (amount > MAXINDENT) {
 
320
        amount = MAXINDENT;
 
321
    }
 
322
    if (amount < 0) {
 
323
        amount = 0;
 
324
        indent = 0;
 
325
        PR_Write(timelineFD, "indent underflow!\n", 18);
 
326
    }
 
327
    while (amount--) {
 
328
        *buf++ = ' ';
 
329
    }
 
330
    return buf;
 
331
}
 
332
 
 
333
static void PrintTime(PRTime tm, const char *text, va_list args)
 
334
{
 
335
    PRInt32 secs, msecs;
 
336
    char pbuf[550], *pc, tbuf[550];
 
337
 
 
338
    ParseTime(tm, secs, msecs);
 
339
 
 
340
    // snprintf/write rather than fprintf because we don't want
 
341
    // messages from multiple threads to garble one another.
 
342
    pc = Indent(pbuf);
 
343
    PR_vsnprintf(pc, sizeof pbuf - (pc - pbuf), text, args);
 
344
    PR_snprintf(tbuf, sizeof tbuf, "%05d.%03d (%08p): %s\n",
 
345
                secs, msecs, PR_GetCurrentThread(), pbuf);
 
346
    PR_Write(timelineFD, tbuf, strlen(tbuf));
 
347
}
 
348
 
 
349
/*
 
350
 * Make this public if we need it.
 
351
 */
 
352
static nsresult NS_TimelineMarkV(const char *text, va_list args)
 
353
{
 
354
    PRTime elapsed,tmp;
 
355
 
 
356
    PR_CallOnce(&initonce, TimelineInit);
 
357
 
 
358
    TimelineThreadData *thread = GetThisThreadData();
 
359
 
 
360
    tmp = Now();
 
361
    LL_SUB(elapsed, tmp, thread->initTime);
 
362
 
 
363
    PrintTime(elapsed, text, args);
 
364
 
 
365
    return NS_OK;
 
366
}
 
367
 
 
368
PR_IMPLEMENT(nsresult) NS_TimelineForceMark(const char *text, ...)
 
369
{
 
370
    va_list args;
 
371
    va_start(args, text);
 
372
    NS_TimelineMarkV(text, args);
 
373
 
 
374
    return NS_OK;
 
375
}
 
376
 
 
377
PR_IMPLEMENT(nsresult) NS_TimelineMark(const char *text, ...)
 
378
{
 
379
    va_list args;
 
380
    va_start(args, text);
 
381
 
 
382
    PR_CallOnce(&initonce, TimelineInit);
 
383
 
 
384
    if (gTimelineDisabled)
 
385
        return NS_ERROR_NOT_AVAILABLE;
 
386
 
 
387
    TimelineThreadData *thread = GetThisThreadData();
 
388
 
 
389
    if (thread->disabled)
 
390
        return NS_ERROR_NOT_AVAILABLE;
 
391
 
 
392
    NS_TimelineMarkV(text, args);
 
393
 
 
394
    return NS_OK;
 
395
}
 
396
 
 
397
PR_IMPLEMENT(nsresult) NS_TimelineStartTimer(const char *timerName)
 
398
{
 
399
    PR_CallOnce(&initonce, TimelineInit);
 
400
 
 
401
    if (gTimelineDisabled)
 
402
        return NS_ERROR_NOT_AVAILABLE;
 
403
 
 
404
    TimelineThreadData *thread = GetThisThreadData();
 
405
 
 
406
    if (thread->timers == NULL)
 
407
        return NS_ERROR_FAILURE;
 
408
    if (thread->disabled)
 
409
        return NS_ERROR_NOT_AVAILABLE;
 
410
 
 
411
    nsTimelineServiceTimer *timer
 
412
        = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName);
 
413
    if (timer == NULL) {
 
414
        timer = new nsTimelineServiceTimer;
 
415
        if (!timer)
 
416
            return NS_ERROR_OUT_OF_MEMORY;
 
417
 
 
418
        PL_HashTableAdd(thread->timers, timerName, timer);
 
419
    }
 
420
    timer->start();
 
421
    return NS_OK;
 
422
}
 
423
 
 
424
PR_IMPLEMENT(nsresult) NS_TimelineStopTimer(const char *timerName)
 
425
{
 
426
    if (gTimelineDisabled)
 
427
        return NS_ERROR_NOT_AVAILABLE;
 
428
    /*
 
429
     * Strange-looking now/timer->stop() interaction is to avoid
 
430
     * including time spent in TLS and PL_HashTableLookup in the
 
431
     * timer.
 
432
     */
 
433
    PRTime now = Now();
 
434
 
 
435
    TimelineThreadData *thread = GetThisThreadData();
 
436
    if (thread->timers == NULL)
 
437
        return NS_ERROR_FAILURE;
 
438
    if (thread->disabled)
 
439
        return NS_ERROR_NOT_AVAILABLE;
 
440
    nsTimelineServiceTimer *timer
 
441
        = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName);
 
442
    if (timer == NULL) {
 
443
        return NS_ERROR_FAILURE;
 
444
    }
 
445
 
 
446
    timer->stop(now);
 
447
 
 
448
    return NS_OK;
 
449
}
 
450
 
 
451
PR_IMPLEMENT(nsresult) NS_TimelineMarkTimer(const char *timerName, const char *str)
 
452
{
 
453
    PR_CallOnce(&initonce, TimelineInit);
 
454
 
 
455
    if (gTimelineDisabled)
 
456
        return NS_ERROR_NOT_AVAILABLE;
 
457
 
 
458
    TimelineThreadData *thread = GetThisThreadData();
 
459
    if (thread->timers == NULL)
 
460
        return NS_ERROR_FAILURE;
 
461
    if (thread->disabled)
 
462
        return NS_ERROR_NOT_AVAILABLE;
 
463
    nsTimelineServiceTimer *timer
 
464
        = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName);
 
465
    if (timer == NULL) {
 
466
        return NS_ERROR_FAILURE;
 
467
    }
 
468
    PRTime accum = timer->getAccum();
 
469
 
 
470
    char buf[500];
 
471
    PRInt32 sec, msec;
 
472
    ParseTime(accum, sec, msec);
 
473
    if (!str)
 
474
        PR_snprintf(buf, sizeof buf, "%s total: %d.%03d",
 
475
                    timerName, sec, msec);
 
476
    else
 
477
        PR_snprintf(buf, sizeof buf, "%s total: %d.%03d (%s)",
 
478
                    timerName, sec, msec, str);
 
479
    NS_TimelineMark(buf);
 
480
 
 
481
    return NS_OK;
 
482
}
 
483
 
 
484
PR_IMPLEMENT(nsresult) NS_TimelineResetTimer(const char *timerName)
 
485
{
 
486
    if (gTimelineDisabled)
 
487
        return NS_ERROR_NOT_AVAILABLE;
 
488
 
 
489
    TimelineThreadData *thread = GetThisThreadData();
 
490
    if (thread->timers == NULL)
 
491
        return NS_ERROR_FAILURE;
 
492
    if (thread->disabled)
 
493
        return NS_ERROR_NOT_AVAILABLE;
 
494
    nsTimelineServiceTimer *timer
 
495
        = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName);
 
496
    if (timer == NULL) {
 
497
        return NS_ERROR_FAILURE;
 
498
    }
 
499
 
 
500
    timer->reset();
 
501
    return NS_OK;
 
502
}
 
503
 
 
504
PR_IMPLEMENT(nsresult) NS_TimelineIndent()
 
505
{
 
506
    if (gTimelineDisabled)
 
507
        return NS_ERROR_NOT_AVAILABLE;
 
508
 
 
509
    TimelineThreadData *thread = GetThisThreadData();
 
510
    if (thread->disabled)
 
511
        return NS_ERROR_NOT_AVAILABLE;
 
512
    thread->indent++;
 
513
    return NS_OK;
 
514
}
 
515
 
 
516
PR_IMPLEMENT(nsresult) NS_TimelineOutdent()
 
517
{
 
518
    if (gTimelineDisabled)
 
519
        return NS_ERROR_NOT_AVAILABLE;
 
520
 
 
521
    TimelineThreadData *thread = GetThisThreadData();
 
522
    if (thread->disabled)
 
523
        return NS_ERROR_NOT_AVAILABLE;
 
524
    thread->indent--;
 
525
    return NS_OK;
 
526
}
 
527
 
 
528
PR_IMPLEMENT(nsresult) NS_TimelineEnter(const char *text)
 
529
{
 
530
    nsresult rv = NS_TimelineMark("%s...", text);
 
531
    if (NS_FAILED(rv)) {
 
532
        return rv;
 
533
    }
 
534
    return NS_TimelineIndent();
 
535
}
 
536
 
 
537
PR_IMPLEMENT(nsresult) NS_TimelineLeave(const char *text)
 
538
{
 
539
    nsresult rv = NS_TimelineOutdent();
 
540
    if (NS_FAILED(rv)) {
 
541
        return rv;
 
542
    }
 
543
    return NS_TimelineMark("...%s", text);
 
544
}
 
545
 
 
546
nsTimelineService::nsTimelineService()
 
547
{
 
548
  /* member initializers and constructor code */
 
549
}
 
550
 
 
551
/* void mark (in string text); */
 
552
NS_IMETHODIMP nsTimelineService::Mark(const char *text)
 
553
{
 
554
    return NS_TimelineMark(text);
 
555
}
 
556
 
 
557
/* void startTimer (in string timerName); */
 
558
NS_IMETHODIMP nsTimelineService::StartTimer(const char *timerName)
 
559
{
 
560
    return NS_TimelineStartTimer(timerName);
 
561
}
 
562
 
 
563
/* void stopTimer (in string timerName); */
 
564
NS_IMETHODIMP nsTimelineService::StopTimer(const char *timerName)
 
565
{
 
566
    return NS_TimelineStopTimer(timerName);
 
567
}
 
568
 
 
569
/* void markTimer (in string timerName); */
 
570
NS_IMETHODIMP nsTimelineService::MarkTimer(const char *timerName)
 
571
{
 
572
    return NS_TimelineMarkTimer(timerName);
 
573
}
 
574
 
 
575
/* void markTimerWithComment(in string timerName, in string comment); */
 
576
NS_IMETHODIMP nsTimelineService::MarkTimerWithComment(const char *timerName, const char *comment)
 
577
{
 
578
    return NS_TimelineMarkTimer(timerName, comment);
 
579
}
 
580
 
 
581
/* void resetTimer (in string timerName); */
 
582
NS_IMETHODIMP nsTimelineService::ResetTimer(const char *timerName)
 
583
{
 
584
    return NS_TimelineResetTimer(timerName);
 
585
}
 
586
 
 
587
/* void indent (); */
 
588
NS_IMETHODIMP nsTimelineService::Indent()
 
589
{
 
590
    return NS_TimelineIndent();
 
591
}
 
592
 
 
593
/* void outdent (); */
 
594
NS_IMETHODIMP nsTimelineService::Outdent()
 
595
{
 
596
    return NS_TimelineOutdent();
 
597
}
 
598
 
 
599
/* void enter (in string text); */
 
600
NS_IMETHODIMP nsTimelineService::Enter(const char *text)
 
601
{
 
602
    return NS_TimelineEnter(text);
 
603
}
 
604
 
 
605
/* void leave (in string text); */
 
606
NS_IMETHODIMP nsTimelineService::Leave(const char *text)
 
607
{
 
608
    return NS_TimelineLeave(text);
 
609
}
 
610
 
 
611
#endif /* MOZ_TIMELINE */