OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "SkPaint.h" | 9 #include "SkPaint.h" |
10 #include "SkAnnotation.h" | 10 #include "SkAnnotation.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "SkStringUtils.h" | 30 #include "SkStringUtils.h" |
31 #include "SkStroke.h" | 31 #include "SkStroke.h" |
32 #include "SkTextFormatParams.h" | 32 #include "SkTextFormatParams.h" |
33 #include "SkTextToPathIter.h" | 33 #include "SkTextToPathIter.h" |
34 #include "SkTLazy.h" | 34 #include "SkTLazy.h" |
35 #include "SkTypeface.h" | 35 #include "SkTypeface.h" |
36 #include "SkXfermode.h" | 36 #include "SkXfermode.h" |
37 | 37 |
38 enum { | 38 enum { |
39 kColor_DirtyBit = 1 << 0, | 39 kColor_DirtyBit = 1 << 0, |
40 kBitfields_DirtyBit = 1 << 1, | 40 kTextSize_DirtyBit = 1 << 1, |
41 kTextSize_DirtyBit = 1 << 2, | 41 kTextScaleX_DirtyBit = 1 << 2, |
42 kTextScaleX_DirtyBit = 1 << 3, | 42 kTextSkewX_DirtyBit = 1 << 3, |
43 kTextSkewX_DirtyBit = 1 << 4, | 43 kStrokeWidth_DirtyBit = 1 << 4, |
44 kStrokeWidth_DirtyBit = 1 << 5, | 44 kStrokeMiter_DirtyBit = 1 << 5, |
45 kStrokeMiter_DirtyBit = 1 << 6, | 45 |
46 kPathEffect_DirtyBit = 1 << 7, | 46 kPOD_DirtyBitMask = 63, |
47 kShader_DirtyBit = 1 << 8, | 47 |
48 kXfermode_DirtyBit = 1 << 9, | 48 kPathEffect_DirtyBit = 1 << 6, |
49 kMaskFilter_DirtyBit = 1 << 10, | 49 kShader_DirtyBit = 1 << 7, |
50 kColorFilter_DirtyBit = 1 << 11, | 50 kXfermode_DirtyBit = 1 << 8, |
51 kRasterizer_DirtyBit = 1 << 12, | 51 kMaskFilter_DirtyBit = 1 << 9, |
52 kLooper_DirtyBit = 1 << 13, | 52 kColorFilter_DirtyBit = 1 << 10, |
53 kImageFilter_DirtyBit = 1 << 14, | 53 kRasterizer_DirtyBit = 1 << 11, |
54 kTypeface_DirtyBit = 1 << 15, | 54 kLooper_DirtyBit = 1 << 12, |
55 kAnnotation_DirtyBit = 1 << 16, | 55 kImageFilter_DirtyBit = 1 << 13, |
56 kPaintOptionsAndroid_DirtyBit = 1 << 17, | 56 kTypeface_DirtyBit = 1 << 14, |
| 57 kAnnotation_DirtyBit = 1 << 15, |
| 58 kPaintOptionsAndroid_DirtyBit = 1 << 16, |
57 }; | 59 }; |
58 | 60 |
59 // define this to get a printf for out-of-range parameter in setters | 61 // define this to get a printf for out-of-range parameter in setters |
60 // e.g. setTextSize(-1) | 62 // e.g. setTextSize(-1) |
61 //#define SK_REPORT_API_RANGE_CHECK | 63 //#define SK_REPORT_API_RANGE_CHECK |
62 | 64 |
63 #ifdef SK_BUILD_FOR_ANDROID | 65 #ifdef SK_BUILD_FOR_ANDROID |
64 #define GEN_ID_INC fGenerationID++ | 66 #define GEN_ID_INC fGenerationID++ |
65 #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; } | 67 #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; } |
66 #else | 68 #else |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 fPaintOptionsAndroid = options; | 249 fPaintOptionsAndroid = options; |
248 GEN_ID_INC; | 250 GEN_ID_INC; |
249 fDirtyBits |= kPaintOptionsAndroid_DirtyBit; | 251 fDirtyBits |= kPaintOptionsAndroid_DirtyBit; |
250 } | 252 } |
251 } | 253 } |
252 #endif | 254 #endif |
253 | 255 |
254 void SkPaint::setFilterLevel(FilterLevel level) { | 256 void SkPaint::setFilterLevel(FilterLevel level) { |
255 GEN_ID_INC_EVAL((unsigned) level != fFilterLevel); | 257 GEN_ID_INC_EVAL((unsigned) level != fFilterLevel); |
256 fFilterLevel = level; | 258 fFilterLevel = level; |
257 fDirtyBits |= kBitfields_DirtyBit; | |
258 } | 259 } |
259 | 260 |
260 void SkPaint::setHinting(Hinting hintingLevel) { | 261 void SkPaint::setHinting(Hinting hintingLevel) { |
261 GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting); | 262 GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting); |
262 fHinting = hintingLevel; | 263 fHinting = hintingLevel; |
263 fDirtyBits |= kBitfields_DirtyBit; | |
264 } | 264 } |
265 | 265 |
266 void SkPaint::setFlags(uint32_t flags) { | 266 void SkPaint::setFlags(uint32_t flags) { |
267 GEN_ID_INC_EVAL(fFlags != flags); | 267 GEN_ID_INC_EVAL(fFlags != flags); |
268 fFlags = flags; | 268 fFlags = flags; |
269 fDirtyBits |= kBitfields_DirtyBit; | |
270 } | 269 } |
271 | 270 |
272 void SkPaint::setAntiAlias(bool doAA) { | 271 void SkPaint::setAntiAlias(bool doAA) { |
273 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); | 272 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); |
274 } | 273 } |
275 | 274 |
276 void SkPaint::setDither(bool doDither) { | 275 void SkPaint::setDither(bool doDither) { |
277 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); | 276 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); |
278 } | 277 } |
279 | 278 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 } | 317 } |
319 | 318 |
320 void SkPaint::setDistanceFieldTextTEMP(bool doDistanceFieldText) { | 319 void SkPaint::setDistanceFieldTextTEMP(bool doDistanceFieldText) { |
321 this->setFlags(SkSetClearMask(fFlags, doDistanceFieldText, kDistanceFieldTex
tTEMP_Flag)); | 320 this->setFlags(SkSetClearMask(fFlags, doDistanceFieldText, kDistanceFieldTex
tTEMP_Flag)); |
322 } | 321 } |
323 | 322 |
324 void SkPaint::setStyle(Style style) { | 323 void SkPaint::setStyle(Style style) { |
325 if ((unsigned)style < kStyleCount) { | 324 if ((unsigned)style < kStyleCount) { |
326 GEN_ID_INC_EVAL((unsigned)style != fStyle); | 325 GEN_ID_INC_EVAL((unsigned)style != fStyle); |
327 fStyle = style; | 326 fStyle = style; |
328 fDirtyBits |= kBitfields_DirtyBit; | |
329 } else { | 327 } else { |
330 #ifdef SK_REPORT_API_RANGE_CHECK | 328 #ifdef SK_REPORT_API_RANGE_CHECK |
331 SkDebugf("SkPaint::setStyle(%d) out of range\n", style); | 329 SkDebugf("SkPaint::setStyle(%d) out of range\n", style); |
332 #endif | 330 #endif |
333 } | 331 } |
334 } | 332 } |
335 | 333 |
336 void SkPaint::setColor(SkColor color) { | 334 void SkPaint::setColor(SkColor color) { |
337 GEN_ID_INC_EVAL(color != fColor); | 335 GEN_ID_INC_EVAL(color != fColor); |
338 fColor = color; | 336 fColor = color; |
(...skipping 30 matching lines...) Expand all Loading... |
369 #ifdef SK_REPORT_API_RANGE_CHECK | 367 #ifdef SK_REPORT_API_RANGE_CHECK |
370 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); | 368 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); |
371 #endif | 369 #endif |
372 } | 370 } |
373 } | 371 } |
374 | 372 |
375 void SkPaint::setStrokeCap(Cap ct) { | 373 void SkPaint::setStrokeCap(Cap ct) { |
376 if ((unsigned)ct < kCapCount) { | 374 if ((unsigned)ct < kCapCount) { |
377 GEN_ID_INC_EVAL((unsigned)ct != fCapType); | 375 GEN_ID_INC_EVAL((unsigned)ct != fCapType); |
378 fCapType = SkToU8(ct); | 376 fCapType = SkToU8(ct); |
379 fDirtyBits |= kBitfields_DirtyBit; | |
380 } else { | 377 } else { |
381 #ifdef SK_REPORT_API_RANGE_CHECK | 378 #ifdef SK_REPORT_API_RANGE_CHECK |
382 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); | 379 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); |
383 #endif | 380 #endif |
384 } | 381 } |
385 } | 382 } |
386 | 383 |
387 void SkPaint::setStrokeJoin(Join jt) { | 384 void SkPaint::setStrokeJoin(Join jt) { |
388 if ((unsigned)jt < kJoinCount) { | 385 if ((unsigned)jt < kJoinCount) { |
389 GEN_ID_INC_EVAL((unsigned)jt != fJoinType); | 386 GEN_ID_INC_EVAL((unsigned)jt != fJoinType); |
390 fJoinType = SkToU8(jt); | 387 fJoinType = SkToU8(jt); |
391 fDirtyBits |= kBitfields_DirtyBit; | |
392 } else { | 388 } else { |
393 #ifdef SK_REPORT_API_RANGE_CHECK | 389 #ifdef SK_REPORT_API_RANGE_CHECK |
394 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); | 390 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); |
395 #endif | 391 #endif |
396 } | 392 } |
397 } | 393 } |
398 | 394 |
399 /////////////////////////////////////////////////////////////////////////////// | 395 /////////////////////////////////////////////////////////////////////////////// |
400 | 396 |
401 void SkPaint::setTextAlign(Align align) { | 397 void SkPaint::setTextAlign(Align align) { |
402 if ((unsigned)align < kAlignCount) { | 398 if ((unsigned)align < kAlignCount) { |
403 GEN_ID_INC_EVAL((unsigned)align != fTextAlign); | 399 GEN_ID_INC_EVAL((unsigned)align != fTextAlign); |
404 fTextAlign = SkToU8(align); | 400 fTextAlign = SkToU8(align); |
405 fDirtyBits |= kBitfields_DirtyBit; | |
406 } else { | 401 } else { |
407 #ifdef SK_REPORT_API_RANGE_CHECK | 402 #ifdef SK_REPORT_API_RANGE_CHECK |
408 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align); | 403 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align); |
409 #endif | 404 #endif |
410 } | 405 } |
411 } | 406 } |
412 | 407 |
413 void SkPaint::setTextSize(SkScalar ts) { | 408 void SkPaint::setTextSize(SkScalar ts) { |
414 if (ts >= 0) { | 409 if (ts >= 0) { |
415 GEN_ID_INC_EVAL(ts != fTextSize); | 410 GEN_ID_INC_EVAL(ts != fTextSize); |
(...skipping 15 matching lines...) Expand all Loading... |
431 void SkPaint::setTextSkewX(SkScalar skewX) { | 426 void SkPaint::setTextSkewX(SkScalar skewX) { |
432 GEN_ID_INC_EVAL(skewX != fTextSkewX); | 427 GEN_ID_INC_EVAL(skewX != fTextSkewX); |
433 fTextSkewX = skewX; | 428 fTextSkewX = skewX; |
434 fDirtyBits |= kTextSkewX_DirtyBit; | 429 fDirtyBits |= kTextSkewX_DirtyBit; |
435 } | 430 } |
436 | 431 |
437 void SkPaint::setTextEncoding(TextEncoding encoding) { | 432 void SkPaint::setTextEncoding(TextEncoding encoding) { |
438 if ((unsigned)encoding <= kGlyphID_TextEncoding) { | 433 if ((unsigned)encoding <= kGlyphID_TextEncoding) { |
439 GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding); | 434 GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding); |
440 fTextEncoding = encoding; | 435 fTextEncoding = encoding; |
441 fDirtyBits |= kBitfields_DirtyBit; | |
442 } else { | 436 } else { |
443 #ifdef SK_REPORT_API_RANGE_CHECK | 437 #ifdef SK_REPORT_API_RANGE_CHECK |
444 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding); | 438 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding); |
445 #endif | 439 #endif |
446 } | 440 } |
447 } | 441 } |
448 | 442 |
449 /////////////////////////////////////////////////////////////////////////////// | 443 /////////////////////////////////////////////////////////////////////////////// |
450 | 444 |
451 // Returns dst with the given bitmask enabled or disabled, depending on value. | 445 // Returns dst with the given bitmask enabled or disabled, depending on value. |
(...skipping 2191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2643 return true; | 2637 return true; |
2644 default: | 2638 default: |
2645 break; | 2639 break; |
2646 } | 2640 } |
2647 } | 2641 } |
2648 return false; | 2642 return false; |
2649 } | 2643 } |
2650 | 2644 |
2651 void SkPaint::setBitfields(uint32_t bitfields) { | 2645 void SkPaint::setBitfields(uint32_t bitfields) { |
2652 fBitfields = bitfields; | 2646 fBitfields = bitfields; |
2653 fDirtyBits |= kBitfields_DirtyBit; | |
2654 } | 2647 } |
2655 | 2648 |
2656 inline static unsigned popcount(uint8_t x) { | 2649 inline static unsigned popcount(uint8_t x) { |
2657 // As in Hacker's delight, adapted for just 8 bits. | 2650 // As in Hacker's delight, adapted for just 8 bits. |
2658 x = (x & 0x55) + ((x >> 1) & 0x55); // a b c d w x y z -> a+b c+d w+x y+z | 2651 x = (x & 0x55) + ((x >> 1) & 0x55); // a b c d w x y z -> a+b c+d w+x y+z |
2659 x = (x & 0x33) + ((x >> 2) & 0x33); // a+b c+d w+x y+z -> a+b+c+d w+x+y+z | 2652 x = (x & 0x33) + ((x >> 2) & 0x33); // a+b c+d w+x y+z -> a+b+c+d w+x+y+z |
2660 x = (x & 0x0F) + ((x >> 4) & 0x0F); // a+b+c+d w+x+y+z -> a+b+c+d+w+x+y+z | 2653 x = (x & 0x0F) + ((x >> 4) & 0x0F); // a+b+c+d w+x+y+z -> a+b+c+d+w+x+y+z |
2661 return x; | 2654 return x; |
2662 } | 2655 } |
2663 | 2656 |
2664 void SkPaint::FlatteningTraits::Flatten(SkWriteBuffer& buffer, const SkPaint& pa
int) { | 2657 void SkPaint::FlatteningTraits::Flatten(SkWriteBuffer& buffer, const SkPaint& pa
int) { |
2665 const uint32_t dirty = paint.fDirtyBits; | 2658 const uint32_t dirty = paint.fDirtyBits; |
2666 | 2659 |
2667 // Each of the low 7 dirty bits corresponds to a 4-byte flat value, plus one
for the dirty bits. | 2660 // Each of the low 7 dirty bits corresponds to a 4-byte flat value, |
2668 const size_t flatBytes = 4 * (popcount(dirty & 127) + 1); | 2661 // plus one for the dirty bits and one for the bitfields |
| 2662 const size_t flatBytes = 4 * (popcount(dirty & kPOD_DirtyBitMask) + 2); |
2669 SkASSERT(flatBytes <= 32); | 2663 SkASSERT(flatBytes <= 32); |
2670 uint32_t* u32 = buffer.reserve(flatBytes); | 2664 uint32_t* u32 = buffer.reserve(flatBytes); |
2671 *u32++ = dirty; | 2665 *u32++ = dirty; |
2672 if (dirty == 0) { | 2666 *u32++ = paint.getBitfields(); |
| 2667 if (0 == dirty) { |
2673 return; | 2668 return; |
2674 } | 2669 } |
2675 | 2670 |
2676 #define F(dst, field) if (dirty & k##field##_DirtyBit) *dst++ = paint.get##field
() | 2671 #define F(dst, field) if (dirty & k##field##_DirtyBit) *dst++ = paint.get##field
() |
2677 F(u32, Color); | 2672 F(u32, Color); |
2678 F(u32, Bitfields); | |
2679 SkScalar* f32 = reinterpret_cast<SkScalar*>(u32); | 2673 SkScalar* f32 = reinterpret_cast<SkScalar*>(u32); |
2680 F(f32, TextSize); | 2674 F(f32, TextSize); |
2681 F(f32, TextScaleX); | 2675 F(f32, TextScaleX); |
2682 F(f32, TextSkewX); | 2676 F(f32, TextSkewX); |
2683 F(f32, StrokeWidth); | 2677 F(f32, StrokeWidth); |
2684 F(f32, StrokeMiter); | 2678 F(f32, StrokeMiter); |
2685 #undef F | 2679 #undef F |
2686 #define F(field) if (dirty & k##field##_DirtyBit) buffer.writeFlattenable(paint.
get##field()) | 2680 #define F(field) if (dirty & k##field##_DirtyBit) buffer.writeFlattenable(paint.
get##field()) |
2687 F(PathEffect); | 2681 F(PathEffect); |
2688 F(Shader); | 2682 F(Shader); |
2689 F(Xfermode); | 2683 F(Xfermode); |
2690 F(MaskFilter); | 2684 F(MaskFilter); |
2691 F(ColorFilter); | 2685 F(ColorFilter); |
2692 F(Rasterizer); | 2686 F(Rasterizer); |
2693 F(Looper); | 2687 F(Looper); |
2694 F(ImageFilter); | 2688 F(ImageFilter); |
2695 #undef F | 2689 #undef F |
2696 if (dirty & kTypeface_DirtyBit) buffer.writeTypeface(paint.getTypeface()); | 2690 if (dirty & kTypeface_DirtyBit) buffer.writeTypeface(paint.getTypeface()); |
2697 if (dirty & kAnnotation_DirtyBit) paint.getAnnotation()->writeToBuffer(buffe
r); | 2691 if (dirty & kAnnotation_DirtyBit) paint.getAnnotation()->writeToBuffer(buffe
r); |
2698 #ifdef SK_BUILD_FOR_ANDROID | 2692 #ifdef SK_BUILD_FOR_ANDROID |
2699 if (dirty & kPaintOptionsAndroid_DirtyBit) paint.getPaintOptionsAndroid().fl
atten(buffer); | 2693 if (dirty & kPaintOptionsAndroid_DirtyBit) paint.getPaintOptionsAndroid().fl
atten(buffer); |
2700 #endif | 2694 #endif |
2701 } | 2695 } |
2702 | 2696 |
2703 void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint)
{ | 2697 void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint)
{ |
2704 const uint32_t dirty = buffer.readUInt(); | 2698 const uint32_t dirty = buffer.readUInt(); |
| 2699 paint->setBitfields(buffer.readUInt()); |
2705 if (dirty == 0) { | 2700 if (dirty == 0) { |
2706 return; | 2701 return; |
2707 } | 2702 } |
2708 #define F(field, reader) if (dirty & k##field##_DirtyBit) paint->set##field(buff
er.reader()) | 2703 #define F(field, reader) if (dirty & k##field##_DirtyBit) paint->set##field(buff
er.reader()) |
2709 // Same function, except it unrefs the object newly set on the paint: | 2704 // Same function, except it unrefs the object newly set on the paint: |
2710 #define F_UNREF(field, reader) \ | 2705 #define F_UNREF(field, reader) \ |
2711 if (dirty & k##field##_DirtyBit) \ | 2706 if (dirty & k##field##_DirtyBit) \ |
2712 paint->set##field(buffer.reader())->unref() | 2707 paint->set##field(buffer.reader())->unref() |
2713 | 2708 |
2714 F(Color, readUInt); | 2709 F(Color, readUInt); |
2715 F(Bitfields, readUInt); | |
2716 F(TextSize, readScalar); | 2710 F(TextSize, readScalar); |
2717 F(TextScaleX, readScalar); | 2711 F(TextScaleX, readScalar); |
2718 F(TextSkewX, readScalar); | 2712 F(TextSkewX, readScalar); |
2719 F(StrokeWidth, readScalar); | 2713 F(StrokeWidth, readScalar); |
2720 F(StrokeMiter, readScalar); | 2714 F(StrokeMiter, readScalar); |
2721 F_UNREF(PathEffect, readPathEffect); | 2715 F_UNREF(PathEffect, readPathEffect); |
2722 F_UNREF(Shader, readShader); | 2716 F_UNREF(Shader, readShader); |
2723 F_UNREF(Xfermode, readXfermode); | 2717 F_UNREF(Xfermode, readXfermode); |
2724 F_UNREF(MaskFilter, readMaskFilter); | 2718 F_UNREF(MaskFilter, readMaskFilter); |
2725 F_UNREF(ColorFilter, readColorFilter); | 2719 F_UNREF(ColorFilter, readColorFilter); |
2726 F_UNREF(Rasterizer, readRasterizer); | 2720 F_UNREF(Rasterizer, readRasterizer); |
2727 F_UNREF(Looper, readDrawLooper); | 2721 F_UNREF(Looper, readDrawLooper); |
2728 F_UNREF(ImageFilter, readImageFilter); | 2722 F_UNREF(ImageFilter, readImageFilter); |
2729 F(Typeface, readTypeface); | 2723 F(Typeface, readTypeface); |
2730 #undef F | 2724 #undef F |
2731 #undef F_UNREF | 2725 #undef F_UNREF |
2732 if (dirty & kAnnotation_DirtyBit) { | 2726 if (dirty & kAnnotation_DirtyBit) { |
2733 paint->setAnnotation(SkAnnotation::Create(buffer))->unref(); | 2727 paint->setAnnotation(SkAnnotation::Create(buffer))->unref(); |
2734 } | 2728 } |
2735 #ifdef SK_BUILD_FOR_ANDROID | 2729 #ifdef SK_BUILD_FOR_ANDROID |
2736 if (dirty & kPaintOptionsAndroid_DirtyBit) { | 2730 if (dirty & kPaintOptionsAndroid_DirtyBit) { |
2737 SkPaintOptionsAndroid options; | 2731 SkPaintOptionsAndroid options; |
2738 options.unflatten(buffer); | 2732 options.unflatten(buffer); |
2739 paint->setPaintOptionsAndroid(options); | 2733 paint->setPaintOptionsAndroid(options); |
2740 } | 2734 } |
2741 #endif | 2735 #endif |
2742 SkASSERT(dirty == paint->fDirtyBits); | 2736 SkASSERT(dirty == paint->fDirtyBits); |
2743 } | 2737 } |
OLD | NEW |