Fix #111332: 4.0 files cannot be opened in 3.6, invalid region types

4.0 files now include asset shelf regions in 3D views. This region type is not
known to older Blender versions. So far, in such cases we would just change
the region type to be the first known region type and keep the region storage
otherwise. This was arbitrary, and in fact unsafe: the reused settings may
violate invariants/assumptions for a region type and worse, the
`ARegion.regiondata` can only be interpreted and correctly written to files
if the region type is known.

Make sure all invalid regions (regions where the type cannot be restored) are
removed on file read.

Committed to 3.6 release branch as e2d4403497.

Pull Request: https://projects.blender.org/blender/blender/pulls/111483
This commit is contained in:
Julian Eisel
2023-08-29 13:52:16 +02:00
committed by Julian Eisel
parent dc9589d3e4
commit 7fb58a33f0
3 changed files with 42 additions and 17 deletions

View File

@@ -464,7 +464,6 @@ typedef struct AssetShelfType {
/* Space-types. */
struct SpaceType *BKE_spacetype_from_id(int spaceid);
struct ARegionType *BKE_regiontype_from_id_or_first(const struct SpaceType *st, int regionid);
struct ARegionType *BKE_regiontype_from_id(const struct SpaceType *st, int regionid);
const struct ListBase *BKE_spacetypes_list(void);
void BKE_spacetype_register(struct SpaceType *st);

View File

@@ -244,19 +244,6 @@ SpaceType *BKE_spacetype_from_id(int spaceid)
return nullptr;
}
ARegionType *BKE_regiontype_from_id_or_first(const SpaceType *st, int regionid)
{
LISTBASE_FOREACH (ARegionType *, art, &st->regiontypes) {
if (art->regionid == regionid) {
return art;
}
}
printf(
"Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
return static_cast<ARegionType *>(st->regiontypes.first);
}
ARegionType *BKE_regiontype_from_id(const SpaceType *st, int regionid)
{
LISTBASE_FOREACH (ARegionType *, art, &st->regiontypes) {
@@ -1276,13 +1263,49 @@ bool BKE_screen_area_map_blend_read_data(BlendDataReader *reader, ScrAreaMap *ar
return true;
}
/**
* Removes all regions whose type cannot be reconstructed. For example files from new versions may
* be stored with a newly introduced region type that this version cannot handle.
*/
static void regions_remove_invalid(SpaceType *space_type, ListBase *regionbase)
{
LISTBASE_FOREACH_MUTABLE (ARegion *, region, regionbase) {
if (BKE_regiontype_from_id(space_type, region->regiontype) != NULL) {
continue;
}
printf("Warning: region type %d missing in space type \"%s\" (id: %d) - removing region\n",
region->regiontype,
space_type->name,
space_type->spaceid);
BKE_area_region_free(space_type, region);
BLI_freelinkN(regionbase, region);
}
}
void BKE_screen_area_blend_read_after_liblink(BlendLibReader *reader, ID *parent_id, ScrArea *area)
{
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
SpaceType *space_type = BKE_spacetype_from_id(sl->spacetype);
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
if (space_type && space_type->blend_read_after_liblink) {
/* We cannot restore the region type without a valid space type. So delete all regions to make
* sure no data is kept around that can't be restored safely (like the type dependent
* #ARegion.regiondata). */
if (!space_type) {
LISTBASE_FOREACH_MUTABLE (ARegion *, region, regionbase) {
BKE_area_region_free(nullptr, region);
BLI_freelinkN(regionbase, region);
}
continue;
}
if (space_type->blend_read_after_liblink) {
space_type->blend_read_after_liblink(reader, parent_id, sl);
}
regions_remove_invalid(space_type, regionbase);
}
}

View File

@@ -2035,7 +2035,10 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
}
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
region->type = BKE_regiontype_from_id_or_first(area->type, region->regiontype);
region->type = BKE_regiontype_from_id(area->type, region->regiontype);
/* Invalid region types may be stored in files (e.g. for new files), but they should be handled
* on file read already, see #BKE_screen_area_blend_read_lib(). */
BLI_assert_msg(region->type != nullptr, "Region type not valid for this space type");
}
/* area sizes */
@@ -2101,7 +2104,7 @@ static void area_offscreen_init(ScrArea *area)
BLI_assert(area->type != nullptr);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
region->type = BKE_regiontype_from_id_or_first(area->type, region->regiontype);
region->type = BKE_regiontype_from_id(area->type, region->regiontype);
}
}