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

Side by Side Diff: src/pdf/SkPDFFont.cpp

Issue 944643002: PDF: Now threadsafe! (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: TODO=DONE Created 5 years, 10 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/pdf/SkPDFFont.h ('k') | src/pdf/SkPDFFontImpl.h » ('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 * Copyright 2011 Google Inc. 2 * Copyright 2011 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 <ctype.h> 8 #include <ctype.h>
9 9
10 #include "SkData.h" 10 #include "SkData.h"
(...skipping 729 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 * 740 *
741 * Resources are canonicalized and uniqueified by pointer so there has to be 741 * Resources are canonicalized and uniqueified by pointer so there has to be
742 * some additional state indicating which subset of the font is used. It 742 * some additional state indicating which subset of the font is used. It
743 * must be maintained at the page granularity and then combined at the document 743 * must be maintained at the page granularity and then combined at the document
744 * granularity. a) change SkPDFFont to fill in its state on demand, kind of 744 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
745 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each 745 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
746 * page/pdf device. c) in the document, retrieve the per font glyph usage 746 * page/pdf device. c) in the document, retrieve the per font glyph usage
747 * from each page and combine it and ask for a resource with that subset. 747 * from each page and combine it and ask for a resource with that subset.
748 */ 748 */
749 749
750 SkPDFFont::~SkPDFFont() { 750 SkPDFFont::~SkPDFFont() { fCanon->removeFont(this); }
751 {
752 SkAutoMutexAcquire lock(SkPDFCanon::GetFontMutex());
753 SkPDFCanon::GetCanon().removeFont(this);
754 }
755 }
756 751
757 SkTypeface* SkPDFFont::typeface() { 752 SkTypeface* SkPDFFont::typeface() {
758 return fTypeface.get(); 753 return fTypeface.get();
759 } 754 }
760 755
761 SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() { 756 SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
762 return fFontType; 757 return fFontType;
763 } 758 }
764 759
765 bool SkPDFFont::canEmbed() const { 760 bool SkPDFFont::canEmbed() const {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
797 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) { 792 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
798 return i; 793 return i;
799 } 794 }
800 glyphIDs[i] -= (fFirstGlyphID - 1); 795 glyphIDs[i] -= (fFirstGlyphID - 1);
801 } 796 }
802 797
803 return numGlyphs; 798 return numGlyphs;
804 } 799 }
805 800
806 // static 801 // static
807 SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) { 802 SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
803 SkTypeface* typeface,
804 uint16_t glyphID) {
805 SkASSERT(canon);
808 SkAutoResolveDefaultTypeface autoResolve(typeface); 806 SkAutoResolveDefaultTypeface autoResolve(typeface);
809 typeface = autoResolve.get(); 807 typeface = autoResolve.get();
810 const uint32_t fontID = typeface->uniqueID(); 808 const uint32_t fontID = typeface->uniqueID();
811 809
812 SkAutoMutexAcquire lock(SkPDFCanon::GetFontMutex());
813 SkPDFFont* relatedFont; 810 SkPDFFont* relatedFont;
814 SkPDFFont* pdfFont = 811 if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) {
815 SkPDFCanon::GetCanon().findFont(fontID, glyphID, &relatedFont);
816 if (pdfFont) {
817 return SkRef(pdfFont); 812 return SkRef(pdfFont);
818 } 813 }
819 814
820 SkAutoTUnref<const SkAdvancedTypefaceMetrics> fontMetrics; 815 SkAutoTUnref<const SkAdvancedTypefaceMetrics> fontMetrics;
821 SkPDFDict* relatedFontDescriptor = NULL; 816 SkPDFDict* relatedFontDescriptor = NULL;
822 if (relatedFont) { 817 if (relatedFont) {
823 fontMetrics.reset(SkSafeRef(relatedFont->fontInfo())); 818 fontMetrics.reset(SkSafeRef(relatedFont->fontInfo()));
824 relatedFontDescriptor = relatedFont->getFontDescriptor(); 819 relatedFontDescriptor = relatedFont->getFontDescriptor();
825 820
826 // This only is to catch callers who pass invalid glyph ids. 821 // This only is to catch callers who pass invalid glyph ids.
(...skipping 23 matching lines...) Expand all
850 fontMetrics->fType != SkAdvancedTypefaceMetrics::kTrueType_Font) { 845 fontMetrics->fType != SkAdvancedTypefaceMetrics::kTrueType_Font) {
851 // Font does not support subsetting, get new info with advance. 846 // Font does not support subsetting, get new info with advance.
852 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>( 847 info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
853 info, SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo); 848 info, SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo);
854 fontMetrics.reset( 849 fontMetrics.reset(
855 typeface->getAdvancedTypefaceMetrics(info, NULL, 0)); 850 typeface->getAdvancedTypefaceMetrics(info, NULL, 0));
856 } 851 }
857 #endif 852 #endif
858 } 853 }
859 854
860 SkPDFFont* font = Create(fontMetrics.get(), typeface, glyphID, 855 SkPDFFont* font = SkPDFFont::Create(canon, fontMetrics.get(), typeface,
861 relatedFontDescriptor); 856 glyphID, relatedFontDescriptor);
862 SkPDFCanon::GetCanon().addFont(font, fontID, font->fFirstGlyphID); 857 canon->addFont(font, fontID, font->fFirstGlyphID);
863 return font; // Return the reference new SkPDFFont() created. 858 return font;
864 } 859 }
865 860
866 SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet*) { 861 SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
867 return NULL; // Default: no support. 862 return NULL; // Default: no support.
868 } 863 }
869 864
870 SkPDFFont::SkPDFFont(const SkAdvancedTypefaceMetrics* info, 865 SkPDFFont::SkPDFFont(SkPDFCanon* canon,
866 const SkAdvancedTypefaceMetrics* info,
871 SkTypeface* typeface, 867 SkTypeface* typeface,
872 SkPDFDict* relatedFontDescriptor) 868 SkPDFDict* relatedFontDescriptor)
873 : SkPDFDict("Font"), 869 : SkPDFDict("Font")
874 fTypeface(ref_or_default(typeface)), 870 , fCanon(canon)
875 fFirstGlyphID(1), 871 , fTypeface(ref_or_default(typeface))
876 fLastGlyphID(info ? info->fLastGlyphID : 0), 872 , fFirstGlyphID(1)
877 fFontInfo(SkSafeRef(info)), 873 , fLastGlyphID(info ? info->fLastGlyphID : 0)
878 fDescriptor(SkSafeRef(relatedFontDescriptor)) { 874 , fFontInfo(SkSafeRef(info))
875 , fDescriptor(SkSafeRef(relatedFontDescriptor)) {
879 if (info == NULL || 876 if (info == NULL ||
880 info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) { 877 info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) {
881 fFontType = SkAdvancedTypefaceMetrics::kOther_Font; 878 fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
882 } else { 879 } else {
883 fFontType = info->fType; 880 fFontType = info->fType;
884 } 881 }
885 } 882 }
886 883
887 // static 884 // static
888 SkPDFFont* SkPDFFont::Create(const SkAdvancedTypefaceMetrics* info, 885 SkPDFFont* SkPDFFont::Create(SkPDFCanon* canon,
889 SkTypeface* typeface, uint16_t glyphID, 886 const SkAdvancedTypefaceMetrics* info,
887 SkTypeface* typeface,
888 uint16_t glyphID,
890 SkPDFDict* relatedFontDescriptor) { 889 SkPDFDict* relatedFontDescriptor) {
891 SkAdvancedTypefaceMetrics::FontType type = 890 SkAdvancedTypefaceMetrics::FontType type =
892 info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font; 891 info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font;
893 892
894 if (info && 893 if (info &&
895 (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) { 894 (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
896 NOT_IMPLEMENTED(true, true); 895 NOT_IMPLEMENTED(true, true);
897 return new SkPDFType3Font(info, 896 return new SkPDFType3Font(canon, info, typeface, glyphID);
898 typeface,
899 glyphID);
900 } 897 }
901 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font || 898 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
902 type == SkAdvancedTypefaceMetrics::kTrueType_Font) { 899 type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
903 SkASSERT(relatedFontDescriptor == NULL); 900 SkASSERT(relatedFontDescriptor == NULL);
904 return new SkPDFType0Font(info, typeface); 901 return new SkPDFType0Font(canon, info, typeface);
905 } 902 }
906 if (type == SkAdvancedTypefaceMetrics::kType1_Font) { 903 if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
907 return new SkPDFType1Font(info, 904 return new SkPDFType1Font(canon, info, typeface, glyphID,
908 typeface,
909 glyphID,
910 relatedFontDescriptor); 905 relatedFontDescriptor);
911 } 906 }
912 907
913 SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font || 908 SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
914 type == SkAdvancedTypefaceMetrics::kOther_Font); 909 type == SkAdvancedTypefaceMetrics::kOther_Font);
915 910
916 return new SkPDFType3Font(info, typeface, glyphID); 911 return new SkPDFType3Font(canon, info, typeface, glyphID);
917 } 912 }
918 913
919 const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() { 914 const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
920 return fFontInfo.get(); 915 return fFontInfo.get();
921 } 916 }
922 917
923 void SkPDFFont::setFontInfo(const SkAdvancedTypefaceMetrics* info) { 918 void SkPDFFont::setFontInfo(const SkAdvancedTypefaceMetrics* info) {
924 if (info == NULL || info == fFontInfo.get()) { 919 if (info == NULL || info == fFontInfo.get()) {
925 return; 920 return;
926 } 921 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
994 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset, 989 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset,
995 multiByteGlyphs(), firstGlyphID(), 990 multiByteGlyphs(), firstGlyphID(),
996 lastGlyphID())); 991 lastGlyphID()));
997 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); 992 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
998 } 993 }
999 994
1000 /////////////////////////////////////////////////////////////////////////////// 995 ///////////////////////////////////////////////////////////////////////////////
1001 // class SkPDFType0Font 996 // class SkPDFType0Font
1002 /////////////////////////////////////////////////////////////////////////////// 997 ///////////////////////////////////////////////////////////////////////////////
1003 998
1004 SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, 999 SkPDFType0Font::SkPDFType0Font(SkPDFCanon* canon,
1000 const SkAdvancedTypefaceMetrics* info,
1005 SkTypeface* typeface) 1001 SkTypeface* typeface)
1006 : SkPDFFont(info, typeface, NULL) { 1002 : SkPDFFont(canon, info, typeface, NULL) {
1007 SkDEBUGCODE(fPopulated = false); 1003 SkDEBUGCODE(fPopulated = false);
1008 if (!canSubset()) { 1004 if (!canSubset()) {
1009 populate(NULL); 1005 populate(NULL);
1010 } 1006 }
1011 } 1007 }
1012 1008
1013 SkPDFType0Font::~SkPDFType0Font() {} 1009 SkPDFType0Font::~SkPDFType0Font() {}
1014 1010
1015 SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) { 1011 SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
1016 if (!canSubset()) { 1012 if (!canSubset()) {
1017 return NULL; 1013 return NULL;
1018 } 1014 }
1019 SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface()); 1015 SkPDFType0Font* newSubset =
1016 new SkPDFType0Font(fCanon, fontInfo(), typeface());
1020 newSubset->populate(subset); 1017 newSubset->populate(subset);
1021 return newSubset; 1018 return newSubset;
1022 } 1019 }
1023 1020
1024 #ifdef SK_DEBUG 1021 #ifdef SK_DEBUG
1025 void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { 1022 void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
1026 SkASSERT(fPopulated); 1023 SkASSERT(fPopulated);
1027 return INHERITED::emitObject(stream, catalog); 1024 return INHERITED::emitObject(stream, catalog);
1028 } 1025 }
1029 #endif 1026 #endif
1030 1027
1031 bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { 1028 bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
1032 insertName("Subtype", "Type0"); 1029 insertName("Subtype", "Type0");
1033 insertName("BaseFont", fontInfo()->fFontName); 1030 insertName("BaseFont", fontInfo()->fFontName);
1034 insertName("Encoding", "Identity-H"); 1031 insertName("Encoding", "Identity-H");
1035 1032
1036 SkAutoTUnref<SkPDFCIDFont> newCIDFont( 1033 SkAutoTUnref<SkPDFCIDFont> newCIDFont(
1037 new SkPDFCIDFont(fontInfo(), typeface(), subset)); 1034 new SkPDFCIDFont(fCanon, fontInfo(), typeface(), subset));
1038 SkAutoTUnref<SkPDFArray> descendantFonts(new SkPDFArray()); 1035 SkAutoTUnref<SkPDFArray> descendantFonts(new SkPDFArray());
1039 descendantFonts->append(new SkPDFObjRef(newCIDFont.get()))->unref(); 1036 descendantFonts->append(new SkPDFObjRef(newCIDFont.get()))->unref();
1040 insert("DescendantFonts", descendantFonts.get()); 1037 insert("DescendantFonts", descendantFonts.get());
1041 1038
1042 populateToUnicodeTable(subset); 1039 populateToUnicodeTable(subset);
1043 1040
1044 SkDEBUGCODE(fPopulated = true); 1041 SkDEBUGCODE(fPopulated = true);
1045 return true; 1042 return true;
1046 } 1043 }
1047 1044
1048 /////////////////////////////////////////////////////////////////////////////// 1045 ///////////////////////////////////////////////////////////////////////////////
1049 // class SkPDFCIDFont 1046 // class SkPDFCIDFont
1050 /////////////////////////////////////////////////////////////////////////////// 1047 ///////////////////////////////////////////////////////////////////////////////
1051 1048
1052 SkPDFCIDFont::SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info, 1049 SkPDFCIDFont::SkPDFCIDFont(SkPDFCanon* canon,
1053 SkTypeface* typeface, const SkPDFGlyphSet* subset) 1050 const SkAdvancedTypefaceMetrics* info,
1054 : SkPDFFont(info, typeface, NULL) { 1051 SkTypeface* typeface,
1052 const SkPDFGlyphSet* subset)
1053 : SkPDFFont(canon, info, typeface, NULL) {
1055 populate(subset); 1054 populate(subset);
1056 } 1055 }
1057 1056
1058 SkPDFCIDFont::~SkPDFCIDFont() {} 1057 SkPDFCIDFont::~SkPDFCIDFont() {}
1059 1058
1060 bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, 1059 bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
1061 const SkTDArray<uint32_t>* subset) { 1060 const SkTDArray<uint32_t>* subset) {
1062 SkAutoTUnref<SkPDFDict> descriptor(new SkPDFDict("FontDescriptor")); 1061 SkAutoTUnref<SkPDFDict> descriptor(new SkPDFDict("FontDescriptor"));
1063 setFontDescriptor(descriptor.get()); 1062 setFontDescriptor(descriptor.get());
1064 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref(); 1063 insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1195 } 1194 }
1196 } 1195 }
1197 1196
1198 return true; 1197 return true;
1199 } 1198 }
1200 1199
1201 /////////////////////////////////////////////////////////////////////////////// 1200 ///////////////////////////////////////////////////////////////////////////////
1202 // class SkPDFType1Font 1201 // class SkPDFType1Font
1203 /////////////////////////////////////////////////////////////////////////////// 1202 ///////////////////////////////////////////////////////////////////////////////
1204 1203
1205 SkPDFType1Font::SkPDFType1Font(const SkAdvancedTypefaceMetrics* info, 1204 SkPDFType1Font::SkPDFType1Font(SkPDFCanon* canon,
1205 const SkAdvancedTypefaceMetrics* info,
1206 SkTypeface* typeface, 1206 SkTypeface* typeface,
1207 uint16_t glyphID, 1207 uint16_t glyphID,
1208 SkPDFDict* relatedFontDescriptor) 1208 SkPDFDict* relatedFontDescriptor)
1209 : SkPDFFont(info, typeface, relatedFontDescriptor) { 1209 : SkPDFFont(canon, info, typeface, relatedFontDescriptor) {
1210 populate(glyphID); 1210 populate(glyphID);
1211 } 1211 }
1212 1212
1213 SkPDFType1Font::~SkPDFType1Font() {} 1213 SkPDFType1Font::~SkPDFType1Font() {}
1214 1214
1215 bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) { 1215 bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
1216 if (getFontDescriptor() != NULL) { 1216 if (getFontDescriptor() != NULL) {
1217 SkPDFDict* descriptor = getFontDescriptor(); 1217 SkPDFDict* descriptor = getFontDescriptor();
1218 insert("FontDescriptor", new SkPDFObjRef(descriptor))->unref(); 1218 insert("FontDescriptor", new SkPDFObjRef(descriptor))->unref();
1219 return true; 1219 return true;
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1322 } 1322 }
1323 insertInt("FirstChar", firstChar); 1323 insertInt("FirstChar", firstChar);
1324 insertInt("LastChar", firstChar + widthArray->size() - 1); 1324 insertInt("LastChar", firstChar + widthArray->size() - 1);
1325 insert("Widths", widthArray.get()); 1325 insert("Widths", widthArray.get());
1326 } 1326 }
1327 1327
1328 /////////////////////////////////////////////////////////////////////////////// 1328 ///////////////////////////////////////////////////////////////////////////////
1329 // class SkPDFType3Font 1329 // class SkPDFType3Font
1330 /////////////////////////////////////////////////////////////////////////////// 1330 ///////////////////////////////////////////////////////////////////////////////
1331 1331
1332 SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info, 1332 SkPDFType3Font::SkPDFType3Font(SkPDFCanon* canon,
1333 const SkAdvancedTypefaceMetrics* info,
1333 SkTypeface* typeface, 1334 SkTypeface* typeface,
1334 uint16_t glyphID) 1335 uint16_t glyphID)
1335 : SkPDFFont(info, typeface, NULL) { 1336 : SkPDFFont(canon, info, typeface, NULL) {
1336 populate(glyphID); 1337 populate(glyphID);
1337 } 1338 }
1338 1339
1339 SkPDFType3Font::~SkPDFType3Font() {} 1340 SkPDFType3Font::~SkPDFType3Font() {}
1340 1341
1341 bool SkPDFType3Font::populate(uint16_t glyphID) { 1342 bool SkPDFType3Font::populate(uint16_t glyphID) {
1342 SkPaint paint; 1343 SkPaint paint;
1343 paint.setTypeface(typeface()); 1344 paint.setTypeface(typeface());
1344 paint.setTextSize(1000); 1345 paint.setTextSize(1000);
1345 SkAutoGlyphCache autoCache(paint, NULL, NULL); 1346 SkAutoGlyphCache autoCache(paint, NULL, NULL);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1423 } 1424 }
1424 if (existingFont != NULL) { 1425 if (existingFont != NULL) {
1425 return (existingFont->fFirstGlyphID <= searchGlyphID && 1426 return (existingFont->fFirstGlyphID <= searchGlyphID &&
1426 searchGlyphID <= existingFont->fLastGlyphID) 1427 searchGlyphID <= existingFont->fLastGlyphID)
1427 ? SkPDFFont::kExact_Match 1428 ? SkPDFFont::kExact_Match
1428 : SkPDFFont::kRelated_Match; 1429 : SkPDFFont::kRelated_Match;
1429 } 1430 }
1430 return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match 1431 return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match
1431 : SkPDFFont::kRelated_Match; 1432 : SkPDFFont::kRelated_Match;
1432 } 1433 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFFont.h ('k') | src/pdf/SkPDFFontImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698