Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: src/pipe/SkGPipeWrite.cpp

Issue 831253002: Revert of Revert of move remaining virtual draw methods to onDraw (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkRecorder.cpp ('k') | src/utils/SkDeferredCanvas.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
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 "SkAnnotation.h" 9 #include "SkAnnotation.h"
10 #include "SkBitmapDevice.h" 10 #include "SkBitmapDevice.h"
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 fDone = true; 224 fDone = true;
225 } 225 }
226 226
227 void flushRecording(bool detachCurrentBlock); 227 void flushRecording(bool detachCurrentBlock);
228 size_t freeMemoryIfPossible(size_t bytesToFree); 228 size_t freeMemoryIfPossible(size_t bytesToFree);
229 229
230 size_t storageAllocatedForRecording() { 230 size_t storageAllocatedForRecording() {
231 return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated(); 231 return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated();
232 } 232 }
233 233
234 // overrides from SkCanvas
235 virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
236 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
237 const SkPaint&) SK_OVERRIDE;
238 virtual void drawOval(const SkRect&, const SkPaint&) SK_OVERRIDE;
239 virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE;
240 virtual void drawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE;
241 virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
242 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
243 const SkPaint*) SK_OVERRIDE;
244 virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src,
245 const SkRect& dst, const SkPaint* paint,
246 DrawBitmapRectFlags flags) SK_OVERRIDE;
247 virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
248 const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE;
249 virtual void drawSprite(const SkBitmap&, int left, int top,
250 const SkPaint*) SK_OVERRIDE;
251 virtual void drawVertices(VertexMode, int vertexCount,
252 const SkPoint vertices[], const SkPoint texs[],
253 const SkColor colors[], SkXfermode*,
254 const uint16_t indices[], int indexCount,
255 const SkPaint&) SK_OVERRIDE;
256 virtual void beginCommentGroup(const char* description) SK_OVERRIDE; 234 virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
257 virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE; 235 virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
258 virtual void endCommentGroup() SK_OVERRIDE; 236 virtual void endCommentGroup() SK_OVERRIDE;
259 237
260 /** 238 /**
261 * Flatten an SkBitmap to send to the reader, where it will be referenced 239 * Flatten an SkBitmap to send to the reader, where it will be referenced
262 * according to slot. 240 * according to slot.
263 */ 241 */
264 bool shuttleBitmap(const SkBitmap&, int32_t slot); 242 bool shuttleBitmap(const SkBitmap&, int32_t slot);
265 243
(...skipping 12 matching lines...) Expand all
278 const SkPaint&) SK_OVERRIDE; 256 const SkPaint&) SK_OVERRIDE;
279 virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkSca lar xpos[], 257 virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkSca lar xpos[],
280 SkScalar constY, const SkPaint&) SK_OVERRIDE; 258 SkScalar constY, const SkPaint&) SK_OVERRIDE;
281 virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkP ath& path, 259 virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkP ath& path,
282 const SkMatrix* matrix, const SkPaint&) SK_OVE RRIDE; 260 const SkMatrix* matrix, const SkPaint&) SK_OVE RRIDE;
283 virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 261 virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
284 const SkPaint& paint) SK_OVERRIDE; 262 const SkPaint& paint) SK_OVERRIDE;
285 virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 263 virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
286 const SkPoint texCoords[4], SkXfermode* xmode, 264 const SkPoint texCoords[4], SkXfermode* xmode,
287 const SkPaint& paint) SK_OVERRIDE; 265 const SkPaint& paint) SK_OVERRIDE;
266 void onDrawPaint(const SkPaint&) SK_OVERRIDE;
267 void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPain t&) SK_OVERRIDE;
268 void onDrawRect(const SkRect&, const SkPaint&) SK_OVERRIDE;
269 void onDrawOval(const SkRect&, const SkPaint&) SK_OVERRIDE;
270 void onDrawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE;
271 void onDrawPath(const SkPath&, const SkPaint&) SK_OVERRIDE;
272 void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPain t*) SK_OVERRIDE;
273 void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
274 DrawBitmapRectFlags flags) SK_OVERRIDE;
275 #if 0
276 // rely on decomposition into bitmap (for now)
277 void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint* ) SK_OVERRIDE;
278 void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
279 const SkPaint*) SK_OVERRIDE;
280 #endif
281 void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
282 const SkPaint*) SK_OVERRIDE;
283 void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) SK_OVE RRIDE;
284 void onDrawVertices(VertexMode vmode, int vertexCount,
285 const SkPoint vertices[], const SkPoint texs[],
286 const SkColor colors[], SkXfermode* xmode,
287 const uint16_t indices[], int indexCount,
288 const SkPaint&) SK_OVERRIDE;
288 virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERR IDE; 289 virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERR IDE;
289 virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVE RRIDE; 290 virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVE RRIDE;
290 virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERR IDE; 291 virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERR IDE;
291 virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE; 292 virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
292 293
293 virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint* ) SK_OVERRIDE; 294 virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint* ) SK_OVERRIDE;
294 295
295 private: 296 private:
296 void recordTranslate(const SkMatrix&); 297 void recordTranslate(const SkMatrix&);
297 void recordScale(const SkMatrix&); 298 void recordScale(const SkMatrix&);
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 NOTIFY_SETUP(this); 662 NOTIFY_SETUP(this);
662 if (this->needOpBytes(region.writeToMemory(NULL))) { 663 if (this->needOpBytes(region.writeToMemory(NULL))) {
663 this->writeOp(kClipRegion_DrawOp, 0, rgnOp); 664 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
664 fWriter.writeRegion(region); 665 fWriter.writeRegion(region);
665 } 666 }
666 this->INHERITED::onClipRegion(region, rgnOp); 667 this->INHERITED::onClipRegion(region, rgnOp);
667 } 668 }
668 669
669 /////////////////////////////////////////////////////////////////////////////// 670 ///////////////////////////////////////////////////////////////////////////////
670 671
671 void SkGPipeCanvas::drawPaint(const SkPaint& paint) { 672 void SkGPipeCanvas::onDrawPaint(const SkPaint& paint) {
672 NOTIFY_SETUP(this); 673 NOTIFY_SETUP(this);
673 this->writePaint(paint); 674 this->writePaint(paint);
674 if (this->needOpBytes()) { 675 if (this->needOpBytes()) {
675 this->writeOp(kDrawPaint_DrawOp); 676 this->writeOp(kDrawPaint_DrawOp);
676 } 677 }
677 } 678 }
678 679
679 void SkGPipeCanvas::drawPoints(PointMode mode, size_t count, 680 void SkGPipeCanvas::onDrawPoints(PointMode mode, size_t count,
680 const SkPoint pts[], const SkPaint& paint) { 681 const SkPoint pts[], const SkPaint& paint) {
681 if (count) { 682 if (count) {
682 NOTIFY_SETUP(this); 683 NOTIFY_SETUP(this);
683 this->writePaint(paint); 684 this->writePaint(paint);
684 if (this->needOpBytes(4 + count * sizeof(SkPoint))) { 685 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
685 this->writeOp(kDrawPoints_DrawOp, mode, 0); 686 this->writeOp(kDrawPoints_DrawOp, mode, 0);
686 fWriter.write32(SkToU32(count)); 687 fWriter.write32(SkToU32(count));
687 fWriter.write(pts, count * sizeof(SkPoint)); 688 fWriter.write(pts, count * sizeof(SkPoint));
688 } 689 }
689 } 690 }
690 } 691 }
691 692
692 void SkGPipeCanvas::drawOval(const SkRect& rect, const SkPaint& paint) { 693 void SkGPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
693 NOTIFY_SETUP(this); 694 NOTIFY_SETUP(this);
694 this->writePaint(paint); 695 this->writePaint(paint);
695 if (this->needOpBytes(sizeof(SkRect))) { 696 if (this->needOpBytes(sizeof(SkRect))) {
696 this->writeOp(kDrawOval_DrawOp); 697 this->writeOp(kDrawOval_DrawOp);
697 fWriter.writeRect(rect); 698 fWriter.writeRect(rect);
698 } 699 }
699 } 700 }
700 701
701 void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { 702 void SkGPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
702 NOTIFY_SETUP(this); 703 NOTIFY_SETUP(this);
703 this->writePaint(paint); 704 this->writePaint(paint);
704 if (this->needOpBytes(sizeof(SkRect))) { 705 if (this->needOpBytes(sizeof(SkRect))) {
705 this->writeOp(kDrawRect_DrawOp); 706 this->writeOp(kDrawRect_DrawOp);
706 fWriter.writeRect(rect); 707 fWriter.writeRect(rect);
707 } 708 }
708 } 709 }
709 710
710 void SkGPipeCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 711 void SkGPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
711 NOTIFY_SETUP(this); 712 NOTIFY_SETUP(this);
712 this->writePaint(paint); 713 this->writePaint(paint);
713 if (this->needOpBytes(kSizeOfFlatRRect)) { 714 if (this->needOpBytes(kSizeOfFlatRRect)) {
714 this->writeOp(kDrawRRect_DrawOp); 715 this->writeOp(kDrawRRect_DrawOp);
715 fWriter.writeRRect(rrect); 716 fWriter.writeRRect(rrect);
716 } 717 }
717 } 718 }
718 719
719 void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 720 void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
720 const SkPaint& paint) { 721 const SkPaint& paint) {
721 NOTIFY_SETUP(this); 722 NOTIFY_SETUP(this);
722 this->writePaint(paint); 723 this->writePaint(paint);
723 if (this->needOpBytes(kSizeOfFlatRRect * 2)) { 724 if (this->needOpBytes(kSizeOfFlatRRect * 2)) {
724 this->writeOp(kDrawDRRect_DrawOp); 725 this->writeOp(kDrawDRRect_DrawOp);
725 fWriter.writeRRect(outer); 726 fWriter.writeRRect(outer);
726 fWriter.writeRRect(inner); 727 fWriter.writeRRect(inner);
727 } 728 }
728 } 729 }
729 730
730 void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 731 void SkGPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
731 NOTIFY_SETUP(this); 732 NOTIFY_SETUP(this);
732 this->writePaint(paint); 733 this->writePaint(paint);
733 if (this->needOpBytes(path.writeToMemory(NULL))) { 734 if (this->needOpBytes(path.writeToMemory(NULL))) {
734 this->writeOp(kDrawPath_DrawOp); 735 this->writeOp(kDrawPath_DrawOp);
735 fWriter.writePath(path); 736 fWriter.writePath(path);
736 } 737 }
737 } 738 }
738 739
739 bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op, 740 bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op,
740 unsigned flags, 741 unsigned flags,
(...skipping 15 matching lines...) Expand all
756 return false; 757 return false;
757 } 758 }
758 759
759 if (this->needOpBytes(opBytesNeeded)) { 760 if (this->needOpBytes(opBytesNeeded)) {
760 this->writeOp(op, flags, bitmapIndex); 761 this->writeOp(op, flags, bitmapIndex);
761 return true; 762 return true;
762 } 763 }
763 return false; 764 return false;
764 } 765 }
765 766
766 void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top, 767 void SkGPipeCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top ,
767 const SkPaint* paint) { 768 const SkPaint* paint) {
768 NOTIFY_SETUP(this); 769 NOTIFY_SETUP(this);
769 size_t opBytesNeeded = sizeof(SkScalar) * 2; 770 size_t opBytesNeeded = sizeof(SkScalar) * 2;
770 771
771 if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint)) { 772 if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint)) {
772 fWriter.writeScalar(left); 773 fWriter.writeScalar(left);
773 fWriter.writeScalar(top); 774 fWriter.writeScalar(top);
774 } 775 }
775 } 776 }
776 777
777 void SkGPipeCanvas::drawBitmapRectToRect(const SkBitmap& bm, const SkRect* src, 778 void SkGPipeCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, cons t SkRect& dst,
778 const SkRect& dst, const SkPaint* paint , 779 const SkPaint* paint, DrawBitmapRectFlags d bmrFlags) {
779 DrawBitmapRectFlags dbmrFlags) {
780 NOTIFY_SETUP(this); 780 NOTIFY_SETUP(this);
781 size_t opBytesNeeded = sizeof(SkRect); 781 size_t opBytesNeeded = sizeof(SkRect);
782 bool hasSrc = src != NULL; 782 bool hasSrc = src != NULL;
783 unsigned flags; 783 unsigned flags;
784 if (hasSrc) { 784 if (hasSrc) {
785 flags = kDrawBitmap_HasSrcRect_DrawOpFlag; 785 flags = kDrawBitmap_HasSrcRect_DrawOpFlag;
786 opBytesNeeded += sizeof(int32_t) * 4; 786 opBytesNeeded += sizeof(int32_t) * 4;
787 } else { 787 } else {
788 flags = 0; 788 flags = 0;
789 } 789 }
790 if (dbmrFlags & kBleed_DrawBitmapRectFlag) { 790 if (dbmrFlags & kBleed_DrawBitmapRectFlag) {
791 flags |= kDrawBitmap_Bleed_DrawOpFlag; 791 flags |= kDrawBitmap_Bleed_DrawOpFlag;
792 } 792 }
793 793
794 if (this->commonDrawBitmap(bm, kDrawBitmapRectToRect_DrawOp, flags, opBytesN eeded, paint)) { 794 if (this->commonDrawBitmap(bm, kDrawBitmapRectToRect_DrawOp, flags, opBytesN eeded, paint)) {
795 if (hasSrc) { 795 if (hasSrc) {
796 fWriter.writeRect(*src); 796 fWriter.writeRect(*src);
797 } 797 }
798 fWriter.writeRect(dst); 798 fWriter.writeRect(dst);
799 } 799 }
800 } 800 }
801 801
802 void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center, 802 void SkGPipeCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center,
803 const SkRect& dst, const SkPaint* paint) { 803 const SkRect& dst, const SkPaint* paint) {
804 NOTIFY_SETUP(this); 804 NOTIFY_SETUP(this);
805 size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect); 805 size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect);
806 806
807 if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, pai nt)) { 807 if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, pai nt)) {
808 fWriter.write32(center.fLeft); 808 fWriter.write32(center.fLeft);
809 fWriter.write32(center.fTop); 809 fWriter.write32(center.fTop);
810 fWriter.write32(center.fRight); 810 fWriter.write32(center.fRight);
811 fWriter.write32(center.fBottom); 811 fWriter.write32(center.fBottom);
812 fWriter.writeRect(dst); 812 fWriter.writeRect(dst);
813 } 813 }
814 } 814 }
815 815
816 void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top, 816 void SkGPipeCanvas::onDrawSprite(const SkBitmap& bm, int left, int top, const Sk Paint* paint) {
817 const SkPaint* paint) {
818 NOTIFY_SETUP(this); 817 NOTIFY_SETUP(this);
819 size_t opBytesNeeded = sizeof(int32_t) * 2; 818 size_t opBytesNeeded = sizeof(int32_t) * 2;
820 819
821 if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) { 820 if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) {
822 fWriter.write32(left); 821 fWriter.write32(left);
823 fWriter.write32(top); 822 fWriter.write32(top);
824 } 823 }
825 } 824 }
826 825
827 void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 826 void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matr ix, 972 void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matr ix,
974 const SkPaint* paint) { 973 const SkPaint* paint) {
975 // we want to playback the picture into individual draw calls 974 // we want to playback the picture into individual draw calls
976 // 975 //
977 // todo: do we always have to unroll? If the pipe is not cross-process, seem s like 976 // todo: do we always have to unroll? If the pipe is not cross-process, seem s like
978 // we could just ref the picture and move on...? <reed, scroggo> 977 // we could just ref the picture and move on...? <reed, scroggo>
979 // 978 //
980 this->INHERITED::onDrawPicture(picture, matrix, paint); 979 this->INHERITED::onDrawPicture(picture, matrix, paint);
981 } 980 }
982 981
983 void SkGPipeCanvas::drawVertices(VertexMode vmode, int vertexCount, 982 void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
984 const SkPoint vertices[], const SkPoint texs[], 983 const SkPoint vertices[], const SkPoint texs[ ],
985 const SkColor colors[], SkXfermode* xfer, 984 const SkColor colors[], SkXfermode* xfer,
986 const uint16_t indices[], int indexCount, 985 const uint16_t indices[], int indexCount,
987 const SkPaint& paint) { 986 const SkPaint& paint) {
988 if (0 == vertexCount) { 987 if (0 == vertexCount) {
989 return; 988 return;
990 } 989 }
991 990
992 NOTIFY_SETUP(this); 991 NOTIFY_SETUP(this);
993 this->writePaint(paint); 992 this->writePaint(paint);
994 993
995 unsigned flags = 0; // packs with the op, so needs no extra space 994 unsigned flags = 0; // packs with the op, so needs no extra space
996 995
997 size_t size = 0; 996 size_t size = 0;
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
1331 return fCanvas->shuttleBitmap(bitmap, slot); 1330 return fCanvas->shuttleBitmap(bitmap, slot);
1332 } 1331 }
1333 1332
1334 void BitmapShuttle::removeCanvas() { 1333 void BitmapShuttle::removeCanvas() {
1335 if (NULL == fCanvas) { 1334 if (NULL == fCanvas) {
1336 return; 1335 return;
1337 } 1336 }
1338 fCanvas->unref(); 1337 fCanvas->unref();
1339 fCanvas = NULL; 1338 fCanvas = NULL;
1340 } 1339 }
OLDNEW
« no previous file with comments | « src/core/SkRecorder.cpp ('k') | src/utils/SkDeferredCanvas.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698