OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 Google Inc. | 2 * Copyright 2010 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkGr.h" | 8 #include "SkGr.h" |
9 | 9 |
10 #include "GrXferProcessor.h" | 10 #include "GrXferProcessor.h" |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 return kNearest_Stretch; | 99 return kNearest_Stretch; |
100 case GrTextureParams::kBilerp_FilterMode: | 100 case GrTextureParams::kBilerp_FilterMode: |
101 case GrTextureParams::kMipMap_FilterMode: | 101 case GrTextureParams::kMipMap_FilterMode: |
102 return kBilerp_Stretch; | 102 return kBilerp_Stretch; |
103 } | 103 } |
104 } | 104 } |
105 } | 105 } |
106 return kNo_Stretch; | 106 return kNo_Stretch; |
107 } | 107 } |
108 | 108 |
109 static bool make_stretched_key(const GrContentKey& origKey, Stretch stretch, | 109 static bool make_stretched_key(const GrUniqueKey& origKey, Stretch stretch, |
110 GrContentKey* stretchedKey) { | 110 GrUniqueKey* stretchedKey) { |
111 if (origKey.isValid() && kNo_Stretch != stretch) { | 111 if (origKey.isValid() && kNo_Stretch != stretch) { |
112 static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain
(); | 112 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
113 GrContentKey::Builder builder(stretchedKey, origKey, kDomain, 1); | 113 GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 1); |
114 builder[0] = stretch; | 114 builder[0] = stretch; |
115 builder.finish(); | 115 builder.finish(); |
116 return true; | 116 return true; |
117 } | 117 } |
118 SkASSERT(!stretchedKey->isValid()); | 118 SkASSERT(!stretchedKey->isValid()); |
119 return false; | 119 return false; |
120 } | 120 } |
121 | 121 |
122 static void make_unstretched_key(const SkBitmap& bitmap, GrContentKey* key) { | 122 static void make_unstretched_key(const SkBitmap& bitmap, GrUniqueKey* key) { |
123 // Our id includes the offset, width, and height so that bitmaps created by
extractSubset() | 123 // Our id includes the offset, width, and height so that bitmaps created by
extractSubset() |
124 // are unique. | 124 // are unique. |
125 uint32_t genID = bitmap.getGenerationID(); | 125 uint32_t genID = bitmap.getGenerationID(); |
126 SkIPoint origin = bitmap.pixelRefOrigin(); | 126 SkIPoint origin = bitmap.pixelRefOrigin(); |
127 uint32_t width = SkToU16(bitmap.width()); | 127 uint32_t width = SkToU16(bitmap.width()); |
128 uint32_t height = SkToU16(bitmap.height()); | 128 uint32_t height = SkToU16(bitmap.height()); |
129 | 129 |
130 static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain(); | 130 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
131 GrContentKey::Builder builder(key, kDomain, 4); | 131 GrUniqueKey::Builder builder(key, kDomain, 4); |
132 builder[0] = genID; | 132 builder[0] = genID; |
133 builder[1] = origin.fX; | 133 builder[1] = origin.fX; |
134 builder[2] = origin.fY; | 134 builder[2] = origin.fY; |
135 builder[3] = width | (height << 16); | 135 builder[3] = width | (height << 16); |
136 } | 136 } |
137 | 137 |
138 static void make_bitmap_keys(const SkBitmap& bitmap, | 138 static void make_bitmap_keys(const SkBitmap& bitmap, |
139 Stretch stretch, | 139 Stretch stretch, |
140 GrContentKey* key, | 140 GrUniqueKey* key, |
141 GrContentKey* stretchedKey) { | 141 GrUniqueKey* stretchedKey) { |
142 make_unstretched_key(bitmap, key); | 142 make_unstretched_key(bitmap, key); |
143 if (kNo_Stretch != stretch) { | 143 if (kNo_Stretch != stretch) { |
144 make_stretched_key(*key, stretch, stretchedKey); | 144 make_stretched_key(*key, stretch, stretchedKey); |
145 } | 145 } |
146 } | 146 } |
147 | 147 |
148 static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrSurfaceDesc*
desc) { | 148 static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrSurfaceDesc*
desc) { |
149 desc->fFlags = kNone_GrSurfaceFlags; | 149 desc->fFlags = kNone_GrSurfaceFlags; |
150 desc->fWidth = bitmap.width(); | 150 desc->fWidth = bitmap.width(); |
151 desc->fHeight = bitmap.height(); | 151 desc->fHeight = bitmap.height(); |
152 desc->fConfig = SkImageInfo2GrPixelConfig(bitmap.info()); | 152 desc->fConfig = SkImageInfo2GrPixelConfig(bitmap.info()); |
153 desc->fSampleCnt = 0; | 153 desc->fSampleCnt = 0; |
154 } | 154 } |
155 | 155 |
156 namespace { | 156 namespace { |
157 | 157 |
158 // When the SkPixelRef genID changes, invalidate a corresponding GrResource desc
ribed by key. | 158 // When the SkPixelRef genID changes, invalidate a corresponding GrResource desc
ribed by key. |
159 class BitmapInvalidator : public SkPixelRef::GenIDChangeListener { | 159 class BitmapInvalidator : public SkPixelRef::GenIDChangeListener { |
160 public: | 160 public: |
161 explicit BitmapInvalidator(const GrContentKey& key) : fMsg(key) {} | 161 explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {} |
162 private: | 162 private: |
163 GrContentKeyInvalidatedMessage fMsg; | 163 GrUniqueKeyInvalidatedMessage fMsg; |
164 | 164 |
165 void onChange() SK_OVERRIDE { | 165 void onChange() SK_OVERRIDE { |
166 SkMessageBus<GrContentKeyInvalidatedMessage>::Post(fMsg); | 166 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); |
167 } | 167 } |
168 }; | 168 }; |
169 | 169 |
170 } // namespace | 170 } // namespace |
171 | 171 |
172 | 172 |
173 static GrTexture* create_texture_for_bmp(GrContext* ctx, | 173 static GrTexture* create_texture_for_bmp(GrContext* ctx, |
174 const GrContentKey& optionalKey, | 174 const GrUniqueKey& optionalKey, |
175 GrSurfaceDesc desc, | 175 GrSurfaceDesc desc, |
176 SkPixelRef* pixelRefForInvalidationNoti
fication, | 176 SkPixelRef* pixelRefForInvalidationNoti
fication, |
177 const void* pixels, | 177 const void* pixels, |
178 size_t rowBytes) { | 178 size_t rowBytes) { |
179 GrTexture* result = ctx->createTexture(desc, true, pixels, rowBytes); | 179 GrTexture* result = ctx->createTexture(desc, true, pixels, rowBytes); |
180 if (result && optionalKey.isValid()) { | 180 if (result && optionalKey.isValid()) { |
181 BitmapInvalidator* listener = SkNEW_ARGS(BitmapInvalidator, (optionalKey
)); | 181 BitmapInvalidator* listener = SkNEW_ARGS(BitmapInvalidator, (optionalKey
)); |
182 pixelRefForInvalidationNotification->addGenIDChangeListener(listener); | 182 pixelRefForInvalidationNotification->addGenIDChangeListener(listener); |
183 SkAssertResult(ctx->addResourceToCache(optionalKey, result)); | 183 SkAssertResult(ctx->addResourceToCache(optionalKey, result)); |
184 } | 184 } |
185 return result; | 185 return result; |
186 } | 186 } |
187 | 187 |
188 // creates a new texture that is the input texture scaled up to the next power o
f two in | 188 // creates a new texture that is the input texture scaled up to the next power o
f two in |
189 // width or height. If optionalKey is valid it will be set on the new texture. s
tretch | 189 // width or height. If optionalKey is valid it will be set on the new texture. s
tretch |
190 // controls whether the scaling is done using nearest or bilerp filtering. | 190 // controls whether the scaling is done using nearest or bilerp filtering. |
191 GrTexture* stretch_texture_to_next_pot(GrTexture* inputTexture, Stretch stretch, | 191 GrTexture* stretch_texture_to_next_pot(GrTexture* inputTexture, Stretch stretch, |
192 SkPixelRef* pixelRef, | 192 SkPixelRef* pixelRef, |
193 const GrContentKey& optionalKey) { | 193 const GrUniqueKey& optionalKey) { |
194 SkASSERT(kNo_Stretch != stretch); | 194 SkASSERT(kNo_Stretch != stretch); |
195 | 195 |
196 GrContext* context = inputTexture->getContext(); | 196 GrContext* context = inputTexture->getContext(); |
197 SkASSERT(context); | 197 SkASSERT(context); |
198 | 198 |
199 // Either it's a cache miss or the original wasn't cached to begin with. | 199 // Either it's a cache miss or the original wasn't cached to begin with. |
200 GrSurfaceDesc rtDesc = inputTexture->desc(); | 200 GrSurfaceDesc rtDesc = inputTexture->desc(); |
201 rtDesc.fFlags = rtDesc.fFlags | | 201 rtDesc.fFlags = rtDesc.fFlags | |
202 kRenderTarget_GrSurfaceFlag | | 202 kRenderTarget_GrSurfaceFlag | |
203 kNoStencil_GrSurfaceFlag; | 203 kNoStencil_GrSurfaceFlag; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 SkRect localRect = SkRect::MakeWH(1.f, 1.f); | 246 SkRect localRect = SkRect::MakeWH(1.f, 1.f); |
247 | 247 |
248 GrContext::AutoClip ac(context, GrContext::AutoClip::kWideOpen_InitialClip); | 248 GrContext::AutoClip ac(context, GrContext::AutoClip::kWideOpen_InitialClip); |
249 context->drawNonAARectToRect(stretched->asRenderTarget(), paint, SkMatrix::I
(), rect, | 249 context->drawNonAARectToRect(stretched->asRenderTarget(), paint, SkMatrix::I
(), rect, |
250 localRect); | 250 localRect); |
251 | 251 |
252 return stretched; | 252 return stretched; |
253 } | 253 } |
254 | 254 |
255 #ifndef SK_IGNORE_ETC1_SUPPORT | 255 #ifndef SK_IGNORE_ETC1_SUPPORT |
256 static GrTexture *load_etc1_texture(GrContext* ctx, const GrContentKey& optional
Key, | 256 static GrTexture *load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalK
ey, |
257 const SkBitmap &bm, GrSurfaceDesc desc) { | 257 const SkBitmap &bm, GrSurfaceDesc desc) { |
258 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); | 258 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData()); |
259 | 259 |
260 // Is this even encoded data? | 260 // Is this even encoded data? |
261 if (NULL == data) { | 261 if (NULL == data) { |
262 return NULL; | 262 return NULL; |
263 } | 263 } |
264 | 264 |
265 // Is this a valid PKM encoded data? | 265 // Is this a valid PKM encoded data? |
266 const uint8_t *bytes = data->bytes(); | 266 const uint8_t *bytes = data->bytes(); |
(...skipping 28 matching lines...) Expand all Loading... |
295 bytes = ktx.pixelData(); | 295 bytes = ktx.pixelData(); |
296 desc.fConfig = kETC1_GrPixelConfig; | 296 desc.fConfig = kETC1_GrPixelConfig; |
297 } else { | 297 } else { |
298 return NULL; | 298 return NULL; |
299 } | 299 } |
300 | 300 |
301 return create_texture_for_bmp(ctx, optionalKey, desc, bm.pixelRef(), bytes,
0); | 301 return create_texture_for_bmp(ctx, optionalKey, desc, bm.pixelRef(), bytes,
0); |
302 } | 302 } |
303 #endif // SK_IGNORE_ETC1_SUPPORT | 303 #endif // SK_IGNORE_ETC1_SUPPORT |
304 | 304 |
305 static GrTexture* load_yuv_texture(GrContext* ctx, const GrContentKey& optionalK
ey, | 305 static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKe
y, |
306 const SkBitmap& bm, const GrSurfaceDesc& desc
) { | 306 const SkBitmap& bm, const GrSurfaceDesc& desc
) { |
307 // Subsets are not supported, the whole pixelRef is loaded when using YUV de
coding | 307 // Subsets are not supported, the whole pixelRef is loaded when using YUV de
coding |
308 SkPixelRef* pixelRef = bm.pixelRef(); | 308 SkPixelRef* pixelRef = bm.pixelRef(); |
309 if ((NULL == pixelRef) || | 309 if ((NULL == pixelRef) || |
310 (pixelRef->info().width() != bm.info().width()) || | 310 (pixelRef->info().width() != bm.info().width()) || |
311 (pixelRef->info().height() != bm.info().height())) { | 311 (pixelRef->info().height() != bm.info().height())) { |
312 return NULL; | 312 return NULL; |
313 } | 313 } |
314 | 314 |
315 const bool useCache = optionalKey.isValid(); | 315 const bool useCache = optionalKey.isValid(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth), | 397 SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth), |
398 SkIntToScalar(yuvInfo.fSize[0].fHeight)); | 398 SkIntToScalar(yuvInfo.fSize[0].fHeight)); |
399 GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip); | 399 GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip); |
400 ctx->drawRect(renderTarget, paint, SkMatrix::I(), r); | 400 ctx->drawRect(renderTarget, paint, SkMatrix::I(), r); |
401 | 401 |
402 return result; | 402 return result; |
403 } | 403 } |
404 | 404 |
405 static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx, | 405 static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx, |
406 const SkBitmap& origBitmap, | 406 const SkBitmap& origBitmap, |
407 const GrContentKey& optional
Key) { | 407 const GrUniqueKey& optionalK
ey) { |
408 SkBitmap tmpBitmap; | 408 SkBitmap tmpBitmap; |
409 | 409 |
410 const SkBitmap* bitmap = &origBitmap; | 410 const SkBitmap* bitmap = &origBitmap; |
411 | 411 |
412 GrSurfaceDesc desc; | 412 GrSurfaceDesc desc; |
413 generate_bitmap_texture_desc(*bitmap, &desc); | 413 generate_bitmap_texture_desc(*bitmap, &desc); |
414 | 414 |
415 if (kIndex_8_SkColorType == bitmap->colorType()) { | 415 if (kIndex_8_SkColorType == bitmap->colorType()) { |
416 if (ctx->isConfigTexturable(kIndex_8_GrPixelConfig)) { | 416 if (ctx->isConfigTexturable(kIndex_8_GrPixelConfig)) { |
417 size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig
, | 417 size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig
, |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 return NULL; | 458 return NULL; |
459 } | 459 } |
460 | 460 |
461 return create_texture_for_bmp(ctx, optionalKey, desc, origBitmap.pixelRef(), | 461 return create_texture_for_bmp(ctx, optionalKey, desc, origBitmap.pixelRef(), |
462 bitmap->getPixels(), bitmap->rowBytes()); | 462 bitmap->getPixels(), bitmap->rowBytes()); |
463 } | 463 } |
464 | 464 |
465 static GrTexture* create_bitmap_texture(GrContext* ctx, | 465 static GrTexture* create_bitmap_texture(GrContext* ctx, |
466 const SkBitmap& bmp, | 466 const SkBitmap& bmp, |
467 Stretch stretch, | 467 Stretch stretch, |
468 const GrContentKey& unstretchedKey, | 468 const GrUniqueKey& unstretchedKey, |
469 const GrContentKey& stretchedKey) { | 469 const GrUniqueKey& stretchedKey) { |
470 if (kNo_Stretch != stretch) { | 470 if (kNo_Stretch != stretch) { |
471 SkAutoTUnref<GrTexture> unstretched; | 471 SkAutoTUnref<GrTexture> unstretched; |
472 // Check if we have the unstretched version in the cache, if not create
it. | 472 // Check if we have the unstretched version in the cache, if not create
it. |
473 if (unstretchedKey.isValid()) { | 473 if (unstretchedKey.isValid()) { |
474 unstretched.reset(ctx->findAndRefCachedTexture(unstretchedKey)); | 474 unstretched.reset(ctx->findAndRefCachedTexture(unstretchedKey)); |
475 } | 475 } |
476 if (!unstretched) { | 476 if (!unstretched) { |
477 unstretched.reset(create_unstretched_bitmap_texture(ctx, bmp, unstre
tchedKey)); | 477 unstretched.reset(create_unstretched_bitmap_texture(ctx, bmp, unstre
tchedKey)); |
478 if (!unstretched) { | 478 if (!unstretched) { |
479 return NULL; | 479 return NULL; |
(...skipping 16 matching lines...) Expand all Loading... |
496 // Handle the case where the bitmap is explicitly texture backed. | 496 // Handle the case where the bitmap is explicitly texture backed. |
497 GrTexture* texture = bitmap.getTexture(); | 497 GrTexture* texture = bitmap.getTexture(); |
498 if (texture) { | 498 if (texture) { |
499 if (kNo_Stretch == stretch) { | 499 if (kNo_Stretch == stretch) { |
500 return true; | 500 return true; |
501 } | 501 } |
502 // No keys for volatile bitmaps. | 502 // No keys for volatile bitmaps. |
503 if (bitmap.isVolatile()) { | 503 if (bitmap.isVolatile()) { |
504 return false; | 504 return false; |
505 } | 505 } |
506 const GrContentKey& key = texture->getContentKey(); | 506 const GrUniqueKey& key = texture->getUniqueKey(); |
507 if (!key.isValid()) { | 507 if (!key.isValid()) { |
508 return false; | 508 return false; |
509 } | 509 } |
510 GrContentKey stretchedKey; | 510 GrUniqueKey stretchedKey; |
511 make_stretched_key(key, stretch, &stretchedKey); | 511 make_stretched_key(key, stretch, &stretchedKey); |
512 return ctx->isResourceInCache(stretchedKey); | 512 return ctx->isResourceInCache(stretchedKey); |
513 } | 513 } |
514 | 514 |
515 // We don't cache volatile bitmaps | 515 // We don't cache volatile bitmaps |
516 if (bitmap.isVolatile()) { | 516 if (bitmap.isVolatile()) { |
517 return false; | 517 return false; |
518 } | 518 } |
519 | 519 |
520 GrContentKey key, stretchedKey; | 520 GrUniqueKey key, stretchedKey; |
521 make_bitmap_keys(bitmap, stretch, &key, &stretchedKey); | 521 make_bitmap_keys(bitmap, stretch, &key, &stretchedKey); |
522 return ctx->isResourceInCache((kNo_Stretch == stretch) ? key : stretchedKey)
; | 522 return ctx->isResourceInCache((kNo_Stretch == stretch) ? key : stretchedKey)
; |
523 } | 523 } |
524 | 524 |
525 GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, | 525 GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, |
526 const SkBitmap& bitmap, | 526 const SkBitmap& bitmap, |
527 const GrTextureParams* params) { | 527 const GrTextureParams* params) { |
528 | 528 |
529 Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), par
ams); | 529 Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), par
ams); |
530 | 530 |
531 GrTexture* result = bitmap.getTexture(); | 531 GrTexture* result = bitmap.getTexture(); |
532 if (result) { | 532 if (result) { |
533 if (kNo_Stretch == stretch) { | 533 if (kNo_Stretch == stretch) { |
534 return SkRef(result); | 534 return SkRef(result); |
535 } | 535 } |
536 GrContentKey stretchedKey; | 536 GrUniqueKey stretchedKey; |
537 // Don't create a key for the resized version if the bmp is volatile. | 537 // Don't create a key for the resized version if the bmp is volatile. |
538 if (!bitmap.isVolatile()) { | 538 if (!bitmap.isVolatile()) { |
539 const GrContentKey& key = result->getContentKey(); | 539 const GrUniqueKey& key = result->getUniqueKey(); |
540 if (key.isValid()) { | 540 if (key.isValid()) { |
541 make_stretched_key(key, stretch, &stretchedKey); | 541 make_stretched_key(key, stretch, &stretchedKey); |
542 GrTexture* stretched = ctx->findAndRefCachedTexture(stretchedKey
); | 542 GrTexture* stretched = ctx->findAndRefCachedTexture(stretchedKey
); |
543 if (stretched) { | 543 if (stretched) { |
544 return stretched; | 544 return stretched; |
545 } | 545 } |
546 } | 546 } |
547 } | 547 } |
548 return stretch_texture_to_next_pot(result, stretch, bitmap.pixelRef(), s
tretchedKey); | 548 return stretch_texture_to_next_pot(result, stretch, bitmap.pixelRef(), s
tretchedKey); |
549 } | 549 } |
550 | 550 |
551 GrContentKey key, resizedKey; | 551 GrUniqueKey key, resizedKey; |
552 | 552 |
553 if (!bitmap.isVolatile()) { | 553 if (!bitmap.isVolatile()) { |
554 // If the bitmap isn't changing try to find a cached copy first. | 554 // If the bitmap isn't changing try to find a cached copy first. |
555 make_bitmap_keys(bitmap, stretch, &key, &resizedKey); | 555 make_bitmap_keys(bitmap, stretch, &key, &resizedKey); |
556 | 556 |
557 result = ctx->findAndRefCachedTexture(resizedKey.isValid() ? resizedKey
: key); | 557 result = ctx->findAndRefCachedTexture(resizedKey.isValid() ? resizedKey
: key); |
558 if (result) { | 558 if (result) { |
559 return result; | 559 return result; |
560 } | 560 } |
561 } | 561 } |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 if (shader->asFragmentProcessor(context, skPaint, viewM, NULL, &paintCol
or, &fp) && fp) { | 718 if (shader->asFragmentProcessor(context, skPaint, viewM, NULL, &paintCol
or, &fp) && fp) { |
719 grPaint->addColorProcessor(fp)->unref(); | 719 grPaint->addColorProcessor(fp)->unref(); |
720 constantColor = false; | 720 constantColor = false; |
721 } | 721 } |
722 } | 722 } |
723 | 723 |
724 // The grcolor is automatically set when calling asFragmentProcessor. | 724 // The grcolor is automatically set when calling asFragmentProcessor. |
725 // If the shader can be seen as an effect it returns true and adds its effec
t to the grpaint. | 725 // If the shader can be seen as an effect it returns true and adds its effec
t to the grpaint. |
726 SkPaint2GrPaintNoShader(context, rt, skPaint, paintColor, constantColor, grP
aint); | 726 SkPaint2GrPaintNoShader(context, rt, skPaint, paintColor, constantColor, grP
aint); |
727 } | 727 } |
OLD | NEW |