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

Side by Side Diff: pdf/pdfium/pdfium_engine.cc

Issue 2455453002: Remove stl_util's deletion function use from pdf/. (Closed)
Patch Set: Created 4 years, 1 month 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 | « pdf/pdfium/pdfium_engine.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "pdf/pdfium/pdfium_engine.h" 5 #include "pdf/pdfium/pdfium_engine.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 #include <memory> 12 #include <memory>
13 #include <set> 13 #include <set>
14 14
15 #include "base/i18n/encoding_detection.h" 15 #include "base/i18n/encoding_detection.h"
16 #include "base/i18n/icu_string_conversions.h" 16 #include "base/i18n/icu_string_conversions.h"
17 #include "base/lazy_instance.h" 17 #include "base/lazy_instance.h"
18 #include "base/logging.h" 18 #include "base/logging.h"
19 #include "base/macros.h" 19 #include "base/macros.h"
20 #include "base/memory/ptr_util.h"
20 #include "base/numerics/safe_conversions.h" 21 #include "base/numerics/safe_conversions.h"
21 #include "base/stl_util.h" 22 #include "base/stl_util.h"
22 #include "base/strings/string_number_conversions.h" 23 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_piece.h" 24 #include "base/strings/string_piece.h"
24 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
25 #include "base/strings/utf_string_conversions.h" 26 #include "base/strings/utf_string_conversions.h"
26 #include "gin/array_buffer.h" 27 #include "gin/array_buffer.h"
27 #include "gin/public/gin_embedders.h" 28 #include "gin/public/gin_embedders.h"
28 #include "gin/public/isolate_holder.h" 29 #include "gin/public/isolate_holder.h"
29 #include "pdf/draw_utils.h" 30 #include "pdf/draw_utils.h"
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 // XFA may require |form_| to outlive |doc_|, so shut down in that order. 648 // XFA may require |form_| to outlive |doc_|, so shut down in that order.
648 FPDF_CloseDocument(doc_); 649 FPDF_CloseDocument(doc_);
649 FPDFDOC_ExitFormFillEnvironment(form_); 650 FPDFDOC_ExitFormFillEnvironment(form_);
650 #else 651 #else
651 // Normally |doc_| should outlive |form_|. 652 // Normally |doc_| should outlive |form_|.
652 FPDFDOC_ExitFormFillEnvironment(form_); 653 FPDFDOC_ExitFormFillEnvironment(form_);
653 FPDF_CloseDocument(doc_); 654 FPDF_CloseDocument(doc_);
654 #endif 655 #endif
655 } 656 }
656 FPDFAvail_Destroy(fpdf_availability_); 657 FPDFAvail_Destroy(fpdf_availability_);
657
658 base::STLDeleteElements(&pages_);
659 } 658 }
660 659
661 #if defined(PDF_ENABLE_XFA) 660 #if defined(PDF_ENABLE_XFA)
662 661
663 void PDFiumEngine::Form_EmailTo(FPDF_FORMFILLINFO* param, 662 void PDFiumEngine::Form_EmailTo(FPDF_FORMFILLINFO* param,
664 FPDF_FILEHANDLER* file_handler, 663 FPDF_FILEHANDLER* file_handler,
665 FPDF_WIDESTRING to, 664 FPDF_WIDESTRING to,
666 FPDF_WIDESTRING subject, 665 FPDF_WIDESTRING subject,
667 FPDF_WIDESTRING cc, 666 FPDF_WIDESTRING cc,
668 FPDF_WIDESTRING bcc, 667 FPDF_WIDESTRING bcc,
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after
1600 } else if (event.GetClickCount() == 2 || 1599 } else if (event.GetClickCount() == 2 ||
1601 event.GetClickCount() == 3) { 1600 event.GetClickCount() == 3) {
1602 OnMultipleClick(event.GetClickCount(), page_index, char_index); 1601 OnMultipleClick(event.GetClickCount(), page_index, char_index);
1603 } 1602 }
1604 1603
1605 return true; 1604 return true;
1606 } 1605 }
1607 1606
1608 void PDFiumEngine::OnSingleClick(int page_index, int char_index) { 1607 void PDFiumEngine::OnSingleClick(int page_index, int char_index) {
1609 SetSelecting(true); 1608 SetSelecting(true);
1610 selection_.push_back(PDFiumRange(pages_[page_index], char_index, 0)); 1609 selection_.push_back(PDFiumRange(pages_[page_index].get(), char_index, 0));
1611 } 1610 }
1612 1611
1613 void PDFiumEngine::OnMultipleClick(int click_count, 1612 void PDFiumEngine::OnMultipleClick(int click_count,
1614 int page_index, 1613 int page_index,
1615 int char_index) { 1614 int char_index) {
1616 // It would be more efficient if the SDK could support finding a space, but 1615 // It would be more efficient if the SDK could support finding a space, but
1617 // now it doesn't. 1616 // now it doesn't.
1618 int start_index = char_index; 1617 int start_index = char_index;
1619 do { 1618 do {
1620 base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index); 1619 base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index);
1621 // For double click, we want to select one word so we look for whitespace 1620 // For double click, we want to select one word so we look for whitespace
1622 // boundaries. For triple click, we want the whole line. 1621 // boundaries. For triple click, we want the whole line.
1623 if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t'))) 1622 if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))
1624 break; 1623 break;
1625 } while (--start_index >= 0); 1624 } while (--start_index >= 0);
1626 if (start_index) 1625 if (start_index)
1627 start_index++; 1626 start_index++;
1628 1627
1629 int end_index = char_index; 1628 int end_index = char_index;
1630 int total = pages_[page_index]->GetCharCount(); 1629 int total = pages_[page_index]->GetCharCount();
1631 while (end_index++ <= total) { 1630 while (end_index++ <= total) {
1632 base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index); 1631 base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index);
1633 if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t'))) 1632 if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))
1634 break; 1633 break;
1635 } 1634 }
1636 1635
1637 selection_.push_back(PDFiumRange( 1636 selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
1638 pages_[page_index], start_index, end_index - start_index)); 1637 end_index - start_index));
1639 } 1638 }
1640 1639
1641 bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) { 1640 bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) {
1642 if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT && 1641 if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
1643 event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) { 1642 event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) {
1644 return false; 1643 return false;
1645 } 1644 }
1646 1645
1647 int page_index = -1; 1646 int page_index = -1;
1648 int char_index = -1; 1647 int char_index = -1;
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1784 } else { 1783 } else {
1785 count = char_index - selection_[last].char_index() - 1; 1784 count = char_index - selection_[last].char_index() - 1;
1786 } 1785 }
1787 selection_[last].SetCharCount(count); 1786 selection_[last].SetCharCount(count);
1788 } else if (selection_[last].page_index() < page_index) { 1787 } else if (selection_[last].page_index() < page_index) {
1789 // Selecting into the next page. 1788 // Selecting into the next page.
1790 1789
1791 // First make sure that there are no gaps in selection, i.e. if mousedown on 1790 // First make sure that there are no gaps in selection, i.e. if mousedown on
1792 // page one but we only get mousemove over page three, we want page two. 1791 // page one but we only get mousemove over page three, we want page two.
1793 for (int i = selection_[last].page_index() + 1; i < page_index; ++i) { 1792 for (int i = selection_[last].page_index() + 1; i < page_index; ++i) {
1794 selection_.push_back(PDFiumRange(pages_[i], 0, 1793 selection_.push_back(
1795 pages_[i]->GetCharCount())); 1794 PDFiumRange(pages_[i].get(), 0, pages_[i]->GetCharCount()));
1796 } 1795 }
1797 1796
1798 int count = pages_[selection_[last].page_index()]->GetCharCount(); 1797 int count = pages_[selection_[last].page_index()]->GetCharCount();
1799 selection_[last].SetCharCount(count - selection_[last].char_index()); 1798 selection_[last].SetCharCount(count - selection_[last].char_index());
1800 selection_.push_back(PDFiumRange(pages_[page_index], 0, char_index)); 1799 selection_.push_back(PDFiumRange(pages_[page_index].get(), 0, char_index));
1801 } else { 1800 } else {
1802 // Selecting into the previous page. 1801 // Selecting into the previous page.
1803 // The selection's char_index is 0-based, so the character count is one 1802 // The selection's char_index is 0-based, so the character count is one
1804 // more than the index. The character count needs to be negative to 1803 // more than the index. The character count needs to be negative to
1805 // indicate a backwards selection. 1804 // indicate a backwards selection.
1806 selection_[last].SetCharCount(-(selection_[last].char_index() + 1)); 1805 selection_[last].SetCharCount(-(selection_[last].char_index() + 1));
1807 1806
1808 // First make sure that there are no gaps in selection, i.e. if mousedown on 1807 // First make sure that there are no gaps in selection, i.e. if mousedown on
1809 // page three but we only get mousemove over page one, we want page two. 1808 // page three but we only get mousemove over page one, we want page two.
1810 for (int i = selection_[last].page_index() - 1; i > page_index; --i) { 1809 for (int i = selection_[last].page_index() - 1; i > page_index; --i) {
1811 selection_.push_back(PDFiumRange(pages_[i], 0, 1810 selection_.push_back(
1812 pages_[i]->GetCharCount())); 1811 PDFiumRange(pages_[i].get(), 0, pages_[i]->GetCharCount()));
1813 } 1812 }
1814 1813
1815 int count = pages_[page_index]->GetCharCount(); 1814 int count = pages_[page_index]->GetCharCount();
1816 selection_.push_back( 1815 selection_.push_back(
1817 PDFiumRange(pages_[page_index], count, count - char_index)); 1816 PDFiumRange(pages_[page_index].get(), count, count - char_index));
1818 } 1817 }
1819 1818
1820 return true; 1819 return true;
1821 } 1820 }
1822 1821
1823 bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent& event) { 1822 bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent& event) {
1824 if (last_page_mouse_down_ == -1) 1823 if (last_page_mouse_down_ == -1)
1825 return false; 1824 return false;
1826 1825
1827 bool rv = !!FORM_OnKeyDown( 1826 bool rv = !!FORM_OnKeyDown(
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1972 unsigned long flags = case_sensitive ? FPDF_MATCHCASE : 0; 1971 unsigned long flags = case_sensitive ? FPDF_MATCHCASE : 0;
1973 FPDF_SCHHANDLE find = FPDFText_FindStart( 1972 FPDF_SCHHANDLE find = FPDFText_FindStart(
1974 pages_[current_page]->GetTextPage(), 1973 pages_[current_page]->GetTextPage(),
1975 reinterpret_cast<const unsigned short*>(term.c_str()), 1974 reinterpret_cast<const unsigned short*>(term.c_str()),
1976 flags, character_to_start_searching_from); 1975 flags, character_to_start_searching_from);
1977 1976
1978 // Note: since we search one page at a time, we don't find matches across 1977 // Note: since we search one page at a time, we don't find matches across
1979 // page boundaries. We could do this manually ourself, but it seems low 1978 // page boundaries. We could do this manually ourself, but it seems low
1980 // priority since Reader itself doesn't do it. 1979 // priority since Reader itself doesn't do it.
1981 while (FPDFText_FindNext(find)) { 1980 while (FPDFText_FindNext(find)) {
1982 PDFiumRange result(pages_[current_page], 1981 PDFiumRange result(pages_[current_page].get(),
1983 FPDFText_GetSchResultIndex(find), 1982 FPDFText_GetSchResultIndex(find),
1984 FPDFText_GetSchCount(find)); 1983 FPDFText_GetSchCount(find));
1985 1984
1986 if (!first_search && 1985 if (!first_search &&
1987 last_character_index_to_search_ != -1 && 1986 last_character_index_to_search_ != -1 &&
1988 result.page_index() == last_page_to_search_ && 1987 result.page_index() == last_page_to_search_ &&
1989 result.char_index() >= last_character_index_to_search_) { 1988 result.char_index() >= last_character_index_to_search_) {
1990 break; 1989 break;
1991 } 1990 }
1992 1991
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2029 page_text.c_str(), term.c_str(), case_sensitive, &results); 2028 page_text.c_str(), term.c_str(), case_sensitive, &results);
2030 for (const auto& result : results) { 2029 for (const auto& result : results) {
2031 // Need to map the indexes from the page text, which may have generated 2030 // Need to map the indexes from the page text, which may have generated
2032 // characters like space etc, to character indices from the page. 2031 // characters like space etc, to character indices from the page.
2033 int temp_start = result.start_index + character_to_start_searching_from; 2032 int temp_start = result.start_index + character_to_start_searching_from;
2034 int start = FPDFText_GetCharIndexFromTextIndex( 2033 int start = FPDFText_GetCharIndexFromTextIndex(
2035 pages_[current_page]->GetTextPage(), temp_start); 2034 pages_[current_page]->GetTextPage(), temp_start);
2036 int end = FPDFText_GetCharIndexFromTextIndex( 2035 int end = FPDFText_GetCharIndexFromTextIndex(
2037 pages_[current_page]->GetTextPage(), 2036 pages_[current_page]->GetTextPage(),
2038 temp_start + result.length); 2037 temp_start + result.length);
2039 AddFindResult(PDFiumRange(pages_[current_page], start, end - start)); 2038 AddFindResult(PDFiumRange(pages_[current_page].get(), start, end - start));
2040 } 2039 }
2041 } 2040 }
2042 2041
2043 void PDFiumEngine::AddFindResult(const PDFiumRange& result) { 2042 void PDFiumEngine::AddFindResult(const PDFiumRange& result) {
2044 // Figure out where to insert the new location, since we could have 2043 // Figure out where to insert the new location, since we could have
2045 // started searching midway and now we wrapped. 2044 // started searching midway and now we wrapped.
2046 size_t result_index; 2045 size_t result_index;
2047 int page_index = result.page_index(); 2046 int page_index = result.page_index();
2048 int char_index = result.char_index(); 2047 int char_index = result.char_index();
2049 for (result_index = 0; result_index < find_results_.size(); ++result_index) { 2048 for (result_index = 0; result_index < find_results_.size(); ++result_index) {
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
2257 return true; 2256 return true;
2258 } 2257 }
2259 } 2258 }
2260 2259
2261 void PDFiumEngine::SelectAll() { 2260 void PDFiumEngine::SelectAll() {
2262 SelectionChangeInvalidator selection_invalidator(this); 2261 SelectionChangeInvalidator selection_invalidator(this);
2263 2262
2264 selection_.clear(); 2263 selection_.clear();
2265 for (const auto& page : pages_) { 2264 for (const auto& page : pages_) {
2266 if (page->available()) 2265 if (page->available())
2267 selection_.push_back(PDFiumRange(page, 0, page->GetCharCount())); 2266 selection_.push_back(PDFiumRange(page.get(), 0, page->GetCharCount()));
2268 } 2267 }
2269 } 2268 }
2270 2269
2271 int PDFiumEngine::GetNumberOfPages() { 2270 int PDFiumEngine::GetNumberOfPages() {
2272 return pages_.size(); 2271 return pages_.size();
2273 } 2272 }
2274 2273
2275 pp::VarArray PDFiumEngine::GetBookmarks() { 2274 pp::VarArray PDFiumEngine::GetBookmarks() {
2276 pp::VarDictionary dict = TraverseBookmarks(doc_, nullptr, 0); 2275 pp::VarDictionary dict = TraverseBookmarks(doc_, nullptr, 0);
2277 // The root bookmark contains no useful information. 2276 // The root bookmark contains no useful information.
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
2399 DCHECK_NE(num_pages, 0); 2398 DCHECK_NE(num_pages, 0);
2400 2399
2401 if (!doc_) 2400 if (!doc_)
2402 return; 2401 return;
2403 2402
2404 selection_.clear(); 2403 selection_.clear();
2405 pending_pages_.clear(); 2404 pending_pages_.clear();
2406 2405
2407 // Delete all pages except the first one. 2406 // Delete all pages except the first one.
2408 while (pages_.size() > 1) { 2407 while (pages_.size() > 1) {
2409 delete pages_.back();
2410 pages_.pop_back(); 2408 pages_.pop_back();
2411 FPDFPage_Delete(doc_, pages_.size()); 2409 FPDFPage_Delete(doc_, pages_.size());
2412 } 2410 }
2413 2411
2414 // Calculate document size and all page sizes. 2412 // Calculate document size and all page sizes.
2415 std::vector<pp::Rect> page_rects; 2413 std::vector<pp::Rect> page_rects;
2416 pp::Size page_size = GetPageSize(0); 2414 pp::Size page_size = GetPageSize(0);
2417 page_size.Enlarge(kPageShadowLeft + kPageShadowRight, 2415 page_size.Enlarge(kPageShadowLeft + kPageShadowRight,
2418 kPageShadowTop + kPageShadowBottom); 2416 kPageShadowTop + kPageShadowBottom);
2419 pp::Size old_document_size = document_size_; 2417 pp::Size old_document_size = document_size_;
(...skipping 15 matching lines...) Expand all
2435 pp::Rect page_rect(page_rects[i]); 2433 pp::Rect page_rect(page_rects[i]);
2436 page_rect.Inset(kPageShadowLeft, kPageShadowTop, 2434 page_rect.Inset(kPageShadowLeft, kPageShadowTop,
2437 kPageShadowRight, kPageShadowBottom); 2435 kPageShadowRight, kPageShadowBottom);
2438 double width_in_points = ConvertUnitDouble(page_rect.width(), 2436 double width_in_points = ConvertUnitDouble(page_rect.width(),
2439 kPixelsPerInch, 2437 kPixelsPerInch,
2440 kPointsPerInch); 2438 kPointsPerInch);
2441 double height_in_points = ConvertUnitDouble(page_rect.height(), 2439 double height_in_points = ConvertUnitDouble(page_rect.height(),
2442 kPixelsPerInch, 2440 kPixelsPerInch,
2443 kPointsPerInch); 2441 kPointsPerInch);
2444 FPDFPage_New(doc_, i, width_in_points, height_in_points); 2442 FPDFPage_New(doc_, i, width_in_points, height_in_points);
2445 pages_.push_back(new PDFiumPage(this, i, page_rect, true)); 2443 pages_.push_back(base::MakeUnique<PDFiumPage>(this, i, page_rect, true));
2446 } 2444 }
2447 2445
2448 CalculateVisiblePages(); 2446 CalculateVisiblePages();
2449 if (document_size_ != old_document_size) 2447 if (document_size_ != old_document_size)
2450 client_->DocumentSizeUpdated(document_size_); 2448 client_->DocumentSizeUpdated(document_size_);
2451 } 2449 }
2452 2450
2453 void PDFiumEngine::LoadDocument() { 2451 void PDFiumEngine::LoadDocument() {
2454 // Check if the document is ready for loading. If it isn't just bail for now, 2452 // Check if the document is ready for loading. If it isn't just bail for now,
2455 // we will call LoadDocument() again later. 2453 // we will call LoadDocument() again later.
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
2628 page_rects[i].set_x((document_size_.width() - page_rects[i].width()) / 2); 2626 page_rects[i].set_x((document_size_.width() - page_rects[i].width()) / 2);
2629 pp::Rect page_rect(page_rects[i]); 2627 pp::Rect page_rect(page_rects[i]);
2630 page_rect.Inset(kPageShadowLeft, kPageShadowTop, 2628 page_rect.Inset(kPageShadowLeft, kPageShadowTop,
2631 kPageShadowRight, kPageShadowBottom); 2629 kPageShadowRight, kPageShadowBottom);
2632 if (reload) { 2630 if (reload) {
2633 pages_[i]->set_rect(page_rect); 2631 pages_[i]->set_rect(page_rect);
2634 } else { 2632 } else {
2635 // The page is marked as not being available even if |doc_complete| is 2633 // The page is marked as not being available even if |doc_complete| is
2636 // true because FPDFAvail_IsPageAvail() still has to be called for this 2634 // true because FPDFAvail_IsPageAvail() still has to be called for this
2637 // page, which will be done in FinishLoadingDocument(). 2635 // page, which will be done in FinishLoadingDocument().
2638 pages_.push_back(new PDFiumPage(this, i, page_rect, false)); 2636 pages_.push_back(base::MakeUnique<PDFiumPage>(this, i, page_rect, false));
2639 } 2637 }
2640 } 2638 }
2641 2639
2642 CalculateVisiblePages(); 2640 CalculateVisiblePages();
2643 if (document_size_ != old_document_size) 2641 if (document_size_ != old_document_size)
2644 client_->DocumentSizeUpdated(document_size_); 2642 client_->DocumentSizeUpdated(document_size_);
2645 } 2643 }
2646 2644
2647 void PDFiumEngine::CalculateVisiblePages() { 2645 void PDFiumEngine::CalculateVisiblePages() {
2648 // Clear pending requests queue, since it may contain requests to the pages 2646 // Clear pending requests queue, since it may contain requests to the pages
(...skipping 1359 matching lines...) Expand 10 before | Expand all | Expand 10 after
4008 FPDF_DOCUMENT doc = 4006 FPDF_DOCUMENT doc =
4009 FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr); 4007 FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr);
4010 if (!doc) 4008 if (!doc)
4011 return false; 4009 return false;
4012 bool success = FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0; 4010 bool success = FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0;
4013 FPDF_CloseDocument(doc); 4011 FPDF_CloseDocument(doc);
4014 return success; 4012 return success;
4015 } 4013 }
4016 4014
4017 } // namespace chrome_pdf 4015 } // namespace chrome_pdf
OLDNEW
« no previous file with comments | « pdf/pdfium/pdfium_engine.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698