~mir-team/mir/in-process-egl+input-conglomeration

« back to all changes in this revision

Viewing changes to 3rd_party/android-input/android/frameworks/native/libs/utils/BufferedTextOutput.cpp

Merged trunk and fixed issues

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2006 The Android Open Source Project
3
 
 *
4
 
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 
 * you may not use this file except in compliance with the License.
6
 
 * You may obtain a copy of the License at
7
 
 *
8
 
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 
 *
10
 
 * Unless required by applicable law or agreed to in writing, software
11
 
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 
 * See the License for the specific language governing permissions and
14
 
 * limitations under the License.
15
 
 */
16
 
 
17
 
#include <utils/BufferedTextOutput.h>
18
 
 
19
 
#include <utils/Atomic.h>
20
 
#include <utils/Debug.h>
21
 
#include <utils/Log.h>
22
 
#include <utils/RefBase.h>
23
 
#include <utils/Vector.h>
24
 
#include <cutils/threads.h>
25
 
 
26
 
#include <private/utils/Static.h>
27
 
 
28
 
#include <stdio.h>
29
 
#include <stdlib.h>
30
 
 
31
 
// ---------------------------------------------------------------------------
32
 
 
33
 
namespace android {
34
 
 
35
 
struct BufferedTextOutput::BufferState : public RefBase
36
 
{
37
 
    BufferState(int32_t _seq)
38
 
        : seq(_seq)
39
 
        , buffer(NULL)
40
 
        , bufferPos(0)
41
 
        , bufferSize(0)
42
 
        , atFront(true)
43
 
        , indent(0)
44
 
        , bundle(0) {
45
 
    }
46
 
    ~BufferState() {
47
 
        free(buffer);
48
 
    }
49
 
    
50
 
    status_t append(const char* txt, size_t len) {
51
 
        if ((len+bufferPos) > bufferSize) {
52
 
            void* b = realloc(buffer, ((len+bufferPos)*3)/2);
53
 
            if (!b) return NO_MEMORY;
54
 
            buffer = (char*)b;
55
 
        }
56
 
        memcpy(buffer+bufferPos, txt, len);
57
 
        bufferPos += len;
58
 
        return NO_ERROR;
59
 
    }
60
 
    
61
 
    void restart() {
62
 
        bufferPos = 0;
63
 
        atFront = true;
64
 
        if (bufferSize > 256) {
65
 
            void* b = realloc(buffer, 256);
66
 
            if (b) {
67
 
                buffer = (char*)b;
68
 
                bufferSize = 256;
69
 
            }
70
 
        }
71
 
    }
72
 
    
73
 
    const int32_t seq;
74
 
    char* buffer;
75
 
    size_t bufferPos;
76
 
    size_t bufferSize;
77
 
    bool atFront;
78
 
    int32_t indent;
79
 
    int32_t bundle;
80
 
};
81
 
 
82
 
struct BufferedTextOutput::ThreadState
83
 
{
84
 
    Vector<sp<BufferedTextOutput::BufferState> > states;
85
 
};
86
 
 
87
 
static mutex_t          gMutex;
88
 
 
89
 
static thread_store_t   tls;
90
 
 
91
 
BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
92
 
{
93
 
    ThreadState*  ts = (ThreadState*) thread_store_get( &tls );
94
 
    if (ts) return ts;
95
 
    ts = new ThreadState;
96
 
    thread_store_set( &tls, ts, threadDestructor );
97
 
    return ts;
98
 
}
99
 
 
100
 
void BufferedTextOutput::threadDestructor(void *st)
101
 
{
102
 
    delete ((ThreadState*)st);
103
 
}
104
 
 
105
 
static volatile int32_t gSequence = 0;
106
 
 
107
 
static volatile int32_t gFreeBufferIndex = -1;
108
 
 
109
 
static int32_t allocBufferIndex()
110
 
{
111
 
    int32_t res = -1;
112
 
    
113
 
    mutex_lock(&gMutex);
114
 
    
115
 
    if (gFreeBufferIndex >= 0) {
116
 
        res = gFreeBufferIndex;
117
 
        gFreeBufferIndex = gTextBuffers[res];
118
 
        gTextBuffers.editItemAt(res) = -1;
119
 
 
120
 
    } else {
121
 
        res = gTextBuffers.size();
122
 
        gTextBuffers.add(-1);
123
 
    }
124
 
 
125
 
    mutex_unlock(&gMutex);
126
 
    
127
 
    return res;
128
 
}
129
 
 
130
 
static void freeBufferIndex(int32_t idx)
131
 
{
132
 
    mutex_lock(&gMutex);
133
 
    gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
134
 
    gFreeBufferIndex = idx;
135
 
    mutex_unlock(&gMutex);
136
 
}
137
 
 
138
 
// ---------------------------------------------------------------------------
139
 
 
140
 
BufferedTextOutput::BufferedTextOutput(uint32_t flags)
141
 
    : mFlags(flags)
142
 
    , mSeq(android_atomic_inc(&gSequence))
143
 
