blob: 379a7b30e0c2c9e95fe8f01e7e4f64bec9b3d1cc [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkBitmapProcState.h"
2#include "SkColorPriv.h"
3#include "SkFilterProc.h"
4#include "SkPaint.h"
5#include "SkShader.h" // for tilemodes
6
7#ifdef SK_CPU_BENDIAN
8 #define UNPACK_PRIMARY_SHORT(packed) ((uint32_t)(packed) >> 16)
9 #define UNPACK_SECONDARY_SHORT(packed) ((packed) & 0xFFFF)
10#else
11 #define UNPACK_PRIMARY_SHORT(packed) ((packed) & 0xFFFF)
12 #define UNPACK_SECONDARY_SHORT(packed) ((uint32_t)(packed) >> 16)
13#endif
14
15static inline SkPMColor Filter_32(unsigned x, unsigned y,
16 SkPMColor a00, SkPMColor a01,
17 SkPMColor a10, SkPMColor a11) {
18 SkASSERT((unsigned)x <= 0xF);
19 SkASSERT((unsigned)y <= 0xF);
20
21 int xy = x * y;
22 uint32_t mask = gMask_00FF00FF; //0xFF00FF;
23
24 int scale = 256 - 16*y - 16*x + xy;
25 uint32_t lo = (a00 & mask) * scale;
26 uint32_t hi = ((a00 >> 8) & mask) * scale;
27
28 scale = 16*x - xy;
29 lo += (a01 & mask) * scale;
30 hi += ((a01 >> 8) & mask) * scale;
31
32 scale = 16*y - xy;
33 lo += (a10 & mask) * scale;
34 hi += ((a10 >> 8) & mask) * scale;
35
36 lo += (a11 & mask) * xy;
37 hi += ((a11 >> 8) & mask) * xy;
38
39 return ((lo >> 8) & mask) | (hi & ~mask);
40}
41
42// returns expanded * 5bits
43static inline uint32_t Filter_565_Expanded(unsigned x, unsigned y,
44 uint32_t a00, uint32_t a01,
45 uint32_t a10, uint32_t a11) {
46 SkASSERT((unsigned)x <= 0xF);
47 SkASSERT((unsigned)y <= 0xF);
48
49 a00 = SkExpand_rgb_16(a00);
50 a01 = SkExpand_rgb_16(a01);
51 a10 = SkExpand_rgb_16(a10);
52 a11 = SkExpand_rgb_16(a11);
53
54 int xy = x * y >> 3;
55 return a00 * (32 - 2*y - 2*x + xy) +
56 a01 * (2*x - xy) +
57 a10 * (2*y - xy) +
58 a11 * xy;
59}
60
61// turn an expanded 565 * 5bits into SkPMColor
62// g:11 | r:10 | x:1 | b:10
63static inline SkPMColor SkExpanded_565_To_PMColor(uint32_t c) {
64 unsigned r = (c >> 13) & 0xFF;
65 unsigned g = (c >> 24);
66 unsigned b = (c >> 2) & 0xFF;
67 return SkPackARGB32(0xFF, r, g, b);
68}
69
70// returns answer in SkPMColor format
71static inline SkPMColor Filter_4444_D32(unsigned x, unsigned y,
72 uint32_t a00, uint32_t a01,
73 uint32_t a10, uint32_t a11) {
74 SkASSERT((unsigned)x <= 0xF);
75 SkASSERT((unsigned)y <= 0xF);
76
77 a00 = SkExpand_4444(a00);
78 a01 = SkExpand_4444(a01);
79 a10 = SkExpand_4444(a10);
80 a11 = SkExpand_4444(a11);
81
82 int xy = x * y >> 4;
83 uint32_t result = a00 * (16 - y - x + xy) +
84 a01 * (x - xy) +
85 a10 * (y - xy) +
86 a11 * xy;
87
88 return SkCompact_8888(result);
89}
90
91static inline U8CPU Filter_8(unsigned x, unsigned y,
92 U8CPU a00, U8CPU a01,
93 U8CPU a10, U8CPU a11) {
94 SkASSERT((unsigned)x <= 0xF);
95 SkASSERT((unsigned)y <= 0xF);
96
97 int xy = x * y;
98 unsigned result = a00 * (256 - 16*y - 16*x + xy) +
99 a01 * (16*x - xy) +
100 a10 * (16*y - xy) +
101 a11 * xy;
102
103 return result >> 8;
104}
105
106/*****************************************************************************
107 *
108 * D32 functions
109 *
110 */
111
112// SRC == 8888
113
114#define FILTER_PROC(x, y, a, b, c, d) Filter_32(x, y, a, b, c, d)
115
116#define MAKENAME(suffix) S32_opaque_D32 ## suffix
117#define DSTSIZE 32
118#define SRCTYPE SkPMColor
119#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
120 SkASSERT(state.fAlphaScale == 256)
121#define RETURNDST(src) src
122#define SRC_TO_FILTER(src) src
123#define FILTER_TO_DST(c) c
124#include "SkBitmapProcState_sample.h"
125
126#define MAKENAME(suffix) S32_alpha_D32 ## suffix
127#define DSTSIZE 32
128#define SRCTYPE SkPMColor
129#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
130 SkASSERT(state.fAlphaScale < 256)
131#define PREAMBLE(state) unsigned scale = state.fAlphaScale
132#define RETURNDST(src) SkAlphaMulQ(src, scale)
133#define SRC_TO_FILTER(src) src
134#define FILTER_TO_DST(c) SkAlphaMulQ(c, scale)
135#include "SkBitmapProcState_sample.h"
136
137// SRC == 565
138
139#undef FILTER_PROC
140#define FILTER_PROC(x, y, a, b, c, d) Filter_565_Expanded(x, y, a, b, c, d)
141
142#define MAKENAME(suffix) S16_opaque_D32 ## suffix
143#define DSTSIZE 32
144#define SRCTYPE uint16_t
145#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config); \
146 SkASSERT(state.fAlphaScale == 256)
147#define RETURNDST(src) SkPixel16ToPixel32(src)
148#define SRC_TO_FILTER(src) src
149#define FILTER_TO_DST(c) SkExpanded_565_To_PMColor(c)
150#include "SkBitmapProcState_sample.h"
151
152#define MAKENAME(suffix) S16_alpha_D32 ## suffix
153#define DSTSIZE 32
154#define SRCTYPE uint16_t
155#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config); \
156 SkASSERT(state.fAlphaScale < 256)
157#define PREAMBLE(state) unsigned scale = state.fAlphaScale
158#define RETURNDST(src) SkAlphaMulQ(SkPixel16ToPixel32(src), scale)
159#define SRC_TO_FILTER(src) src
160#define FILTER_TO_DST(c) SkAlphaMulQ(SkExpanded_565_To_PMColor(c), scale)
161#include "SkBitmapProcState_sample.h"
162
163// SRC == Index8
164
165#undef FILTER_PROC
166#define FILTER_PROC(x, y, a, b, c, d) Filter_32(x, y, a, b, c, d)
167
168#define MAKENAME(suffix) SI8_opaque_D32 ## suffix
169#define DSTSIZE 32
170#define SRCTYPE uint8_t
171#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
172 SkASSERT(state.fAlphaScale == 256)
173#define PREAMBLE(state) const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
174#define RETURNDST(src) table[src]
175#define SRC_TO_FILTER(src) table[src]
176#define FILTER_TO_DST(c) c
177#define POSTAMBLE(state) state.fBitmap->getColorTable()->unlockColors(false)
178#include "SkBitmapProcState_sample.h"
179
180#define MAKENAME(suffix) SI8_alpha_D32 ## suffix
181#define DSTSIZE 32
182#define SRCTYPE uint8_t
183#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
184 SkASSERT(state.fAlphaScale < 256)
185#define PREAMBLE(state) unsigned scale = state.fAlphaScale; \
186 const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
187#define RETURNDST(src) SkAlphaMulQ(table[src], scale)
188#define SRC_TO_FILTER(src) table[src]
189#define FILTER_TO_DST(c) SkAlphaMulQ(c, scale)
190#define POSTAMBLE(state) state.fBitmap->getColorTable()->unlockColors(false)
191#include "SkBitmapProcState_sample.h"
192
193// SRC == 4444
194
195#undef FILTER_PROC
196#define FILTER_PROC(x, y, a, b, c, d) Filter_4444_D32(x, y, a, b, c, d)
197
198#define MAKENAME(suffix) S4444_opaque_D32 ## suffix
199#define DSTSIZE 32
200#define SRCTYPE SkPMColor16
201#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_4444_Config); \
202SkASSERT(state.fAlphaScale == 256)
203#define RETURNDST(src) SkPixel4444ToPixel32(src)
204#define SRC_TO_FILTER(src) src
205#define FILTER_TO_DST(c) c
206#include "SkBitmapProcState_sample.h"
207
208#define MAKENAME(suffix) S4444_alpha_D32 ## suffix
209#define DSTSIZE 32
210#define SRCTYPE SkPMColor16
211#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_4444_Config); \
212SkASSERT(state.fAlphaScale < 256)
213#define PREAMBLE(state) unsigned scale = state.fAlphaScale
214#define RETURNDST(src) SkAlphaMulQ(SkPixel4444ToPixel32(src), scale)
215#define SRC_TO_FILTER(src) src
216#define FILTER_TO_DST(c) SkAlphaMulQ(c, scale)
217#include "SkBitmapProcState_sample.h"
218
219// SRC == A8
220
221#undef FILTER_PROC
222#define FILTER_PROC(x, y, a, b, c, d) Filter_8(x, y, a, b, c, d)
223
224#define MAKENAME(suffix) SA8_alpha_D32 ## suffix
225#define DSTSIZE 32
226#define SRCTYPE uint8_t
227#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kA8_Config); \
228 SkASSERT(state.fAlphaScale == 256)
229#define PREAMBLE(state) const SkPMColor pmColor = state.fPaintPMColor;
230#define RETURNDST(src) SkAlphaMulQ(pmColor, SkAlpha255To256(src))
231#define SRC_TO_FILTER(src) src
232#define FILTER_TO_DST(c) SkAlphaMulQ(pmColor, SkAlpha255To256(c))
233#include "SkBitmapProcState_sample.h"
234
235/*****************************************************************************
236 *
237 * D16 functions
238 *
239 */
240
241// SRC == 8888
242
243#undef FILTER_PROC
244#define FILTER_PROC(x, y, a, b, c, d) Filter_32(x, y, a, b, c, d)
245
246#define MAKENAME(suffix) S32_D16 ## suffix
247#define DSTSIZE 16
248#define SRCTYPE SkPMColor
249#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
250 SkASSERT(state.fBitmap->isOpaque())
251#define RETURNDST(src) SkPixel32ToPixel16(src)
252#define SRC_TO_FILTER(src) src
253#define FILTER_TO_DST(c) SkPixel32ToPixel16(c)
254#include "SkBitmapProcState_sample.h"
255
256// SRC == 565
257
258#undef FILTER_PROC
259#define FILTER_PROC(x, y, a, b, c, d) Filter_565_Expanded(x, y, a, b, c, d)
260
261#define MAKENAME(suffix) S16_D16 ## suffix
262#define DSTSIZE 16
263#define SRCTYPE uint16_t
264#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
265#define RETURNDST(src) src
266#define SRC_TO_FILTER(src) src
267#define FILTER_TO_DST(c) SkCompact_rgb_16((c) >> 5)
268#include "SkBitmapProcState_sample.h"
269
270// SRC == Index8
271
272#undef FILTER_PROC
273#define FILTER_PROC(x, y, a, b, c, d) Filter_565_Expanded(x, y, a, b, c, d)
274
275#define MAKENAME(suffix) SI8_D16 ## suffix
276#define DSTSIZE 16
277#define SRCTYPE uint8_t
278#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
279 SkASSERT(state.fBitmap->isOpaque())
280#define PREAMBLE(state) const uint16_t* SK_RESTRICT table = state.fBitmap->getColorTable()->lock16BitCache()
281#define RETURNDST(src) table[src]
282#define SRC_TO_FILTER(src) table[src]
283#define FILTER_TO_DST(c) SkCompact_rgb_16(c >> 5)
284#define POSTAMBLE(state) state.fBitmap->getColorTable()->unlock16BitCache()
285#include "SkBitmapProcState_sample.h"
286
reed@android.coma44b4cc2009-07-16 02:03:58 +0000287///////////////////////////////////////////////////////////////////////////////
288
289#undef FILTER_PROC
290#define FILTER_PROC(x, y, a, b, c, d) Filter_565_Expanded(x, y, a, b, c, d)
291
292#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max)
293#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max)
294#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
295#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
296
297#define MAKENAME(suffix) Clamp_S16_D16 ## suffix
298#define SRCTYPE uint16_t
299#define DSTTYPE uint16_t
300#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
301#define SRC_TO_FILTER(src) src
302#define FILTER_TO_DST(c) SkCompact_rgb_16((c) >> 5)
303#include "SkBitmapProcState_shaderproc.h"
304
reed@android.comaa9152a2009-07-17 21:24:56 +0000305
306#define TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16)
307#define TILEY_PROCF(fy, max) (((fy) & 0xFFFF) * ((max) + 1) >> 16)
308#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
309#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
310
311#define MAKENAME(suffix) Repeat_S16_D16 ## suffix
312#define SRCTYPE uint16_t
313#define DSTTYPE uint16_t
314#define CHECKSTATE(state) SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
315#define SRC_TO_FILTER(src) src
316#define FILTER_TO_DST(c) SkCompact_rgb_16((c) >> 5)
317#include "SkBitmapProcState_shaderproc.h"
318
reed@android.coma44b4cc2009-07-16 02:03:58 +0000319///////////////////////////////////////////////////////////////////////////////
320
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321static bool valid_for_filtering(unsigned dimension) {
322 // for filtering, width and height must fit in 14bits, since we use steal
323 // 2 bits from each to store our 4bit subpixel data
324 return (dimension & ~0x3FFF) == 0;
325}
326
327bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
328 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
329 return false;
330 }
331 const SkMatrix* m;
reed@android.coma44b4cc2009-07-16 02:03:58 +0000332 bool clamp_clamp;
333
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 if (SkShader::kClamp_TileMode == fTileModeX &&
335 SkShader::kClamp_TileMode == fTileModeY) {
336 m = &inv;
reed@android.coma44b4cc2009-07-16 02:03:58 +0000337 clamp_clamp = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 } else {
339 fUnitInvMatrix = inv;
340 fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
341 m = &fUnitInvMatrix;
reed@android.coma44b4cc2009-07-16 02:03:58 +0000342 clamp_clamp = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 }
344
345 fBitmap = &fOrigBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 if (fOrigBitmap.hasMipMap()) {
347 int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
348 SkScalarToFixed(m->getScaleX()),
349 SkScalarToFixed(m->getSkewY()));
350
351 if (shift > 0) {
352 if (m != &fUnitInvMatrix) {
353 fUnitInvMatrix = *m;
354 m = &fUnitInvMatrix;
355 }
356
357 SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
358 fUnitInvMatrix.postScale(scale, scale);
359
360 // now point here instead of fOrigBitmap
361 fBitmap = &fMipBitmap;
362 }
363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364
365 fInvMatrix = m;
366 fInvProc = m->getMapXYProc();
367 fInvType = m->getType();
368 fInvSx = SkScalarToFixed(m->getScaleX());
369 fInvSy = SkScalarToFixed(m->getScaleY());
370 fInvKy = SkScalarToFixed(m->getSkewY());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371
372 fAlphaScale = SkAlpha255To256(paint.getAlpha());
373
374 // pick-up filtering from the paint, but only if the matrix is
375 // more complex than identity/translate (i.e. no need to pay the cost
376 // of filtering if we're not scaled etc.).
377 // note: we explicitly check inv, since m might be scaled due to unitinv
378 // trickery, but we don't want to see that for this test
379 fDoFilter = paint.isFilterBitmap() &&
380 (inv.getType() > SkMatrix::kTranslate_Mask &&
381 valid_for_filtering(fBitmap->width() | fBitmap->height()));
382
reed@android.com7a99eb12009-07-16 01:13:14 +0000383 fShaderProc32 = NULL;
384 fShaderProc16 = NULL;
385 fSampleProc32 = NULL;
386 fSampleProc16 = NULL;
reed@android.com48534f92009-07-16 20:53:26 +0000387
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 fMatrixProc = this->chooseMatrixProc();
389 if (NULL == fMatrixProc) {
390 return false;
391 }
392
393 ///////////////////////////////////////////////////////////////////////
394
395 int index = 0;
396 if (fAlphaScale < 256) { // note: this distinction is not used for D16
397 index |= 1;
398 }
399 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
400 index |= 2;
401 }
402 if (fDoFilter) {
403 index |= 4;
404 }
405 // bits 3,4,5 encoding the source bitmap format
406 switch (fBitmap->config()) {
407 case SkBitmap::kARGB_8888_Config:
408 index |= 0;
409 break;
410 case SkBitmap::kRGB_565_Config:
411 index |= 8;
412 break;
413 case SkBitmap::kIndex8_Config:
414 index |= 16;
415 break;
416 case SkBitmap::kARGB_4444_Config:
417 index |= 24;
418 break;
419 case SkBitmap::kA8_Config:
420 index |= 32;
421 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
reed@android.com3469c762009-02-24 19:03:20 +0000422 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423 default:
424 return false;
425 }
426
427 static const SampleProc32 gSample32[] = {
428 S32_opaque_D32_nofilter_DXDY,
429 S32_alpha_D32_nofilter_DXDY,
430 S32_opaque_D32_nofilter_DX,
431 S32_alpha_D32_nofilter_DX,
432 S32_opaque_D32_filter_DXDY,
433 S32_alpha_D32_filter_DXDY,
434 S32_opaque_D32_filter_DX,
435 S32_alpha_D32_filter_DX,
436
437 S16_opaque_D32_nofilter_DXDY,
438 S16_alpha_D32_nofilter_DXDY,
439 S16_opaque_D32_nofilter_DX,
440 S16_alpha_D32_nofilter_DX,
441 S16_opaque_D32_filter_DXDY,
442 S16_alpha_D32_filter_DXDY,
443 S16_opaque_D32_filter_DX,
444 S16_alpha_D32_filter_DX,
445
446 SI8_opaque_D32_nofilter_DXDY,
447 SI8_alpha_D32_nofilter_DXDY,
448 SI8_opaque_D32_nofilter_DX,
449 SI8_alpha_D32_nofilter_DX,
450 SI8_opaque_D32_filter_DXDY,
451 SI8_alpha_D32_filter_DXDY,
452 SI8_opaque_D32_filter_DX,
453 SI8_alpha_D32_filter_DX,
454
455 S4444_opaque_D32_nofilter_DXDY,
456 S4444_alpha_D32_nofilter_DXDY,
457 S4444_opaque_D32_nofilter_DX,
458 S4444_alpha_D32_nofilter_DX,
459 S4444_opaque_D32_filter_DXDY,
460 S4444_alpha_D32_filter_DXDY,
461 S4444_opaque_D32_filter_DX,
462 S4444_alpha_D32_filter_DX,
463
464 // A8 treats alpha/opauqe the same (equally efficient)
465 SA8_alpha_D32_nofilter_DXDY,
466 SA8_alpha_D32_nofilter_DXDY,
467 SA8_alpha_D32_nofilter_DX,
468 SA8_alpha_D32_nofilter_DX,
469 SA8_alpha_D32_filter_DXDY,
470 SA8_alpha_D32_filter_DXDY,
471 SA8_alpha_D32_filter_DX,
472 SA8_alpha_D32_filter_DX
473 };
474
475 static const SampleProc16 gSample16[] = {
476 S32_D16_nofilter_DXDY,
477 S32_D16_nofilter_DX,
478 S32_D16_filter_DXDY,
479 S32_D16_filter_DX,
480
481 S16_D16_nofilter_DXDY,
482 S16_D16_nofilter_DX,
483 S16_D16_filter_DXDY,
484 S16_D16_filter_DX,
485
486 SI8_D16_nofilter_DXDY,
487 SI8_D16_nofilter_DX,
488 SI8_D16_filter_DXDY,
489 SI8_D16_filter_DX,
490
491 // Don't support 4444 -> 565
492 NULL, NULL, NULL, NULL,
493 // Don't support A8 -> 565
494 NULL, NULL, NULL, NULL
495 };
reed@android.com48534f92009-07-16 20:53:26 +0000496
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 fSampleProc32 = gSample32[index];
498 index >>= 1; // shift away any opaque/alpha distinction
499 fSampleProc16 = gSample16[index];
500
reed@android.coma44b4cc2009-07-16 02:03:58 +0000501 // our special-case shaderprocs
reed@android.comaa9152a2009-07-17 21:24:56 +0000502 if (S16_D16_filter_DX == fSampleProc16) {
503 if (clamp_clamp) {
504 fShaderProc16 = Clamp_S16_D16_filter_DX_shaderproc;
505 } else if (SkShader::kRepeat_TileMode == fTileModeX &&
506 SkShader::kRepeat_TileMode == fTileModeY) {
507 fShaderProc16 = Repeat_S16_D16_filter_DX_shaderproc;
508 }
reed@android.coma44b4cc2009-07-16 02:03:58 +0000509 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000510 return true;
511}
512