| OLD | NEW | 
|---|
| 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 "chrome/browser/ui/views/download/download_item_view.h" | 5 #include "chrome/browser/ui/views/download/download_item_view.h" | 
| 6 | 6 | 
| 7 #include <algorithm> | 7 #include <algorithm> | 
| 8 #include <vector> | 8 #include <vector> | 
| 9 | 9 | 
| 10 #include "base/bind.h" | 10 #include "base/bind.h" | 
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 89 | 89 | 
| 90 // How long we keep the item disabled after the user clicked it to open the | 90 // How long we keep the item disabled after the user clicked it to open the | 
| 91 // downloaded item. | 91 // downloaded item. | 
| 92 static const int kDisabledOnOpenDuration = 3000; | 92 static const int kDisabledOnOpenDuration = 3000; | 
| 93 | 93 | 
| 94 // Darken light-on-dark download status text by 20% before drawing, thus | 94 // Darken light-on-dark download status text by 20% before drawing, thus | 
| 95 // creating a "muted" version of title text for both dark-on-light and | 95 // creating a "muted" version of title text for both dark-on-light and | 
| 96 // light-on-dark themes. | 96 // light-on-dark themes. | 
| 97 static const double kDownloadItemLuminanceMod = 0.8; | 97 static const double kDownloadItemLuminanceMod = 0.8; | 
| 98 | 98 | 
| 99 namespace { |  | 
| 100 |  | 
| 101 // Callback for DownloadShelf paint functions to mirror the progress animation |  | 
| 102 // in RTL locales. |  | 
| 103 void RTLMirrorXForView(views::View* containing_view, gfx::Rect* bounds) { |  | 
| 104   bounds->set_x(containing_view->GetMirroredXForRect(*bounds)); |  | 
| 105 } |  | 
| 106 |  | 
| 107 }  // namespace |  | 
| 108 |  | 
| 109 DownloadItemView::DownloadItemView(DownloadItem* download_item, | 99 DownloadItemView::DownloadItemView(DownloadItem* download_item, | 
| 110     DownloadShelfView* parent) | 100     DownloadShelfView* parent) | 
| 111   : warning_icon_(NULL), | 101   : warning_icon_(NULL), | 
| 112     shelf_(parent), | 102     shelf_(parent), | 
| 113     status_text_(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING)), | 103     status_text_(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING)), | 
| 114     body_state_(NORMAL), | 104     body_state_(NORMAL), | 
| 115     drop_down_state_(NORMAL), | 105     drop_down_state_(NORMAL), | 
| 116     mode_(NORMAL_MODE), | 106     mode_(NORMAL_MODE), | 
| 117     progress_angle_(DownloadShelf::kStartAngleDegrees), |  | 
| 118     drop_down_pressed_(false), | 107     drop_down_pressed_(false), | 
| 119     dragging_(false), | 108     dragging_(false), | 
| 120     starting_drag_(false), | 109     starting_drag_(false), | 
| 121     model_(download_item), | 110     model_(download_item), | 
| 122     save_button_(NULL), | 111     save_button_(NULL), | 
| 123     discard_button_(NULL), | 112     discard_button_(NULL), | 
| 124     dangerous_download_label_(NULL), | 113     dangerous_download_label_(NULL), | 
| 125     dangerous_download_label_sized_(false), | 114     dangerous_download_label_sized_(false), | 
| 126     disabled_while_opening_(false), | 115     disabled_while_opening_(false), | 
| 127     creation_time_(base::Time::Now()), | 116     creation_time_(base::Time::Now()), | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 210 | 199 | 
| 211   LoadIcon(); | 200   LoadIcon(); | 
| 212 | 201 | 
| 213   font_list_ = rb.GetFontList(ui::ResourceBundle::BaseFont); | 202   font_list_ = rb.GetFontList(ui::ResourceBundle::BaseFont); | 
| 214   box_height_ = std::max<int>(2 * kVerticalPadding + font_list_.GetHeight() + | 203   box_height_ = std::max<int>(2 * kVerticalPadding + font_list_.GetHeight() + | 
| 215                                   kVerticalTextPadding + font_list_.GetHeight(), | 204                                   kVerticalTextPadding + font_list_.GetHeight(), | 
| 216                               2 * kVerticalPadding + | 205                               2 * kVerticalPadding + | 
| 217                                   normal_body_image_set_.top_left->height() + | 206                                   normal_body_image_set_.top_left->height() + | 
| 218                                   normal_body_image_set_.bottom_left->height()); | 207                                   normal_body_image_set_.bottom_left->height()); | 
| 219 | 208 | 
| 220   if (DownloadShelf::kSmallProgressIconSize > box_height_) | 209   if (DownloadShelf::kProgressIndicatorSize > box_height_) | 
| 221     box_y_ = (DownloadShelf::kSmallProgressIconSize - box_height_) / 2; | 210     box_y_ = (DownloadShelf::kProgressIndicatorSize - box_height_) / 2; | 
| 222   else | 211   else | 
| 223     box_y_ = 0; | 212     box_y_ = 0; | 
| 224 | 213 | 
| 225   body_hover_animation_.reset(new gfx::SlideAnimation(this)); | 214   body_hover_animation_.reset(new gfx::SlideAnimation(this)); | 
| 226   drop_hover_animation_.reset(new gfx::SlideAnimation(this)); | 215   drop_hover_animation_.reset(new gfx::SlideAnimation(this)); | 
| 227 | 216 | 
| 228   SetAccessibilityFocusable(true); | 217   SetAccessibilityFocusable(true); | 
| 229 | 218 | 
| 230   OnDownloadUpdated(download()); | 219   OnDownloadUpdated(download()); | 
| 231   UpdateDropDownButtonPosition(); | 220   UpdateDropDownButtonPosition(); | 
| 232 } | 221 } | 
| 233 | 222 | 
| 234 DownloadItemView::~DownloadItemView() { | 223 DownloadItemView::~DownloadItemView() { | 
| 235   StopDownloadProgress(); | 224   StopDownloadProgress(); | 
| 236   download()->RemoveObserver(this); | 225   download()->RemoveObserver(this); | 
| 237 | 226 | 
| 238   // ExperienceSampling: If the user took no action to remove the warning | 227   // ExperienceSampling: If the user took no action to remove the warning | 
| 239   // before it disappeared, then the user effectively dismissed the download | 228   // before it disappeared, then the user effectively dismissed the download | 
| 240   // without keeping it. | 229   // without keeping it. | 
| 241   if (sampling_event_.get()) | 230   if (sampling_event_.get()) | 
| 242     sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kIgnore); | 231     sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kIgnore); | 
| 243 } | 232 } | 
| 244 | 233 | 
| 245 // Progress animation handlers. | 234 // Progress animation handlers. | 
| 246 | 235 | 
| 247 void DownloadItemView::UpdateDownloadProgress() { |  | 
| 248   progress_angle_ = |  | 
| 249       (progress_angle_ + DownloadShelf::kUnknownIncrementDegrees) % |  | 
| 250       DownloadShelf::kMaxDegrees; |  | 
| 251   SchedulePaint(); |  | 
| 252 } |  | 
| 253 |  | 
| 254 void DownloadItemView::StartDownloadProgress() { | 236 void DownloadItemView::StartDownloadProgress() { | 
| 255   if (progress_timer_.IsRunning()) | 237   if (progress_timer_.IsRunning()) | 
| 256     return; | 238     return; | 
| 257   progress_timer_.Start(FROM_HERE, | 239   progress_start_time_ = base::TimeTicks::Now(); | 
| 258       base::TimeDelta::FromMilliseconds(DownloadShelf::kProgressRateMs), this, | 240   progress_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds( | 
| 259       &DownloadItemView::UpdateDownloadProgress); | 241                                        DownloadShelf::kProgressRateMs), | 
|  | 242                         this, &DownloadItemView::SchedulePaint); | 
| 260 } | 243 } | 
| 261 | 244 | 
| 262 void DownloadItemView::StopDownloadProgress() { | 245 void DownloadItemView::StopDownloadProgress() { | 
| 263   progress_timer_.Stop(); | 246   progress_timer_.Stop(); | 
| 264 } | 247 } | 
| 265 | 248 | 
| 266 void DownloadItemView::OnExtractIconComplete(gfx::Image* icon_bitmap) { | 249 void DownloadItemView::OnExtractIconComplete(gfx::Image* icon_bitmap) { | 
| 267   if (icon_bitmap) | 250   if (icon_bitmap) | 
| 268     shelf_->SchedulePaint(); | 251     shelf_->SchedulePaint(); | 
| 269 } | 252 } | 
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 386   } | 369   } | 
| 387 } | 370 } | 
| 388 | 371 | 
| 389 gfx::Size DownloadItemView::GetPreferredSize() const { | 372 gfx::Size DownloadItemView::GetPreferredSize() const { | 
| 390   int width, height; | 373   int width, height; | 
| 391 | 374 | 
| 392   // First, we set the height to the height of two rows or text plus margins. | 375   // First, we set the height to the height of two rows or text plus margins. | 
| 393   height = 2 * kVerticalPadding + 2 * font_list_.GetHeight() + | 376   height = 2 * kVerticalPadding + 2 * font_list_.GetHeight() + | 
| 394       kVerticalTextPadding; | 377       kVerticalTextPadding; | 
| 395   // Then we increase the size if the progress icon doesn't fit. | 378   // Then we increase the size if the progress icon doesn't fit. | 
| 396   height = std::max<int>(height, DownloadShelf::kSmallProgressIconSize); | 379   height = std::max<int>(height, DownloadShelf::kProgressIndicatorSize); | 
| 397 | 380 | 
| 398   if (IsShowingWarningDialog()) { | 381   if (IsShowingWarningDialog()) { | 
| 399     const BodyImageSet* body_image_set = | 382     const BodyImageSet* body_image_set = | 
| 400         (mode_ == DANGEROUS_MODE) ? &dangerous_mode_body_image_set_ : | 383         (mode_ == DANGEROUS_MODE) ? &dangerous_mode_body_image_set_ : | 
| 401             &malicious_mode_body_image_set_; | 384             &malicious_mode_body_image_set_; | 
| 402     width = kLeftPadding + body_image_set->top_left->width(); | 385     width = kLeftPadding + body_image_set->top_left->width(); | 
| 403     width += warning_icon_->width() + kLabelPadding; | 386     width += warning_icon_->width() + kLabelPadding; | 
| 404     width += dangerous_download_label_->width() + kLabelPadding; | 387     width += dangerous_download_label_->width() + kLabelPadding; | 
| 405     gfx::Size button_size = GetButtonSize(); | 388     gfx::Size button_size = GetButtonSize(); | 
| 406     // Make sure the button fits. | 389     // Make sure the button fits. | 
| 407     height = std::max<int>(height, 2 * kVerticalPadding + button_size.height()); | 390     height = std::max<int>(height, 2 * kVerticalPadding + button_size.height()); | 
| 408     // Then we make sure the warning icon fits. | 391     // Then we make sure the warning icon fits. | 
| 409     height = std::max<int>(height, 2 * kVerticalPadding + | 392     height = std::max<int>(height, 2 * kVerticalPadding + | 
| 410                                    warning_icon_->height()); | 393                                    warning_icon_->height()); | 
| 411     if (save_button_) | 394     if (save_button_) | 
| 412       width += button_size.width() + kButtonPadding; | 395       width += button_size.width() + kButtonPadding; | 
| 413     width += button_size.width(); | 396     width += button_size.width(); | 
| 414     width += body_image_set->top_right->width(); | 397     width += body_image_set->top_right->width(); | 
| 415     if (mode_ == MALICIOUS_MODE) | 398     if (mode_ == MALICIOUS_MODE) | 
| 416       width += normal_drop_down_image_set_.top->width(); | 399       width += normal_drop_down_image_set_.top->width(); | 
| 417   } else { | 400   } else { | 
| 418     width = kLeftPadding + normal_body_image_set_.top_left->width(); | 401     width = kLeftPadding + normal_body_image_set_.top_left->width(); | 
| 419     width += DownloadShelf::kSmallProgressIconSize; | 402     width += DownloadShelf::kProgressIndicatorSize; | 
| 420     width += kTextWidth; | 403     width += kTextWidth; | 
| 421     width += normal_body_image_set_.top_right->width(); | 404     width += normal_body_image_set_.top_right->width(); | 
| 422     width += normal_drop_down_image_set_.top->width(); | 405     width += normal_drop_down_image_set_.top->width(); | 
| 423   } | 406   } | 
| 424   return gfx::Size(width, height); | 407   return gfx::Size(width, height); | 
| 425 } | 408 } | 
| 426 | 409 | 
| 427 // Handle a mouse click and open the context menu if the mouse is | 410 // Handle a mouse click and open the context menu if the mouse is | 
| 428 // over the drop-down region. | 411 // over the drop-down region. | 
| 429 bool DownloadItemView::OnMousePressed(const ui::MouseEvent& event) { | 412 bool DownloadItemView::OnMousePressed(const ui::MouseEvent& event) { | 
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 705 | 688 | 
| 706   // May be caused by animation. | 689   // May be caused by animation. | 
| 707   if (center_width <= 0) | 690   if (center_width <= 0) | 
| 708     return; | 691     return; | 
| 709 | 692 | 
| 710   // Draw status before button image to effectively lighten text.  No status for | 693   // Draw status before button image to effectively lighten text.  No status for | 
| 711   // warning dialogs. | 694   // warning dialogs. | 
| 712   if (!IsShowingWarningDialog()) { | 695   if (!IsShowingWarningDialog()) { | 
| 713     if (!status_text_.empty()) { | 696     if (!status_text_.empty()) { | 
| 714       int mirrored_x = GetMirroredXWithWidthInView( | 697       int mirrored_x = GetMirroredXWithWidthInView( | 
| 715           DownloadShelf::kSmallProgressIconSize, kTextWidth); | 698           DownloadShelf::kProgressIndicatorSize, kTextWidth); | 
| 716       // Add font_list_.height() to compensate for title, which is drawn later. | 699       // Add font_list_.height() to compensate for title, which is drawn later. | 
| 717       int y = box_y_ + kVerticalPadding + font_list_.GetHeight() + | 700       int y = box_y_ + kVerticalPadding + font_list_.GetHeight() + | 
| 718               kVerticalTextPadding; | 701               kVerticalTextPadding; | 
| 719       SkColor file_name_color = GetThemeProvider()->GetColor( | 702       SkColor file_name_color = GetThemeProvider()->GetColor( | 
| 720           ThemeProperties::COLOR_BOOKMARK_TEXT); | 703           ThemeProperties::COLOR_BOOKMARK_TEXT); | 
| 721       // If text is light-on-dark, lightening it alone will do nothing. | 704       // If text is light-on-dark, lightening it alone will do nothing. | 
| 722       // Therefore we mute luminance a wee bit before drawing in this case. | 705       // Therefore we mute luminance a wee bit before drawing in this case. | 
| 723       if (color_utils::RelativeLuminance(file_name_color) > 0.5) | 706       if (color_utils::RelativeLuminance(file_name_color) > 0.5) | 
| 724           file_name_color = SkColorSetRGB( | 707           file_name_color = SkColorSetRGB( | 
| 725               static_cast<int>(kDownloadItemLuminanceMod * | 708               static_cast<int>(kDownloadItemLuminanceMod * | 
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 831       // Then, elide the file name. | 814       // Then, elide the file name. | 
| 832       base::string16 filename_string = | 815       base::string16 filename_string = | 
| 833           gfx::ElideFilename(download()->GetFileNameToReportUser(), font_list_, | 816           gfx::ElideFilename(download()->GetFileNameToReportUser(), font_list_, | 
| 834                             kTextWidth - status_string_width); | 817                             kTextWidth - status_string_width); | 
| 835       // Last, concat the whole string. | 818       // Last, concat the whole string. | 
| 836       filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, | 819       filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, | 
| 837                                             filename_string); | 820                                             filename_string); | 
| 838     } | 821     } | 
| 839 | 822 | 
| 840     int mirrored_x = GetMirroredXWithWidthInView( | 823     int mirrored_x = GetMirroredXWithWidthInView( | 
| 841         DownloadShelf::kSmallProgressIconSize, kTextWidth); | 824         DownloadShelf::kProgressIndicatorSize, kTextWidth); | 
| 842     SkColor file_name_color = GetThemeProvider()->GetColor( | 825     SkColor file_name_color = GetThemeProvider()->GetColor( | 
| 843         ThemeProperties::COLOR_BOOKMARK_TEXT); | 826         ThemeProperties::COLOR_BOOKMARK_TEXT); | 
| 844     int y = | 827     int y = | 
| 845         box_y_ + (status_text_.empty() ? | 828         box_y_ + (status_text_.empty() ? | 
| 846             ((box_height_ - font_list_.GetHeight()) / 2) : kVerticalPadding); | 829             ((box_height_ - font_list_.GetHeight()) / 2) : kVerticalPadding); | 
| 847 | 830 | 
| 848     // Draw the file's name. | 831     // Draw the file's name. | 
| 849     canvas->DrawStringRect( | 832     canvas->DrawStringRect( | 
| 850         filename, font_list_, | 833         filename, font_list_, | 
| 851         enabled() ? file_name_color : kFileNameDisabledColor, | 834         enabled() ? file_name_color : kFileNameDisabledColor, | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 863     icon = image->ToImageSkia(); | 846     icon = image->ToImageSkia(); | 
| 864 | 847 | 
| 865   // We count on the fact that the icon manager will cache the icons and if one | 848   // We count on the fact that the icon manager will cache the icons and if one | 
| 866   // is available, it will be cached here. We *don't* want to request the icon | 849   // is available, it will be cached here. We *don't* want to request the icon | 
| 867   // to be loaded here, since this will also get called if the icon can't be | 850   // to be loaded here, since this will also get called if the icon can't be | 
| 868   // loaded, in which case LookupIcon will always be NULL. The loading will be | 851   // loaded, in which case LookupIcon will always be NULL. The loading will be | 
| 869   // triggered only when we think the status might change. | 852   // triggered only when we think the status might change. | 
| 870   if (icon) { | 853   if (icon) { | 
| 871     if (!IsShowingWarningDialog()) { | 854     if (!IsShowingWarningDialog()) { | 
| 872       DownloadItem::DownloadState state = download()->GetState(); | 855       DownloadItem::DownloadState state = download()->GetState(); | 
| 873       DownloadShelf::BoundsAdjusterCallback rtl_mirror = | 856       canvas->Save(); | 
| 874           base::Bind(&RTLMirrorXForView, base::Unretained(this)); | 857       if (base::i18n::IsRTL()) | 
|  | 858         canvas->Translate( | 
|  | 859             gfx::Vector2d(width() - DownloadShelf::kProgressIndicatorSize, 0)); | 
|  | 860 | 
| 875       if (state == DownloadItem::IN_PROGRESS) { | 861       if (state == DownloadItem::IN_PROGRESS) { | 
| 876         DownloadShelf::PaintDownloadProgress(canvas, rtl_mirror, 0, 0, | 862         DownloadShelf::PaintDownloadProgress(canvas, *GetThemeProvider(), | 
| 877                                              progress_angle_, | 863                                              progress_start_time_, | 
| 878                                              model_.PercentComplete()); | 864                                              model_.PercentComplete()); | 
| 879       } else if (complete_animation_.get() && | 865       } else if (complete_animation_.get() && | 
| 880                  complete_animation_->is_animating()) { | 866                  complete_animation_->is_animating()) { | 
| 881         if (state == DownloadItem::INTERRUPTED) { | 867         if (state == DownloadItem::INTERRUPTED) { | 
| 882           DownloadShelf::PaintDownloadInterrupted( | 868           DownloadShelf::PaintDownloadInterrupted( | 
| 883               canvas, rtl_mirror, 0, 0, complete_animation_->GetCurrentValue()); | 869               canvas, *GetThemeProvider(), | 
|  | 870               complete_animation_->GetCurrentValue()); | 
| 884         } else { | 871         } else { | 
| 885           DCHECK_EQ(DownloadItem::COMPLETE, state); | 872           DCHECK_EQ(DownloadItem::COMPLETE, state); | 
| 886           DownloadShelf::PaintDownloadComplete( | 873           DownloadShelf::PaintDownloadComplete( | 
| 887               canvas, rtl_mirror, 0, 0, complete_animation_->GetCurrentValue()); | 874               canvas, *GetThemeProvider(), | 
|  | 875               complete_animation_->GetCurrentValue()); | 
| 888         } | 876         } | 
| 889       } | 877       } | 
|  | 878       canvas->Restore(); | 
| 890     } | 879     } | 
| 891 | 880 | 
| 892     // Draw the icon image. | 881     // Draw the icon image. | 
| 893     int icon_x, icon_y; | 882     int icon_x, icon_y; | 
| 894 | 883 | 
| 895     if (IsShowingWarningDialog()) { | 884     if (IsShowingWarningDialog()) { | 
| 896       icon_x = kLeftPadding + body_image_set->top_left->width(); | 885       icon_x = kLeftPadding + body_image_set->top_left->width(); | 
| 897       icon_y = (height() - icon->height()) / 2; | 886       icon_y = (height() - icon->height()) / 2; | 
| 898     } else { | 887     } else { | 
| 899       icon_x = DownloadShelf::kSmallProgressIconOffset; | 888       icon_x = DownloadShelf::kFiletypeIconOffset; | 
| 900       icon_y = DownloadShelf::kSmallProgressIconOffset; | 889       icon_y = DownloadShelf::kFiletypeIconOffset; | 
| 901     } | 890     } | 
| 902     icon_x = GetMirroredXWithWidthInView(icon_x, icon->width()); | 891     icon_x = GetMirroredXWithWidthInView(icon_x, icon->width()); | 
| 903     if (enabled()) { | 892     if (enabled()) { | 
| 904       canvas->DrawImageInt(*icon, icon_x, icon_y); | 893       canvas->DrawImageInt(*icon, icon_x, icon_y); | 
| 905     } else { | 894     } else { | 
| 906       // Use an alpha to make the image look disabled. | 895       // Use an alpha to make the image look disabled. | 
| 907       SkPaint paint; | 896       SkPaint paint; | 
| 908       paint.setAlpha(120); | 897       paint.setAlpha(120); | 
| 909       canvas->DrawImageInt(*icon, icon_x, icon_y, paint); | 898       canvas->DrawImageInt(*icon, icon_x, icon_y, paint); | 
| 910     } | 899     } | 
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1382 void DownloadItemView::AnimateStateTransition(State from, State to, | 1371 void DownloadItemView::AnimateStateTransition(State from, State to, | 
| 1383                                               gfx::SlideAnimation* animation) { | 1372                                               gfx::SlideAnimation* animation) { | 
| 1384   if (from == NORMAL && to == HOT) { | 1373   if (from == NORMAL && to == HOT) { | 
| 1385     animation->Show(); | 1374     animation->Show(); | 
| 1386   } else if (from == HOT && to == NORMAL) { | 1375   } else if (from == HOT && to == NORMAL) { | 
| 1387     animation->Hide(); | 1376     animation->Hide(); | 
| 1388   } else if (from != to) { | 1377   } else if (from != to) { | 
| 1389     animation->Reset((to == HOT) ? 1.0 : 0.0); | 1378     animation->Reset((to == HOT) ? 1.0 : 0.0); | 
| 1390   } | 1379   } | 
| 1391 } | 1380 } | 
| OLD | NEW | 
|---|