    , mIndex(allocBufferIndex())
144
 
{
145
 
    mGlobalState = new BufferState(mSeq);
146
 
    if (mGlobalState) mGlobalState->incStrong(this);
147
 
}
148
 
    
149
 
BufferedTextOutput::~BufferedTextOutput()
150
 
{
151
 
    if (mGlobalState) mGlobalState->decStrong(this);
152
 
    freeBufferIndex(mIndex);
153
 
}
154
 
 
155
 
status_t BufferedTextOutput::print(const char* txt, size_t len)
156
 
{
157
 
    //printf("BufferedTextOutput: printing %d\n", len);
158
 
    
159
 
    AutoMutex _l(mLock);
160
 
    BufferState* b = getBuffer();
161
 
    
162
 
    const char* const end = txt+len;
163
 
    
164
 
    status_t err;
165
 
 
166
 
    while (txt < end) {
167
 
        // Find the next line.
168
 
        const char* first = txt;
169
 
        while (txt < end && *txt != '\n') txt++;
170
 
        
171
 
        // Include this and all following empty lines.
172
 
        while (txt < end && *txt == '\n') txt++;
173
 
        
174
 
        // Special cases for first data on a line.
175
 
        if (b->atFront) {
176
 
            if (b->indent > 0) {
177
 
                // If this is the start of a line, add the indent.
178
 
                const char* prefix = stringForIndent(b->indent);
179
 
                err = b->append(prefix, strlen(prefix));
180
 
                if (err != NO_ERROR) return err;
181
 
                
182
 
            } else if (*(txt-1) == '\n' && !b->bundle) {
183
 
                // Fast path: if we are not indenting or bundling, and
184
 
                // have been given one or more complete lines, just write
185
 
                // them out without going through the buffer.
186
 
                
187
 
                // Slurp up all of the lines.
188
 
                const char* lastLine = txt+1;
189
 
                while (txt < end) {
190
 
                    if (*txt++ == '\n') lastLine = txt;
191
 
                }
192
 
                struct iovec vec;
193
 
                vec.iov_base = (void*)first;
194
 
                vec.iov_len = lastLine-first;
195
 
                //printf("Writing %d bytes of data!\n", vec.iov_len);
196
 
                writeLines(vec, 1);
197
 
                txt = lastLine;
198
 
                continue;
199
 
            }
200
 
        }
201
 
        
202
 
        // Append the new text to the buffer.
203
 
        err = b->append(first, txt-first);
204
 
        if (err != NO_ERROR) return err;
205
 
        b->atFront = *(txt-1) == '\n';
206
 
        
207
 
        // If we have finished a line and are not bundling, write
208
 
        // it out.
209
 
        //printf("Buffer is now %d bytes\n", b->bufferPos);
210
 
        if (b->atFront && !b->bundle) {
211
 
            struct iovec vec;
212
 
            vec.iov_base = b->buffer;
213
 
            vec.iov_len = b->bufferPos;
214
 
            //printf("Writing %d bytes of data!\n", vec.iov_len);
215
 
            writeLines(vec, 1);
216
 
            b->restart();
217
 
        }
218
 
    }
219
 
    
220
 
    return NO_ERROR;
221
 
}
222
 
 
223
 
void BufferedTextOutput::moveIndent(int delta)
224
 
{
225
 
    AutoMutex _l(mLock);
226
 
    BufferState* b = getBuffer();
227
 
    b->indent += delta;
228
 
    if (b->indent < 0) b->indent = 0;
229
 
}
230
 
 
231
 
void BufferedTextOutput::pushBundle()
232
 
{
233
 
    AutoMutex _l(mLock);
234
 
    BufferState* b = getBuffer();
235
 
    b->bundle++;
236
 
}
237
 
 
238
 
void BufferedTextOutput::popBundle()
239
 
{
240
 
    AutoMutex _l(mLock);
241
 
    BufferState* b = getBuffer();
242
 
    b->bundle--;
243
 
    LOG_FATAL_IF(b->bundle < 0,
244
 
        "TextOutput::popBundle() called more times than pushBundle()");
245
 
    if (b->bundle < 0) b->bundle = 0;
246
 
    
247
 
    if (b->bundle == 0) {
248
 
        // Last bundle, write out data if it is complete.  If it is not
249
 
        // complete, don't write until the last line is done... this may
250
 
        // or may not be the write thing to do, but it's the easiest.
251
 
        if (b->bufferPos > 0 && b->atFront) {
252
 
            struct iovec vec;
253
 
            vec.iov_base = b->buffer;
254
 
            vec.iov_len = b->bufferPos;
255
 
            writeLines(vec, 1);
256
 
            b->restart();
257
 
        }
258
 
    }
259
 
}
260
 
 
261
 
BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
262
 
{
263
 
    if ((mFlags&MULTITHREADED) != 0) {
264
 
        ThreadState* ts = getThreadState();
265
 
        if (ts) {
266
 
            while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL);
267
 
            BufferState* bs = ts->states[mIndex].get();
268
 
            if (bs != NULL && bs->seq == mSeq) return bs;
269
 
            
270
 
            ts->states.editItemAt(mIndex) = new BufferState(mIndex);
271
 
            bs = ts->states[mIndex].get();
272
 
            if (bs != NULL) return bs;
273
 
        }
274
 
    }
275
 
    
276
 
    return mGlobalState;
277
 
}
278
 
 
279
 
}; // namespace android