|
1 /* |
|
2 * Copyright (c) 1999 - 2004 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 package javax.microedition.lcdui; |
|
19 |
|
20 import com.nokia.mj.impl.rt.legacy.NativeError; |
|
21 |
|
22 /** |
|
23 * Buffer for LCDUI/LCDGR commands. |
|
24 * |
|
25 * Commands placed in buffer consist of a header followed by |
|
26 * optional data. The header is always a 32bit integer in |
|
27 * one of the following two forms. |
|
28 * |
|
29 * An activation header has the ACTIVATE marker (the top bit) set |
|
30 * and contains a component handle in the lower 30 bits. |
|
31 * |
|
32 * A command header has the top four bits clear, and the remaining |
|
33 * 28 bits are divided as follows: |
|
34 * |
|
35 * bits 0-15 contain the command size including the header as the |
|
36 * number of integers (or words) in the buffer occupied by the |
|
37 * commadn. |
|
38 * |
|
39 * bits 16-27 contain an unsigned integer opcode. |
|
40 * |
|
41 */ |
|
42 final class Buffer |
|
43 { |
|
44 private static final int BUFFER_SIZE = 1024; // 4KB buffer |
|
45 private static final int CHAR_BUFFER_SIZE = 128; |
|
46 |
|
47 public static final int NOP = 0; |
|
48 public static final int ACTIVATE = (1<<31); |
|
49 public static final int OP_MASK = 0x0FFF; |
|
50 |
|
51 /** |
|
52 * JavaUnhand<> mangled pointer to CMIDBuffer |
|
53 */ |
|
54 private int iHandle; |
|
55 |
|
56 /** |
|
57 * Java side buffer and write pointer. |
|
58 */ |
|
59 private int[] iBuffer; |
|
60 private int iCount; |
|
61 |
|
62 /** |
|
63 * Tracks current buffer processor to minimize ACTIVATE commands. |
|
64 */ |
|
65 private int iCurrent; |
|
66 // index of activation size |
|
67 private int iStart; // index of activation size |
|
68 private char[] iCharBuffer; |
|
69 |
|
70 |
|
71 /** |
|
72 * |
|
73 */ |
|
74 Buffer(Toolkit aToolkit) |
|
75 { |
|
76 iBuffer = new int[BUFFER_SIZE]; |
|
77 iCharBuffer = new char[CHAR_BUFFER_SIZE]; |
|
78 iCount = 0; |
|
79 iCurrent = -1; |
|
80 iStart = 0; |
|
81 iHandle = NativeError.check(_open(aToolkit.getEventServerHandle())); |
|
82 } |
|
83 |
|
84 /** |
|
85 * Sync any pending commands and then shutdown buffer processing |
|
86 */ |
|
87 synchronized void close() |
|
88 { |
|
89 if (iHandle <= 0) |
|
90 { |
|
91 return; |
|
92 } |
|
93 sync(); |
|
94 _close(iHandle); |
|
95 iHandle = 0; |
|
96 } |
|
97 |
|
98 /** |
|
99 * |
|
100 */ |
|
101 int getHandle() |
|
102 { |
|
103 if (iHandle <= 0) |
|
104 { |
|
105 throw new RuntimeException("Buffer closed"); |
|
106 } |
|
107 return iHandle; |
|
108 } |
|
109 |
|
110 |
|
111 /** |
|
112 * writes a command with no parameters into the buffer. |
|
113 */ |
|
114 final void write(int aHandle, int aCommand) |
|
115 { |
|
116 if (iHandle <= 0) |
|
117 { |
|
118 throw new RuntimeException("Buffer closed"); |
|
119 } |
|
120 |
|
121 if (aHandle != iCurrent) |
|
122 { |
|
123 deactivate(); // remove existing target |
|
124 activate(aHandle); // set new target - this may cause a flush. |
|
125 } |
|
126 |
|
127 // size = 1; |
|
128 final int opc = (aCommand << 16) | 1; |
|
129 ensureSpace(1); |
|
130 |
|
131 iBuffer[iCount++] = opc; |
|
132 } |
|
133 |
|
134 /** |
|
135 * |
|
136 */ |
|
137 final void write(int aHandle, int aCommand, int aArg) |
|
138 { |
|
139 if (iHandle <= 0) |
|
140 { |
|
141 throw new RuntimeException("Buffer closed"); |
|
142 } |
|
143 |
|
144 if (aHandle != iCurrent) |
|
145 { |
|
146 deactivate(); // remove existing target |
|
147 activate(aHandle); // set new target - this may cause a flush. |
|
148 } |
|
149 |
|
150 // size = 2; |
|
151 final int opc = (aCommand << 16) | 2; |
|
152 ensureSpace(2); |
|
153 |
|
154 iBuffer[iCount++] = opc; |
|
155 iBuffer[iCount++] = aArg; |
|
156 } |
|
157 |
|
158 /** |
|
159 * |
|
160 */ |
|
161 final void write(int aHandle, int aCommand, int aArg1, int aArg2) |
|
162 { |
|
163 if (iHandle <= 0) |
|
164 { |
|
165 throw new RuntimeException("Buffer closed"); |
|
166 } |
|
167 |
|
168 if (aHandle != iCurrent) |
|
169 { |
|
170 deactivate(); // remove existing target |
|
171 activate(aHandle); // set new target - this may cause a flush. |
|
172 } |
|
173 |
|
174 // size = 3; |
|
175 final int opc = (aCommand << 16) | 3; |
|
176 ensureSpace(3); |
|
177 |
|
178 final int[] buffer = iBuffer; |
|
179 int count = iCount; |
|
180 buffer[count++] = opc; |
|
181 buffer[count++] = aArg1; |
|
182 buffer[count++] = aArg2; |
|
183 iCount = count; |
|
184 } |
|
185 |
|
186 /** |
|
187 * |
|
188 */ |
|
189 final void write(int aHandle, int aCommand, int aArg1, int aArg2, int aArg3) |
|
190 { |
|
191 if (iHandle <= 0) |
|
192 { |
|
193 throw new RuntimeException("Buffer closed"); |
|
194 } |
|
195 |
|
196 if (aHandle != iCurrent) |
|
197 { |
|
198 deactivate(); // remove existing target |
|
199 activate(aHandle); // set new target - this may cause a flush. |
|
200 } |
|
201 |
|
202 // size = 4; |
|
203 final int opc = (aCommand << 16) | 4; |
|
204 ensureSpace(4); |
|
205 |
|
206 final int[] buffer = iBuffer; |
|
207 int count = iCount; |
|
208 buffer[count++] = opc; |
|
209 buffer[count++] = aArg1; |
|
210 buffer[count++] = aArg2; |
|
211 buffer[count++] = aArg3; |
|
212 iCount = count; |
|
213 } |
|
214 |
|
215 /** |
|
216 * |
|
217 */ |
|
218 final void write(int aHandle, int aCommand, int aArg1, int aArg2, |
|
219 int aArg3, int aArg4) |
|
220 { |
|
221 if (iHandle <= 0) |
|
222 { |
|
223 throw new RuntimeException("Buffer closed"); |
|
224 } |
|
225 |
|
226 if (aHandle != iCurrent) |
|
227 { |
|
228 deactivate(); // remove existing target |
|
229 activate(aHandle); // set new target - this may cause a flush. |
|
230 } |
|
231 |
|
232 // size = 5; |
|
233 final int opc = (aCommand << 16) | 5; |
|
234 ensureSpace(5); |
|
235 |
|
236 final int[] buffer = iBuffer; |
|
237 int count = iCount; |
|
238 buffer[count++] = opc; |
|
239 buffer[count++] = aArg1; |
|
240 buffer[count++] = aArg2; |
|
241 buffer[count++] = aArg3; |
|
242 buffer[count++] = aArg4; |
|
243 iCount = count; |
|
244 } |
|
245 |
|
246 /** |
|
247 * |
|
248 */ |
|
249 final void write(int aHandle, int aCommand, int aArg1, int aArg2, |
|
250 int aArg3, int aArg4, int aArg5) |
|
251 { |
|
252 if (iHandle <= 0) |
|
253 { |
|
254 throw new RuntimeException("Buffer closed"); |
|
255 } |
|
256 |
|
257 if (aHandle != iCurrent) |
|
258 { |
|
259 deactivate(); // remove existing target |
|
260 activate(aHandle); // set new target - this may cause a flush. |
|
261 } |
|
262 |
|
263 // size = 6; |
|
264 final int opc = (aCommand << 16) | 6; |
|
265 ensureSpace(6); |
|
266 |
|
267 final int[] buffer = iBuffer; |
|
268 int count = iCount; |
|
269 buffer[count++] = opc; |
|
270 buffer[count++] = aArg1; |
|
271 buffer[count++] = aArg2; |
|
272 buffer[count++] = aArg3; |
|
273 buffer[count++] = aArg4; |
|
274 buffer[count++] = aArg5; |
|
275 iCount = count; |
|
276 } |
|
277 |
|
278 /** |
|
279 * |
|
280 */ |
|
281 final void write(int aHandle, int aCommand, int aArg1, int aArg2, |
|
282 int aArg3, int aArg4, int aArg5, int aArg6) |
|
283 { |
|
284 if (iHandle <= 0) |
|
285 { |
|
286 throw new RuntimeException("Buffer closed"); |
|
287 } |
|
288 |
|
289 if (aHandle != iCurrent) |
|
290 { |
|
291 deactivate(); // remove existing target |
|
292 activate(aHandle); // set new target - this may cause a flush. |
|
293 } |
|
294 |
|
295 // size = 7; |
|
296 final int opc = (aCommand << 16) | 7; |
|
297 ensureSpace(7); |
|
298 |
|
299 final int[] buffer = iBuffer; |
|
300 int count = iCount; |
|
301 buffer[count++] = opc; |
|
302 buffer[count++] = aArg1; |
|
303 buffer[count++] = aArg2; |
|
304 buffer[count++] = aArg3; |
|
305 buffer[count++] = aArg4; |
|
306 buffer[count++] = aArg5; |
|
307 buffer[count++] = aArg6; |
|
308 iCount = count; |
|
309 } |
|
310 |
|
311 /** |
|
312 * |
|
313 */ |
|
314 final void write(int aHandle, int aCommand, int aArg1, int aArg2, |
|
315 int aArg3, int aArg4, int aArg5, int aArg6, int aArg7) |
|
316 { |
|
317 if (iHandle <= 0) |
|
318 { |
|
319 throw new RuntimeException("Buffer closed"); |
|
320 } |
|
321 |
|
322 if (aHandle != iCurrent) |
|
323 { |
|
324 deactivate(); // remove existing target |
|
325 activate(aHandle); // set new target - this may cause a flush. |
|
326 } |
|
327 |
|
328 // size = 8; |
|
329 final int opc = (aCommand << 16) | 8; |
|
330 ensureSpace(8); |
|
331 |
|
332 final int[] buffer = iBuffer; |
|
333 int count = iCount; |
|
334 buffer[count++] = opc; |
|
335 buffer[count++] = aArg1; |
|
336 buffer[count++] = aArg2; |
|
337 buffer[count++] = aArg3; |
|
338 buffer[count++] = aArg4; |
|
339 buffer[count++] = aArg5; |
|
340 buffer[count++] = aArg6; |
|
341 buffer[count++] = aArg7; |
|
342 iCount = count; |
|
343 } |
|
344 |
|
345 /** |
|
346 * |
|
347 */ |
|
348 final void write(int aHandle, int aCommand, int aArg1, int aArg2, |
|
349 int aArg3, int aArg4, int aArg5, int aArg6, int aArg7, |
|
350 int aArg8, int aArg9) |
|
351 { |
|
352 if (iHandle <= 0) |
|
353 { |
|
354 throw new RuntimeException("Buffer closed"); |
|
355 } |
|
356 |
|
357 if (aHandle != iCurrent) |
|
358 { |
|
359 deactivate(); // remove existing target |
|
360 activate(aHandle); // set new target - this may cause a flush. |
|
361 } |
|
362 |
|
363 // size = 10; |
|
364 final int opc = (aCommand << 16) | 10; |
|
365 ensureSpace(10); |
|
366 |
|
367 final int[] buffer = iBuffer; |
|
368 int count = iCount; |
|
369 buffer[count++] = opc; |
|
370 buffer[count++] = aArg1; |
|
371 buffer[count++] = aArg2; |
|
372 buffer[count++] = aArg3; |
|
373 buffer[count++] = aArg4; |
|
374 buffer[count++] = aArg5; |
|
375 buffer[count++] = aArg6; |
|
376 buffer[count++] = aArg7; |
|
377 buffer[count++] = aArg8; |
|
378 buffer[count++] = aArg9; |
|
379 iCount = count; |
|
380 } |
|
381 |
|
382 /** |
|
383 * Writes a string command into the buffer, intended to support |
|
384 * Graphics.drawString(), this method also passes three additional |
|
385 * integer parameters. |
|
386 * |
|
387 */ |
|
388 final void writeStr(int aHandle, int aCmd, String aString, int aOff, |
|
389 int aLen, int aArg1, int aArg2, int aArg3) |
|
390 { |
|
391 // |
|
392 // Implementation note: We cannot avoid two copies as even a native method |
|
393 // would still have to use GetStringChars() which makes a copy. There is |
|
394 // no equivalent to GetIntArrayRegion. |
|
395 // |
|
396 if (aLen > 0) |
|
397 { |
|
398 final char[] array = (aLen <= CHAR_BUFFER_SIZE ? iCharBuffer : new char[aLen]); |
|
399 aString.getChars(aOff, aOff+aLen, array, 0); |
|
400 writeChars(aHandle, aCmd, array, 0, aLen, aArg1, aArg2, aArg3); |
|
401 } |
|
402 } |
|
403 |
|
404 /** |
|
405 * Writes a character array command into the buffer, intended to support |
|
406 * Graphics.drawChars(), this method also passes three additional |
|
407 * integer parameters. |
|
408 */ |
|
409 final void writeChars(int aHandle, int aCommand, char[] aChars, int aOff, |
|
410 int aLen, int aArg1, int aArg2, int aArg3) |
|
411 { |
|
412 if (aLen < 1) |
|
413 { |
|
414 return; |
|
415 } |
|
416 |
|
417 // |
|
418 // cmd, x, y, anchor, len, char[0..len-1] |
|
419 // |
|
420 final int cmdLen = 4 + ((aLen+1)>>1); |
|
421 |
|
422 if (cmdLen < BUFFER_SIZE) |
|
423 { |
|
424 if (iHandle <= 0) |
|
425 { |
|
426 throw new RuntimeException("Buffer closed"); |
|
427 } |
|
428 |
|
429 if (aHandle != iCurrent) |
|
430 { |
|
431 deactivate(); // remove existing target |
|
432 activate(aHandle); // set new target - this may cause a flush. |
|
433 } |
|
434 |
|
435 final int size = cmdLen + 1; |
|
436 final int opc = (aCommand << 16) | size; |
|
437 ensureSpace(size); |
|
438 |
|
439 iBuffer[iCount++] = opc; |
|
440 iBuffer[iCount++] = aArg1; |
|
441 iBuffer[iCount++] = aArg2; |
|
442 iBuffer[iCount++] = aArg3; |
|
443 |
|
444 writeCharsInLine(aChars, aOff, aLen); |
|
445 } |
|
446 else |
|
447 { |
|
448 // Not enough space in the buffer |
|
449 throw new OutOfMemoryError(); |
|
450 // |
|
451 // Possible alternatives: |
|
452 // |
|
453 // 1. Allocate an HBufC, write the chars into it, stick it in the buffer. |
|
454 // |
|
455 // writeCharsOutOfLine(); |
|
456 // |
|
457 } |
|
458 } |
|
459 |
|
460 /** |
|
461 * |
|
462 */ |
|
463 private void writeCharsInLine(char[] aChars, int aOff, int aLen) |
|
464 { |
|
465 final int[] buffer = iBuffer; |
|
466 int count = iCount; |
|
467 |
|
468 buffer[count++] = aLen; // | CHAR_DATA_INLINE |
|
469 |
|
470 final int wend = aOff + (aLen & ~1); |
|
471 |
|
472 while (aOff < wend) |
|
473 { |
|
474 final int ch1 = aChars[aOff++]; |
|
475 final int ch2 = aChars[aOff++]; |
|
476 |
|
477 // |
|
478 // Pack two chars into each int. |
|
479 // |
|
480 // Assumes: |
|
481 // |
|
482 // ints are little endian. |
|
483 // char to int promotion doesn't sign extend |
|
484 // |
|
485 |
|
486 buffer[count++] = (ch2 << 16) | ch1; |
|
487 } |
|
488 |
|
489 if ((aLen & 1) == 1) |
|
490 { |
|
491 buffer[count++] = aChars[aOff]; // last char in first half-word |
|
492 } |
|
493 |
|
494 iCount = count; |
|
495 } |
|
496 |
|
497 /** |
|
498 * ensures there is at least aSize words of space remaining in the buffer, |
|
499 * and flushes the buffer if not. |
|
500 */ |
|
501 final void ensureSpace(int aSize) |
|
502 { |
|
503 if ((iCount+aSize) > iBuffer.length) |
|
504 { |
|
505 pump(); |
|
506 if (aSize > iBuffer.length) |
|
507 { |
|
508 throw new RuntimeException("Insufficient space in buffer for command: " + aSize); |
|
509 } |
|
510 } |
|
511 } |
|
512 |
|
513 /** |
|
514 * Flushes buffer and waits for native processing to complete. |
|
515 */ |
|
516 final void sync() |
|
517 { |
|
518 synchronized (this) |
|
519 { |
|
520 if (iCount > 0) |
|
521 { |
|
522 deactivate(); |
|
523 _flush(iHandle, iBuffer, iCount); |
|
524 iCount=0; |
|
525 iStart=0; |
|
526 iCurrent=-1; |
|
527 } |
|
528 } |
|
529 } |
|
530 |
|
531 /** |
|
532 * |
|
533 */ |
|
534 private void deactivate() |
|
535 { |
|
536 if (-1 != iCurrent) |
|
537 { |
|
538 iBuffer[iStart] = iCount - iStart - 1; |
|
539 iCurrent = -1; |
|
540 } |
|
541 } |
|
542 |
|
543 /** |
|
544 * |
|
545 */ |
|
546 private void activate(int aHandle) |
|
547 { |
|
548 if (0 != aHandle) |
|
549 { |
|
550 // flush if insufficient space for activation |
|
551 // command. |
|
552 // RECURSION NOTE: we do not use pump() here |
|
553 // to avoid any risk of recursion. |
|
554 if ((iCount + 2) > iBuffer.length) |
|
555 { |
|
556 sync(); |
|
557 } |
|
558 |
|
559 iBuffer[ iCount++ ] = (aHandle | ACTIVATE); |
|
560 iCurrent = aHandle; |
|
561 iStart = iCount; |
|
562 iBuffer[ iCount++ ] = 0; |
|
563 } |
|
564 else |
|
565 { |
|
566 throw new RuntimeException("Invalid handle " + aHandle); |
|
567 } |
|
568 } |
|
569 |
|
570 /** |
|
571 * Flush the current contents of the buffer and reset the current writer. |
|
572 */ |
|
573 private void pump() |
|
574 { |
|
575 final int current = iCurrent; |
|
576 sync(); |
|
577 activate(current); |
|
578 } |
|
579 |
|
580 private native int _open(int aEventServerHandle); |
|
581 private native void _flush(int aHandle, int[] aBuffer, int aCount); |
|
582 private native void _close(int aHandle); |
|
583 } |
|
584 |