Fix crash loading blend files with unknown space types

Logic which initialized a 3D viewport in ED_area_init only set it's
type but didn't ensure `area->spacedata.first` pointed to a valid View3D.

Resolve by adding or reusing the existing View3D.
The check in `area_offscreen_init` has been replaced with an assert
since the space_type for off-screen areas is set at run-time and should
never be unknown.
This commit is contained in:
Campbell Barton
2023-07-20 18:27:22 +10:00
parent 02fcc277be
commit 56dfd213ff

View File

@@ -1925,6 +1925,39 @@ bool ED_area_has_shared_border(ScrArea *a, ScrArea *b)
return area_getorientation(a, b) != -1;
}
/**
* Setup a known space type in the event a file with an unknown space-type is loaded.
*/
static void area_init_type_fallback(ScrArea *area, eSpace_Type space_type)
{
BLI_assert(area->type == nullptr);
area->spacetype = space_type;
area->type = BKE_spacetype_from_id(area->spacetype);
SpaceLink *sl = nullptr;
LISTBASE_FOREACH (SpaceLink *, sl_iter, &area->spacedata) {
if (sl_iter->spacetype == space_type) {
sl = sl_iter;
break;
}
}
if (sl) {
SpaceLink *sl_old = static_cast<SpaceLink *>(area->spacedata.first);
if (LIKELY(sl != sl_old)) {
BLI_remlink(&area->spacedata, sl);
BLI_addhead(&area->spacedata, sl);
/* swap regions */
sl_old->regionbase = area->regionbase;
area->regionbase = sl->regionbase;
BLI_listbase_clear(&sl->regionbase);
}
}
else {
screen_area_spacelink_add(nullptr, area, space_type);
}
}
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
{
WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -1943,8 +1976,8 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
area->type = BKE_spacetype_from_id(area->spacetype);
if (area->type == nullptr) {
area->spacetype = SPACE_VIEW3D;
area->type = BKE_spacetype_from_id(area->spacetype);
area_init_type_fallback(area, SPACE_VIEW3D);
BLI_assert(area->type != nullptr);
}
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
@@ -2009,11 +2042,9 @@ static void area_offscreen_init(ScrArea *area)
{
area->flag |= AREA_FLAG_OFFSCREEN;
area->type = BKE_spacetype_from_id(area->spacetype);
if (area->type == nullptr) {
area->spacetype = SPACE_VIEW3D;
area->type = BKE_spacetype_from_id(area->spacetype);
}
/* Off screen areas are only ever created at run-time,
* so there is no reason for the type to be unknown. */
BLI_assert(area->type != nullptr);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
region->type = BKE_regiontype_from_id_or_first(area->type, region->regiontype);