[apps/calculation] Raise exception if row height miscomputed

Scenario:
Put the complex mode to exponential, then go back to Calculation and:
Toolbox, Down, Down, Down, Down, OK, OK, Two, Plus, Imaginary,
Toolbox, Down, Down, Down, Down, OK, Down, OK, Two, Plus,
Imaginary, OK, Toolbox, Down, Down, Down, Down, Down, OK,
Down, OK, Up, OK, Right, Zero, OK, OK, Toolbox, Down,
Down, OK, Toolbox, Back, Up, Zero, Up, OK, Zero, Up, Up, Up
This commit is contained in:
Léa Saviot
2020-07-06 17:26:06 +02:00
parent 924e235ba8
commit 1128134c37
3 changed files with 24 additions and 3 deletions

View File

@@ -1,5 +1,6 @@
#include "history_controller.h"
#include "app.h"
#include <poincare/exception_checkpoint.h>
#include <assert.h>
using namespace Shared;
@@ -206,6 +207,10 @@ KDCoordinate HistoryController::rowHeight(int j) {
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = HistoryViewCell::Height(calculation.pointer(), expanded);
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
/* We might want to put an assertion here to check the memoization:

View File

@@ -36,7 +36,16 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType,
KDCoordinate HistoryViewCell::Height(Calculation * calculation, bool expanded) {
HistoryViewCell cell(nullptr);
cell.setCalculation(calculation, expanded);
bool didForceOutput = false;
cell.setCalculation(calculation, expanded, &didForceOutput);
if (didForceOutput) {
/* We could not compute the height of the calculation as it is (the display
* output was forced to another value during the height computation).
* Warning: the display output of calculation was actually changed, so it
* will cause problems if we already did some computations with another
* display value. */
return -1;
}
KDRect ellipsisFrame = KDRectZero;
KDRect inputFrame = KDRectZero;
KDRect outputFrame = KDRectZero;
@@ -237,7 +246,8 @@ void HistoryViewCell::resetMemoization() {
m_calculationCRC32 = 0;
}
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation));
if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) {
return;
@@ -265,6 +275,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
if (couldNotCreateExactLayout) {
if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
} else {
/* We should only display the exact result, but we cannot create it
* -> raise an exception. */
@@ -287,6 +300,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
/* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);

View File

@@ -51,7 +51,7 @@ public:
Poincare::Layout layout() const override;
KDColor backgroundColor() const override { return m_even ? KDColorWhite : Palette::WallScreen; }
void resetMemoization();
void setCalculation(Calculation * calculation, bool expanded);
void setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput = nullptr);
int numberOfSubviews() const override { return 2 + displayedEllipsis(); }
View * subviewAtIndex(int index) override;
void layoutSubviews(bool force = false) override;