Skip to content

Commit

Permalink
Ensured memory safety for Elements
Browse files Browse the repository at this point in the history
 - Every instance which theoretically owned a Element, models this now via an unique_ptr
 - Renamed *insertOrder* -> *insertionOrder*

refactor ElementContainer
 - the only purpose for ElementContainer is to use it in ElementContainerView, to draw all elements in the container
 - the draw function could be moved into the element container itself, or we can use a forEach implementation which can then be used elsewhere for other purposes.

VerticalToolHandler: rename getElements to refElements
 - made refElements private
 - only one use internally
 - still copies Element*
 - "ref" means, that instead of returning a reference to the datastructure holding the owned Elements, a copy of each Ptr is returned in a vector
  • Loading branch information
Febbe committed Jan 10, 2024
1 parent e15a79f commit 33baec7
Show file tree
Hide file tree
Showing 68 changed files with 719 additions and 634 deletions.
34 changes: 18 additions & 16 deletions src/core/control/Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,16 +479,18 @@ void Control::selectAllOnPage() {

win->getXournal()->clearSelection();

std::vector<Element*> elements = layer->clearNoFree();
auto elements = layer->clearNoFree();
this->doc->unlock();

if (!elements.empty()) {
InsertionOrder insertOrder;
insertOrder.reserve(elements.size());
InsertionOrder insertionOrder;
insertionOrder.reserve(elements.size());
Element::Index n = 0;
std::transform(elements.begin(), elements.end(), std::back_inserter(insertOrder),
[&n](Element* e) { return InsertionPosition(e, n++); });
auto [sel, rg] = SelectionFactory::createFromFloatingElements(this, page, layer, view, std::move(insertOrder));
for (auto&& e: elements) {
insertionOrder.emplace_back(std::move(e), n++);
}
auto [sel, rg] =
SelectionFactory::createFromFloatingElements(this, page, layer, view, std::move(insertionOrder));

page->fireRangeChanged(rg);

Expand All @@ -502,7 +504,7 @@ void Control::reorderSelection(EditSelection::OrderChange change) {
return;
}

auto undoAction = sel->rearrangeInsertOrder(change);
auto undoAction = sel->rearrangeInsertionOrder(change);
this->undoRedo->addUndoAction(std::move(undoAction));
}

Expand Down Expand Up @@ -1998,16 +2000,16 @@ void Control::clipboardCutCopyEnabled(bool enabled) {
void Control::clipboardPasteEnabled(bool enabled) { this->actionDB->enableAction(Action::PASTE, enabled); }

void Control::clipboardPasteText(string text) {
Text* t = new Text();
auto t = std::make_unique<Text>();
t->setText(text);
t->setFont(settings->getFont());
t->setColor(toolHandler->getTool(TOOL_TEXT).getColor());

clipboardPaste(t);
clipboardPaste(std::move(t));
}

void Control::clipboardPasteImage(GdkPixbuf* img) {
auto image = new Image();
auto image = std::make_unique<Image>();
image->setImage(img);

auto width =
Expand Down Expand Up @@ -2046,10 +2048,10 @@ void Control::clipboardPasteImage(GdkPixbuf* img) {
image->setWidth(scaledWidth);
image->setHeight(scaledHeight);

clipboardPaste(image);
clipboardPaste(std::move(image));
}

void Control::clipboardPaste(Element* e) {
void Control::clipboardPaste(ElementPtr e) {
double x = 0;
double y = 0;
auto pageNr = getCurrentPageNo();
Expand Down Expand Up @@ -2078,8 +2080,8 @@ void Control::clipboardPaste(Element* e) {
e->setX(x);
e->setY(y);

undoRedo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, e));
auto sel = SelectionFactory::createFromFloatingElement(this, page, layer, view, e);
undoRedo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, e.get()));
auto sel = SelectionFactory::createFromFloatingElement(this, page, layer, view, std::move(e));

win->getXournal()->setSelection(sel.release());
}
Expand Down Expand Up @@ -2109,7 +2111,7 @@ void Control::clipboardPasteXournal(ObjectInputStream& in) {
this->doc->unlock();

try {
std::unique_ptr<Element> element;
ElementPtr element;
std::string version = in.readString();
if (version != PROJECT_STRING) {
g_warning("Paste from Xournal Version %s to Xournal Version %s", version.c_str(), PROJECT_STRING);
Expand Down Expand Up @@ -2143,7 +2145,7 @@ void Control::clipboardPasteXournal(ObjectInputStream& in) {

pasteAddUndoAction->addElement(layer, element.get(), layer->indexOf(element.get()));
// Todo: unique_ptr
selection->addElement(element.release(), std::numeric_limits<Element::Index>::max());
selection->addElement(std::move(element), std::numeric_limits<Element::Index>::max());
}
undoRedo->addUndoAction(std::move(pasteAddUndoAction));

Expand Down
2 changes: 1 addition & 1 deletion src/core/control/Control.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class Control:
void clipboardPasteXournal(ObjectInputStream& in) override;
void deleteSelection() override;

void clipboardPaste(Element* e);
void clipboardPaste(ElementPtr e);

public:
void registerPluginToolButtons(ToolMenuHandler* toolMenuHandler);
Expand Down
21 changes: 13 additions & 8 deletions src/core/control/GeometryToolController.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "GeometryToolController.h"

#include <memory>

#include "control/Control.h"
#include "control/layer/LayerController.h"
#include "gui/XournalView.h"
Expand Down Expand Up @@ -50,7 +52,7 @@ void GeometryToolController::scale(double f, double cx, double cy) {
void GeometryToolController::markPoint(double x, double y) {
const auto control = view->getXournal()->getControl();
const auto h = control->getToolHandler();
Stroke* cross = new Stroke();
auto cross = std::make_unique<Stroke>();
cross->setWidth(h->getToolThickness(TOOL_PEN)[TOOL_SIZE_FINE]);
cross->setColor(h->getTool(TOOL_PEN).getColor());
cross->addPoint(Point(x + MARK_SIZE, y + MARK_SIZE));
Expand All @@ -59,17 +61,19 @@ void GeometryToolController::markPoint(double x, double y) {
cross->addPoint(Point(x + MARK_SIZE, y - MARK_SIZE));
cross->addPoint(Point(x - MARK_SIZE, y + MARK_SIZE));

auto* ptr = cross.get();
const auto doc = control->getDocument();
const auto page = view->getPage();
doc->lock();
const auto layer = page->getSelectedLayer();
layer->addElement(cross);
layer->addElement(std::move(cross));
doc->unlock();

const auto undo = control->getUndoRedoHandler();
undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, cross));
undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, ptr));


const Rectangle<double> rect{cross->getX(), cross->getY(), cross->getElementWidth(), cross->getElementHeight()};
const Rectangle<double> rect{ptr->getX(), ptr->getY(), ptr->getElementWidth(), ptr->getElementHeight()};
view->rerenderRect(rect.x, rect.y, rect.width, rect.height);
}

Expand All @@ -79,15 +83,16 @@ void GeometryToolController::addStrokeToLayer() {
const auto doc = control->getDocument();
const auto page = view->getPage();

auto ptr = stroke.get();
doc->lock();
const auto layer = page->getSelectedLayer();
layer->addElement(stroke.get());
layer->addElement(std::move(this->stroke));
doc->unlock();

const auto undo = control->getUndoRedoHandler();
undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, stroke.get()));
const Rectangle<double> rect{stroke->getX(), stroke->getY(), stroke->getElementWidth(), stroke->getElementHeight()};
undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, ptr));
const Rectangle<double> rect{ptr->getX(), ptr->getY(), ptr->getElementWidth(), ptr->getElementHeight()};
view->rerenderRect(rect.x, rect.y, rect.width, rect.height);
stroke.release();
geometryTool->setStroke(nullptr);
xournal->getCursor()->updateCursor();
}
Expand Down
9 changes: 5 additions & 4 deletions src/core/control/LatexController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void LatexController::findSelectedTexElement() {

if (auto* img = dynamic_cast<TexImage*>(this->selectedElem)) {
this->initialTex = img->getText();
this->temporaryRender = std::unique_ptr<TexImage>(img->clone());
this->temporaryRender = img->cloneTexImage();
this->isValidTex = true;
} else if (auto* txt = dynamic_cast<Text*>(this->selectedElem)) {
this->initialTex = "\\text{" + txt->getText() + "}";
Expand Down Expand Up @@ -327,15 +327,16 @@ auto LatexController::loadRendered(string renderedTex) -> std::unique_ptr<TexIma
void LatexController::insertTexImage() {
xoj_assert(this->isValidTex);
xoj_assert(this->temporaryRender != nullptr);
TexImage* img = this->temporaryRender.release();

this->control->clearSelectionEndText();
this->deleteOldImage();

control->getUndoRedoHandler()->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, img));
control->getUndoRedoHandler()->addUndoAction(
std::make_unique<InsertUndoAction>(page, layer, this->temporaryRender.get()));

// Select element
auto selection = SelectionFactory::createFromFloatingElement(control, page, layer, view, img);
auto selection =
SelectionFactory::createFromFloatingElement(control, page, layer, view, std::move(this->temporaryRender));
view->getXournal()->setSelection(selection.release());
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/control/SearchControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ auto SearchControl::search(const std::string& text, size_t index, size_t* occurr
continue;
}

for (Element* e: l->getElements()) {
for (auto&& e: l->getElements()) {
if (e->getType() == ELEMENT_TEXT) {
Text* t = dynamic_cast<Text*>(e);
Text* t = dynamic_cast<Text*>(e.get());

std::vector<XojPdfRectangle> textResult = t->findText(text);
this->results.insert(this->results.end(), textResult.begin(), textResult.end());
Expand Down
9 changes: 5 additions & 4 deletions src/core/control/UndoRedoController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "gui/MainWindow.h" // for MainWindow
#include "gui/XournalView.h" // for XournalView
#include "model/Document.h" // for Document
#include "model/ElementInsertionPosition.h"
#include "model/Layer.h" // for Layer
#include "model/PageRef.h" // for PageRef
#include "model/XojPage.h" // for XojPage
Expand Down Expand Up @@ -51,18 +52,18 @@ void UndoRedoController::after() {
return;
}

InsertionOrder remainingElements;
InsertionOrderRef remainingElements;
for (Element* e: elements) {
// Test is the element has been removed since
// Test, if the element has been removed since
if (auto pos = layer->indexOf(e); pos != -1) {
remainingElements.emplace_back(e, pos);
}
}
if (!remainingElements.empty()) {
layer->removeElementsAt(remainingElements, false);
auto removedElements = layer->removeElementsAt(remainingElements);
lock.unlock(); // Not needed anymore. For all other paths, the lock is released via ~unique_lock()
auto [sel, bounds] =
SelectionFactory::createFromFloatingElements(control, page, layer, view, std::move(remainingElements));
SelectionFactory::createFromFloatingElements(control, page, layer, view, std::move(removedElements));
control->getWindow()->getXournal()->setSelection(sel.release());
page->fireRangeChanged(bounds);
}
Expand Down
7 changes: 4 additions & 3 deletions src/core/control/shaperecognizer/CircleRecognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cmath> // for hypot, cos, fabs, sin, M_PI
#include <iterator> // for begin, end, next
#include <memory>
#include <vector> // for vector

#include "model/Point.h" // for Point
Expand All @@ -13,13 +14,13 @@
/**
* Create circle stroke for inertia
*/
auto CircleRecognizer::makeCircleShape(Stroke* originalStroke, Inertia& inertia) -> Stroke* {
auto CircleRecognizer::makeCircleShape(Stroke* originalStroke, Inertia& inertia) -> std::unique_ptr<Stroke> {
int npts = static_cast<int>(2 * inertia.rad());
if (npts < 24) {
npts = 24; // min. number of points
}

auto* s = new Stroke();
auto s = std::make_unique<Stroke>();
s->applyStyleFrom(originalStroke);

for (int i = 0; i <= npts; i++) {
Expand Down Expand Up @@ -58,7 +59,7 @@ auto CircleRecognizer::scoreCircle(Stroke* s, Inertia& inertia) -> double {
return sum / (divisor);
}

auto CircleRecognizer::recognize(Stroke* stroke) -> Stroke* {
auto CircleRecognizer::recognize(Stroke* stroke) -> std::unique_ptr<Stroke> {
Inertia s;
s.calc(stroke->getPoints(), 0, static_cast<int>(stroke->getPointCount()));
RDEBUG("Mass=%.0f, Center=(%.1f,%.1f), I=(%.0f,%.0f, %.0f), Rad=%.2f, Det=%.4f", s.getMass(), s.centerX(),
Expand Down
7 changes: 4 additions & 3 deletions src/core/control/shaperecognizer/CircleRecognizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#pragma once

#include <memory>
class Stroke;
class Inertia;

Expand All @@ -20,9 +21,9 @@ class CircleRecognizer {
virtual ~CircleRecognizer();

public:
static Stroke* recognize(Stroke* s);
static auto recognize(Stroke* s) -> std::unique_ptr<Stroke>;

private:
static Stroke* makeCircleShape(Stroke* originalStroke, Inertia& inertia);
static double scoreCircle(Stroke* s, Inertia& inertia);
static auto makeCircleShape(Stroke* originalStroke, Inertia& inertia) -> std::unique_ptr<Stroke>;
static auto scoreCircle(Stroke* s, Inertia& inertia) -> double;
};
12 changes: 6 additions & 6 deletions src/core/control/shaperecognizer/ShapeRecognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void ShapeRecognizer::resetRecognizer() {
/**
* Test if segments form standard shapes
*/
auto ShapeRecognizer::tryRectangle() -> Stroke* {
auto ShapeRecognizer::tryRectangle() -> std::unique_ptr<Stroke> {
// first, we need whole strokes to combine to 4 segments...
if (this->queueLength < 4) {
return nullptr;
Expand Down Expand Up @@ -85,7 +85,7 @@ auto ShapeRecognizer::tryRectangle() -> Stroke* {
avgAngle = M_PI / 2;
}

auto* s = new Stroke();
auto s = std::make_unique<Stroke>();
s->applyStyleFrom(this->stroke);

for (int i = 0; i <= 3; i++) {
Expand Down Expand Up @@ -260,7 +260,7 @@ auto ShapeRecognizer::isStrokeLargeEnough(Stroke* stroke, double strokeMinSize)
/**
* The main pattern recognition function
*/
auto ShapeRecognizer::recognizePatterns(Stroke* stroke, double strokeMinSize) -> Stroke* {
auto ShapeRecognizer::recognizePatterns(Stroke* stroke, double strokeMinSize) -> std::unique_ptr<Stroke> {
this->stroke = stroke;

if (!isStrokeLargeEnough(stroke, strokeMinSize)) {
Expand Down Expand Up @@ -305,7 +305,7 @@ auto ShapeRecognizer::recognizePatterns(Stroke* stroke, double strokeMinSize) ->
rs[i].calcSegmentGeometry(stroke->getPoints(), brk[i], brk[i + 1], ss + i);
}

if (Stroke* result = tryRectangle(); result != nullptr) {
if (auto result = tryRectangle(); result != nullptr) {
RDEBUG("return rectangle");
return result;
}
Expand All @@ -326,7 +326,7 @@ auto ShapeRecognizer::recognizePatterns(Stroke* stroke, double strokeMinSize) ->
aligned = false;
}

auto* s = new Stroke();
auto s = std::make_unique<Stroke>();
s->applyStyleFrom(this->stroke);

if (aligned) {
Expand All @@ -344,7 +344,7 @@ auto ShapeRecognizer::recognizePatterns(Stroke* stroke, double strokeMinSize) ->
}

// not a polygon: maybe a circle ?
Stroke* s = CircleRecognizer::recognize(stroke);
auto s = CircleRecognizer::recognize(stroke);
if (s) {
RDEBUG("return circle");
return s;
Expand Down
5 changes: 3 additions & 2 deletions src/core/control/shaperecognizer/ShapeRecognizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#pragma once

#include <array> // for array
#include <memory>

#include "RecoSegment.h"
#include "ShapeRecognizerConfig.h" // for MAX_POLYGON_SIDES
Expand All @@ -26,11 +27,11 @@ class ShapeRecognizer {
ShapeRecognizer();
virtual ~ShapeRecognizer();

Stroke* recognizePatterns(Stroke* stroke, double strokeMinSize);
auto recognizePatterns(Stroke* stroke, double strokeMinSize) -> std::unique_ptr<Stroke>;
void resetRecognizer();

private:
Stroke* tryRectangle();
auto tryRectangle() -> std::unique_ptr<Stroke>;
// function Stroke* tryArrow(); removed after commit a3f7a251282dcfea8b4de695f28ce52bf2035da2

static void optimizePolygonal(const Point* pt, int nsides, int* breaks, Inertia* ss);
Expand Down
6 changes: 3 additions & 3 deletions src/core/control/tools/BaseShapeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,12 @@ void BaseShapeHandler::onButtonReleaseEvent(const PositionInputData& pos, double

undo->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, stroke.get()));

auto ptr = stroke.get();
Document* doc = control->getDocument();
doc->lock();
layer->addElement(stroke.get());
layer->addElement(std::move(stroke));
doc->unlock();
page->fireElementChanged(stroke.get());
stroke.release();
page->fireElementChanged(ptr);

control->getCursor()->updateCursor();
}
Expand Down

0 comments on commit 33baec7

Please sign in to comment.