| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "printing/pdf_ps_metafile_linux.h" | 5 #include "printing/pdf_ps_metafile_linux.h" |
| 6 | 6 |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 | 8 |
| 9 #include <cairo.h> | 9 #include <cairo.h> |
| 10 #include <cairo-ft.h> |
| 10 #include <cairo-pdf.h> | 11 #include <cairo-pdf.h> |
| 11 #include <cairo-ps.h> | 12 #include <cairo-ps.h> |
| 12 | 13 |
| 14 #include <ft2build.h> |
| 15 #include FT_FREETYPE_H |
| 16 |
| 17 #include <map> |
| 18 |
| 13 #include "base/file_util.h" | 19 #include "base/file_util.h" |
| 14 #include "base/logging.h" | 20 #include "base/logging.h" |
| 21 #include "base/singleton.h" |
| 22 #include "third_party/skia/include/core/SkFontHost.h" |
| 23 #include "third_party/skia/include/core/SkStream.h" |
| 24 #include "third_party/skia/include/core/SkTypeface.h" |
| 15 | 25 |
| 16 namespace { | 26 namespace { |
| 17 | 27 |
| 28 FT_Library g_ft_library = NULL; // handle to FreeType library. |
| 29 |
| 30 struct FontInfo { |
| 31 SkStream* font_stream; |
| 32 FT_Face ft_face; |
| 33 cairo_font_face_t* cairo_face; |
| 34 cairo_user_data_key_t data_key; |
| 35 }; |
| 36 |
| 37 typedef std::map<uint32_t, FontInfo> MapFontId2FontInfo; |
| 38 |
| 39 // NOTE: Only call this function when no further rendering will be performed, |
| 40 // and/or the metafile is closed. |
| 41 void CleanUpFonts() { |
| 42 MapFontId2FontInfo* g_font_cache = Singleton<MapFontId2FontInfo>::get(); |
| 43 DCHECK(g_font_cache); |
| 44 |
| 45 for (MapFontId2FontInfo::iterator it = g_font_cache->begin(); |
| 46 it !=g_font_cache->end(); |
| 47 ++it) { |
| 48 DCHECK(it->second.cairo_face); |
| 49 DCHECK(it->second.font_stream); |
| 50 |
| 51 cairo_font_face_destroy(it->second.cairo_face); |
| 52 // |it->second.ft_face| is handled by Cairo. |
| 53 it->second.font_stream->unref(); |
| 54 } |
| 55 g_font_cache->clear(); |
| 56 } |
| 57 |
| 58 void CleanUpFreeType() { |
| 59 if (g_ft_library) { |
| 60 FT_Error ft_error = FT_Done_FreeType(g_ft_library); |
| 61 g_ft_library = NULL; |
| 62 DCHECK_EQ(ft_error, 0); |
| 63 } |
| 64 } |
| 65 |
| 18 // Tests if |surface| is valid. | 66 // Tests if |surface| is valid. |
| 19 bool IsSurfaceValid(cairo_surface_t* surface) { | 67 bool IsSurfaceValid(cairo_surface_t* surface) { |
| 20 return cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS; | 68 return cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS; |
| 21 } | 69 } |
| 22 | 70 |
| 23 // Tests if |context| is valid. | 71 // Tests if |context| is valid. |
| 24 bool IsContextValid(cairo_t* context) { | 72 bool IsContextValid(cairo_t* context) { |
| 25 return cairo_status(context) == CAIRO_STATUS_SUCCESS; | 73 return cairo_status(context) == CAIRO_STATUS_SUCCESS; |
| 26 } | 74 } |
| 27 | 75 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 41 } | 89 } |
| 42 } | 90 } |
| 43 | 91 |
| 44 // Callback function for Cairo to write PDF/PS stream. | 92 // Callback function for Cairo to write PDF/PS stream. |
| 45 // |dst_buffer| is actually a pointer of type `std::string*`. | 93 // |dst_buffer| is actually a pointer of type `std::string*`. |
| 46 cairo_status_t WriteCairoStream(void* dst_buffer, | 94 cairo_status_t WriteCairoStream(void* dst_buffer, |
| 47 const unsigned char* src_data, | 95 const unsigned char* src_data, |
| 48 unsigned int src_data_length) { | 96 unsigned int src_data_length) { |
| 49 DCHECK(dst_buffer); | 97 DCHECK(dst_buffer); |
| 50 DCHECK(src_data); | 98 DCHECK(src_data); |
| 51 DCHECK(src_data_length > 0); | 99 DCHECK_GT(src_data_length, 0u); |
| 52 | 100 |
| 53 std::string* buffer = reinterpret_cast<std::string*>(dst_buffer); | 101 std::string* buffer = reinterpret_cast<std::string*>(dst_buffer); |
| 54 buffer->append(reinterpret_cast<const char*>(src_data), src_data_length); | 102 buffer->append(reinterpret_cast<const char*>(src_data), src_data_length); |
| 55 | 103 |
| 56 return CAIRO_STATUS_SUCCESS; | 104 return CAIRO_STATUS_SUCCESS; |
| 57 } | 105 } |
| 58 | 106 |
| 59 } // namespace | 107 } // namespace |
| 60 | 108 |
| 61 namespace printing { | 109 namespace printing { |
| 62 | 110 |
| 63 PdfPsMetafile::PdfPsMetafile(const FileFormat& format) | 111 PdfPsMetafile::PdfPsMetafile(const FileFormat& format) |
| 64 : format_(format), | 112 : format_(format), |
| 65 surface_(NULL), context_(NULL), | 113 surface_(NULL), context_(NULL), |
| 66 page_surface_(NULL), page_context_(NULL) { | 114 page_surface_(NULL), page_context_(NULL) { |
| 67 } | 115 } |
| 68 | 116 |
| 69 PdfPsMetafile::~PdfPsMetafile() { | 117 PdfPsMetafile::~PdfPsMetafile() { |
| 70 // Releases resources if we forgot to do so. | 118 // Releases all resources if we forgot to do so. |
| 71 CleanUp(); | 119 CleanUpAll(); |
| 72 } | 120 } |
| 73 | 121 |
| 74 bool PdfPsMetafile::Init() { | 122 bool PdfPsMetafile::Init() { |
| 75 // We need to check at least these two members to ensure Init() has not been | 123 // We need to check at least these two members to ensure Init() has not been |
| 76 // called before. Passing these two checks also implies that surface_, | 124 // called before. Passing these two checks also implies that surface_, |
| 77 // page_surface_, and page_context_ are NULL, and current_page_ is empty. | 125 // page_surface_, and page_context_ are NULL, and current_page_ is empty. |
| 78 DCHECK(!context_); | 126 DCHECK(!context_); |
| 79 DCHECK(all_pages_.empty()); | 127 DCHECK(all_pages_.empty()); |
| 128 DCHECK(!g_ft_library); |
| 80 | 129 |
| 81 // Create an 1 by 1 Cairo surface for entire PDF/PS file. | 130 // Initializes FreeType library. |
| 131 FT_Error ft_error = FT_Init_FreeType(&g_ft_library); |
| 132 if (ft_error) { |
| 133 DLOG(ERROR) << "Cannot initialize FreeType library for PdfPsMetafile."; |
| 134 g_ft_library = NULL; |
| 135 return false; |
| 136 } |
| 137 |
| 138 // Creates an 1 by 1 Cairo surface for entire PDF/PS file. |
| 82 // The size for each page will be overwritten later in StartPage(). | 139 // The size for each page will be overwritten later in StartPage(). |
| 83 switch (format_) { | 140 switch (format_) { |
| 84 case PDF: { | 141 case PDF: { |
| 85 surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream, | 142 surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream, |
| 86 &all_pages_, 1, 1); | 143 &all_pages_, 1, 1); |
| 87 } | 144 } |
| 88 break; | 145 break; |
| 89 | 146 |
| 90 case PS: { | 147 case PS: { |
| 91 surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream, | 148 surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream, |
| 92 &all_pages_, 1, 1); | 149 &all_pages_, 1, 1); |
| 93 } | 150 } |
| 94 break; | 151 break; |
| 95 | 152 |
| 96 default: | 153 default: |
| 97 NOTREACHED(); | 154 NOTREACHED(); |
| 98 return false; | 155 return false; |
| 99 } | 156 } |
| 100 | 157 |
| 101 // Cairo always returns a valid pointer. | 158 // Cairo always returns a valid pointer. |
| 102 // Hence, we have to check if it points to a "nil" object. | 159 // Hence, we have to check if it points to a "nil" object. |
| 103 if (!IsSurfaceValid(surface_)) { | 160 if (!IsSurfaceValid(surface_)) { |
| 104 DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!"; | 161 DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!"; |
| 105 CleanUpSurface(&surface_); | 162 CleanUpSurface(&surface_); |
| 163 CleanUpFreeType(); |
| 106 return false; | 164 return false; |
| 107 } | 165 } |
| 108 | 166 |
| 109 // Create a context. | 167 // Creates a context. |
| 110 context_ = cairo_create(surface_); | 168 context_ = cairo_create(surface_); |
| 111 if (!IsContextValid(context_)) { | 169 if (!IsContextValid(context_)) { |
| 112 DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!"; | 170 DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!"; |
| 113 CleanUpContext(&context_); | 171 CleanUpContext(&context_); |
| 114 CleanUpSurface(&surface_); | 172 CleanUpSurface(&surface_); |
| 173 CleanUpFreeType(); |
| 115 return false; | 174 return false; |
| 116 } | 175 } |
| 117 | 176 |
| 118 return true; | 177 return true; |
| 119 } | 178 } |
| 120 | 179 |
| 121 bool PdfPsMetafile::Init(const void* src_buffer, size_t src_buffer_size) { | 180 bool PdfPsMetafile::Init(const void* src_buffer, size_t src_buffer_size) { |
| 122 // We need to check at least these two members to ensure Init() has not been | 181 // We need to check at least these two members to ensure Init() has not been |
| 123 // called before. Passing these two checks also implies that surface_, | 182 // called before. Passing these two checks also implies that surface_, |
| 124 // page_surface_, and page_context_ are NULL, and current_page_ is empty. | 183 // page_surface_, and page_context_ are NULL, and current_page_ is empty. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 138 cairo_t* PdfPsMetafile::StartPage(double width_in_points, | 197 cairo_t* PdfPsMetafile::StartPage(double width_in_points, |
| 139 double height_in_points) { | 198 double height_in_points) { |
| 140 DCHECK(IsSurfaceValid(surface_)); | 199 DCHECK(IsSurfaceValid(surface_)); |
| 141 DCHECK(IsContextValid(context_)); | 200 DCHECK(IsContextValid(context_)); |
| 142 // Passing this check implies page_surface_ is NULL, and current_page_ is | 201 // Passing this check implies page_surface_ is NULL, and current_page_ is |
| 143 // empty. | 202 // empty. |
| 144 DCHECK(!page_context_); | 203 DCHECK(!page_context_); |
| 145 DCHECK_GT(width_in_points, 0.); | 204 DCHECK_GT(width_in_points, 0.); |
| 146 DCHECK_GT(height_in_points, 0.); | 205 DCHECK_GT(height_in_points, 0.); |
| 147 | 206 |
| 148 // Create a target surface for the new page. | 207 // Creates a target surface for the new page. |
| 149 // Cairo 1.6.0 does NOT allow the first argument be NULL, | 208 // Cairo 1.6.0 does NOT allow the first argument be NULL, |
| 150 // but some newer versions do support NULL pointer. | 209 // but some newer versions do support NULL pointer. |
| 151 switch (format_) { | 210 switch (format_) { |
| 152 case PDF: { | 211 case PDF: { |
| 153 page_surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream, | 212 page_surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream, |
| 154 ¤t_page_, | 213 ¤t_page_, |
| 155 width_in_points, | 214 width_in_points, |
| 156 height_in_points); | 215 height_in_points); |
| 157 } | 216 } |
| 158 break; | 217 break; |
| 159 | 218 |
| 160 case PS: { | 219 case PS: { |
| 161 page_surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream, | 220 page_surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream, |
| 162 ¤t_page_, | 221 ¤t_page_, |
| 163 width_in_points, | 222 width_in_points, |
| 164 height_in_points); | 223 height_in_points); |
| 165 } | 224 } |
| 166 break; | 225 break; |
| 167 | 226 |
| 168 default: | 227 default: |
| 169 NOTREACHED(); | 228 NOTREACHED(); |
| 170 CleanUp(); | 229 CleanUpAll(); |
| 171 return NULL; | 230 return NULL; |
| 172 } | 231 } |
| 173 | 232 |
| 174 // Cairo always returns a valid pointer. | 233 // Cairo always returns a valid pointer. |
| 175 // Hence, we have to check if it points to a "nil" object. | 234 // Hence, we have to check if it points to a "nil" object. |
| 176 if (!IsSurfaceValid(page_surface_)) { | 235 if (!IsSurfaceValid(page_surface_)) { |
| 177 DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!"; | 236 DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!"; |
| 178 CleanUp(); | 237 CleanUpAll(); |
| 179 return NULL; | 238 return NULL; |
| 180 } | 239 } |
| 181 | 240 |
| 182 // Create a context. | 241 // Creates a context. |
| 183 page_context_ = cairo_create(page_surface_); | 242 page_context_ = cairo_create(page_surface_); |
| 184 if (!IsContextValid(page_context_)) { | 243 if (!IsContextValid(page_context_)) { |
| 185 DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!"; | 244 DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!"; |
| 186 CleanUp(); | 245 CleanUpAll(); |
| 187 return NULL; | 246 return NULL; |
| 188 } | 247 } |
| 189 | 248 |
| 190 return page_context_; | 249 return page_context_; |
| 191 } | 250 } |
| 192 | 251 |
| 193 bool PdfPsMetafile::FinishPage(float shrink) { | 252 bool PdfPsMetafile::FinishPage(float shrink) { |
| 194 DCHECK(IsSurfaceValid(surface_)); | 253 DCHECK(IsSurfaceValid(surface_)); |
| 195 DCHECK(IsContextValid(context_)); | 254 DCHECK(IsContextValid(context_)); |
| 196 DCHECK(IsSurfaceValid(page_surface_)); | 255 DCHECK(IsSurfaceValid(page_surface_)); |
| 197 DCHECK(IsContextValid(page_context_)); | 256 DCHECK(IsContextValid(page_context_)); |
| 198 DCHECK(shrink > 0); | 257 DCHECK_GT(shrink, 0); |
| 199 | 258 |
| 200 // Flush all rendering for current page. | 259 // Flushes all rendering for current page. |
| 201 cairo_surface_flush(page_surface_); | 260 cairo_surface_flush(page_surface_); |
| 202 | 261 |
| 203 // TODO(myhuang): Use real page settings. | 262 // TODO(myhuang): Use real page settings. |
| 204 // We hard-coded page settings here for testing purpose. | 263 // We hard-coded page settings here for testing purpose. |
| 205 // The paper size is US Letter (8.5 in. by 11 in.). | 264 // The paper size is US Letter (8.5 in. by 11 in.). |
| 206 // The default margins are: | 265 // The default margins are: |
| 207 // Left = 0.25 in. | 266 // Left = 0.25 in. |
| 208 // Right = 0.25 in. | 267 // Right = 0.25 in. |
| 209 // Top = 0.25 in. | 268 // Top = 0.25 in. |
| 210 // Bottom = 0.56 in. | 269 // Bottom = 0.56 in. |
| 211 const double kDPI = 72.0; // Dots (points) per inch. | 270 const double kDPI = 72.0; // Dots (points) per inch. |
| 212 const double kWidthInInch = 8.5; | 271 const double kWidthInInch = 8.5; |
| 213 const double kHeightInInch = 11.0; | 272 const double kHeightInInch = 11.0; |
| 214 const double kWidthInPoint = kWidthInInch * kDPI; | 273 const double kWidthInPoint = kWidthInInch * kDPI; |
| 215 const double kHeightInPoint = kHeightInInch * kDPI; | 274 const double kHeightInPoint = kHeightInInch * kDPI; |
| 216 switch (format_) { | 275 switch (format_) { |
| 217 case PDF: { | 276 case PDF: { |
| 218 cairo_pdf_surface_set_size(surface_, kWidthInPoint, kHeightInPoint); | 277 cairo_pdf_surface_set_size(surface_, kWidthInPoint, kHeightInPoint); |
| 219 } | 278 } |
| 220 break; | 279 break; |
| 221 | 280 |
| 222 case PS: { | 281 case PS: { |
| 223 cairo_ps_surface_set_size(surface_, kWidthInPoint, kHeightInPoint); | 282 cairo_ps_surface_set_size(surface_, kWidthInPoint, kHeightInPoint); |
| 224 } | 283 } |
| 225 break; | 284 break; |
| 226 | 285 |
| 227 default: | 286 default: |
| 228 NOTREACHED(); | 287 NOTREACHED(); |
| 229 CleanUp(); | 288 CleanUpAll(); |
| 230 return false; | 289 return false; |
| 231 } | 290 } |
| 232 | 291 |
| 233 // Check if our surface is still valid after resizing. | 292 // Checks if our surface is still valid after resizing. |
| 234 if (!IsSurfaceValid(surface_)) { | 293 if (!IsSurfaceValid(surface_)) { |
| 235 DLOG(ERROR) << "Cannot resize Cairo surface for PdfPsMetafile!"; | 294 DLOG(ERROR) << "Cannot resize Cairo surface for PdfPsMetafile!"; |
| 236 CleanUp(); | 295 CleanUpAll(); |
| 237 return false; | 296 return false; |
| 238 } | 297 } |
| 239 | 298 |
| 240 // Save context's states. | 299 // Saves context's states. |
| 241 cairo_save(context_); | 300 cairo_save(context_); |
| 242 // Copy current page onto the surface of final result. | 301 // Copies current page onto the surface of final result. |
| 243 // Margins are done by coordinates transformation. | 302 // Margins are done by coordinates transformation. |
| 244 // Please NOTE that we have to call cairo_scale() before we call | 303 // Please NOTE that we have to call cairo_scale() before we call |
| 245 // cairo_set_source_surface(). | 304 // cairo_set_source_surface(). |
| 246 const double scale_factor = 1. / shrink; | 305 const double scale_factor = 1. / shrink; |
| 247 cairo_scale(context_, scale_factor, scale_factor); | 306 cairo_scale(context_, scale_factor, scale_factor); |
| 248 const double kLeftMarginInInch = 0.25; | 307 const double kLeftMarginInInch = 0.25; |
| 249 const double kTopMarginInInch = 0.25; | 308 const double kTopMarginInInch = 0.25; |
| 250 const double kLeftMarginInPoint = kLeftMarginInInch * kDPI; | 309 const double kLeftMarginInPoint = kLeftMarginInInch * kDPI; |
| 251 const double kTopMarginInPoint = kTopMarginInInch * kDPI; | 310 const double kTopMarginInPoint = kTopMarginInInch * kDPI; |
| 252 const double kScaledLeftMarginInPoint = kLeftMarginInPoint * shrink; | 311 const double kScaledLeftMarginInPoint = kLeftMarginInPoint * shrink; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 268 kPrintableWidthInInch * kDPI * shrink; | 327 kPrintableWidthInInch * kDPI * shrink; |
| 269 const double kScaledPrintableHeightInPoint = | 328 const double kScaledPrintableHeightInPoint = |
| 270 kPrintableHeightInInch * kDPI * shrink; | 329 kPrintableHeightInInch * kDPI * shrink; |
| 271 cairo_rectangle(context_, | 330 cairo_rectangle(context_, |
| 272 kScaledLeftMarginInPoint, | 331 kScaledLeftMarginInPoint, |
| 273 kScaledTopMarginInPoint, | 332 kScaledTopMarginInPoint, |
| 274 kScaledPrintableWidthInPoint, | 333 kScaledPrintableWidthInPoint, |
| 275 kScaledPrintableHeightInPoint); | 334 kScaledPrintableHeightInPoint); |
| 276 cairo_fill(context_); | 335 cairo_fill(context_); |
| 277 | 336 |
| 278 // Finishing the duplication of current page. | 337 // Finishes the duplication of current page. |
| 279 cairo_show_page(context_); | 338 cairo_show_page(context_); |
| 280 cairo_surface_flush(surface_); | 339 cairo_surface_flush(surface_); |
| 281 | 340 |
| 282 // Destroy resoreces for current page. | 341 // Destroys resources for current page. |
| 283 CleanUpContext(&page_context_); | 342 CleanUpContext(&page_context_); |
| 284 CleanUpSurface(&page_surface_); | 343 CleanUpSurface(&page_surface_); |
| 285 current_page_.clear(); | 344 current_page_.clear(); |
| 286 | 345 |
| 287 // Restore context's states. | 346 // Restores context's states. |
| 288 cairo_restore(context_); | 347 cairo_restore(context_); |
| 289 | 348 |
| 290 return true; | 349 return true; |
| 291 } | 350 } |
| 292 | 351 |
| 293 void PdfPsMetafile::Close() { | 352 void PdfPsMetafile::Close() { |
| 294 DCHECK(IsSurfaceValid(surface_)); | 353 DCHECK(IsSurfaceValid(surface_)); |
| 295 DCHECK(IsContextValid(context_)); | 354 DCHECK(IsContextValid(context_)); |
| 296 // Passing this check implies page_surface_ is NULL, and current_page_ is | 355 // Passing this check implies page_surface_ is NULL, and current_page_ is |
| 297 // empty. | 356 // empty. |
| 298 DCHECK(!page_context_); | 357 DCHECK(!page_context_); |
| 299 | 358 |
| 300 cairo_surface_finish(surface_); | 359 cairo_surface_finish(surface_); |
| 301 DCHECK(!all_pages_.empty()); // Make sure we did get something. | 360 DCHECK(!all_pages_.empty()); // Make sure we did get something. |
| 302 | 361 |
| 303 CleanUpContext(&context_); | 362 CleanUpContext(&context_); |
| 304 CleanUpSurface(&surface_); | 363 CleanUpSurface(&surface_); |
| 364 CleanUpFonts(); |
| 365 CleanUpFreeType(); |
| 366 } |
| 367 |
| 368 // static |
| 369 bool PdfPsMetafile::SelectFontById(cairo_t* context, uint32_t font_id) { |
| 370 DCHECK(IsContextValid(context)); |
| 371 DCHECK(SkFontHost::ValidFontID(font_id)); |
| 372 DCHECK(g_ft_library); |
| 373 |
| 374 // Checks if we have a cache hit. |
| 375 MapFontId2FontInfo* g_font_cache = Singleton<MapFontId2FontInfo>::get(); |
| 376 DCHECK(g_font_cache); |
| 377 |
| 378 MapFontId2FontInfo::iterator it = g_font_cache->find(font_id); |
| 379 if (it != g_font_cache->end()) { |
| 380 cairo_set_font_face(context, it->second.cairo_face); |
| 381 if (IsContextValid(context)) { |
| 382 return true; |
| 383 } else { |
| 384 NOTREACHED() << "Cannot set font face in Cairo!"; |
| 385 return false; |
| 386 } |
| 387 } |
| 388 |
| 389 // Cache missed. We need to load and create the font. |
| 390 FontInfo new_font_info = {0}; |
| 391 new_font_info.font_stream = SkFontHost::OpenStream(font_id); |
| 392 DCHECK(new_font_info.font_stream); |
| 393 size_t stream_size = new_font_info.font_stream->getLength(); |
| 394 DCHECK(stream_size) << "The Font stream has nothing!"; |
| 395 |
| 396 FT_Error ft_error = FT_New_Memory_Face( |
| 397 g_ft_library, |
| 398 static_cast<FT_Byte*>( |
| 399 const_cast<void*>(new_font_info.font_stream->getMemoryBase())), |
| 400 stream_size, |
| 401 0, |
| 402 &new_font_info.ft_face); |
| 403 |
| 404 if (ft_error) { |
| 405 new_font_info.font_stream->unref(); |
| 406 DLOG(ERROR) << "Cannot create FT_Face!"; |
| 407 SkASSERT(false); |
| 408 return false; |
| 409 } |
| 410 |
| 411 new_font_info.cairo_face = cairo_ft_font_face_create_for_ft_face( |
| 412 new_font_info.ft_face, 0); |
| 413 DCHECK(new_font_info.cairo_face) << "Cannot create font in Cairo!"; |
| 414 |
| 415 // Manage |new_font_info.ft_face|'s life by Cairo. |
| 416 cairo_status_t status = cairo_font_face_set_user_data( |
| 417 new_font_info.cairo_face, |
| 418 &new_font_info.data_key, |
| 419 new_font_info.ft_face, |
| 420 reinterpret_cast<cairo_destroy_func_t>(FT_Done_Face)); |
| 421 |
| 422 if (status != CAIRO_STATUS_SUCCESS) { |
| 423 DLOG(ERROR) << "Cannot set font's user data in Cairo!"; |
| 424 cairo_font_face_destroy(new_font_info.cairo_face); |
| 425 FT_Done_Face(new_font_info.ft_face); |
| 426 new_font_info.font_stream->unref(); |
| 427 SkASSERT(false); |
| 428 return false; |
| 429 } |
| 430 |
| 431 // Inserts |new_font_info| info |g_font_cache|. |
| 432 (*g_font_cache)[font_id] = new_font_info; |
| 433 |
| 434 cairo_set_font_face(context, new_font_info.cairo_face); |
| 435 if (IsContextValid(context)) { |
| 436 return true; |
| 437 } |
| 438 |
| 439 DLOG(ERROR) << "Connot set font face in Cairo!"; |
| 440 return false; |
| 305 } | 441 } |
| 306 | 442 |
| 307 unsigned int PdfPsMetafile::GetDataSize() const { | 443 unsigned int PdfPsMetafile::GetDataSize() const { |
| 308 // We need to check at least these two members to ensure that either Init() | 444 // We need to check at least these two members to ensure that either Init() |
| 309 // has been called to initialize |all_pages_|, or metafile has been closed. | 445 // has been called to initialize |all_pages_|, or metafile has been closed. |
| 310 // Passing these two checks also implies that surface_, page_surface_, and | 446 // Passing these two checks also implies that surface_, page_surface_, and |
| 311 // page_context_ are NULL, and current_page_ is empty. | 447 // page_context_ are NULL, and current_page_ is empty. |
| 312 DCHECK(!context_); | 448 DCHECK(!context_); |
| 313 DCHECK(!all_pages_.empty()); | 449 DCHECK(!all_pages_.empty()); |
| 314 | 450 |
| 315 return all_pages_.size(); | 451 return all_pages_.size(); |
| 316 } | 452 } |
| 317 | 453 |
| 318 bool PdfPsMetafile::GetData(void* dst_buffer, size_t dst_buffer_size) const { | 454 bool PdfPsMetafile::GetData(void* dst_buffer, size_t dst_buffer_size) const { |
| 319 DCHECK(dst_buffer); | 455 DCHECK(dst_buffer); |
| 320 DCHECK(dst_buffer_size > 0); | 456 DCHECK_GT(dst_buffer_size, 0u); |
| 321 // We need to check at least these two members to ensure that either Init() | 457 // We need to check at least these two members to ensure that either Init() |
| 322 // has been called to initialize |all_pages_|, or metafile has been closed. | 458 // has been called to initialize |all_pages_|, or metafile has been closed. |
| 323 // Passing these two checks also implies that surface_, page_surface_, and | 459 // Passing these two checks also implies that surface_, page_surface_, and |
| 324 // page_context_ are NULL, and current_page_ is empty. | 460 // page_context_ are NULL, and current_page_ is empty. |
| 325 DCHECK(!context_); | 461 DCHECK(!context_); |
| 326 DCHECK(!all_pages_.empty()); | 462 DCHECK(!all_pages_.empty()); |
| 327 | 463 |
| 328 size_t data_size = GetDataSize(); | 464 size_t data_size = GetDataSize(); |
| 329 if (dst_buffer_size > data_size) { | 465 if (dst_buffer_size > data_size) { |
| 330 return false; | 466 return false; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 347 const unsigned int bytes_written = | 483 const unsigned int bytes_written = |
| 348 file_util::WriteFile(filename, all_pages_.data(), data_size); | 484 file_util::WriteFile(filename, all_pages_.data(), data_size); |
| 349 if (bytes_written != data_size) { | 485 if (bytes_written != data_size) { |
| 350 DLOG(ERROR) << "Failed to save file: " << filename.value(); | 486 DLOG(ERROR) << "Failed to save file: " << filename.value(); |
| 351 return false; | 487 return false; |
| 352 } | 488 } |
| 353 | 489 |
| 354 return true; | 490 return true; |
| 355 } | 491 } |
| 356 | 492 |
| 357 void PdfPsMetafile::CleanUp() { | 493 void PdfPsMetafile::CleanUpAll() { |
| 358 CleanUpContext(&context_); | 494 CleanUpContext(&context_); |
| 359 CleanUpSurface(&surface_); | 495 CleanUpSurface(&surface_); |
| 360 CleanUpContext(&page_context_); | 496 CleanUpContext(&page_context_); |
| 361 CleanUpSurface(&page_surface_); | 497 CleanUpSurface(&page_surface_); |
| 362 current_page_.clear(); | 498 current_page_.clear(); |
| 363 all_pages_.clear(); | 499 all_pages_.clear(); |
| 500 CleanUpFonts(); |
| 501 CleanUpFreeType(); |
| 364 } | 502 } |
| 365 | 503 |
| 366 } // namespace printing | 504 } // namespace printing |
| 367 | 505 |
| OLD | NEW |